diff --git a/CHANGELOG.md b/CHANGELOG.md index 74725a32..72d64762 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ CHANGELOG for FlatCAM beta - fixed a selection issue in Legacy graphic mode for single click - added a CHANGELOG file and changed the README file to contain the installation instructions - updated the README file +- in Project Tab added tooltips for the loaded objects +- fixed a bug in loading objects by drag&drop into the Project Tab where only one object in the selection was loaded 19.04.2020 diff --git a/ObjectCollection.py b/ObjectCollection.py index 62d6304d..79a1326d 100644 --- a/ObjectCollection.py +++ b/ObjectCollection.py @@ -16,7 +16,8 @@ from PyQt5.QtCore import Qt, QSettings from PyQt5.QtGui import QColor # from PyQt5.QtCore import QModelIndex -from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMExcellon, FlatCAMCNCjob, FlatCAMDocument, FlatCAMScript +from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMExcellon, FlatCAMCNCjob, FlatCAMDocument, FlatCAMScript, \ + FlatCAMObj import inspect # TODO: Remove import FlatCAMApp @@ -55,6 +56,17 @@ class KeySensitiveListView(QtWidgets.QTreeView): self.filename = "" self.app = app + # Enabling Drag and Drop for the items in the Project Tab + # Example: https://github.com/d1vanov/PyQt5-reorderable-list-model/blob/master/reorderable_list_model.py + # https://github.com/jimmykuu/PyQt-PySide-Cookbook/blob/master/tree/drop_indicator.md + # self.setDragEnabled(True) + # self.viewport().setAcceptDrops(True) + # self.setDropIndicatorShown(True) + # self.DragDropMode(QtWidgets.QAbstractItemView.InternalMove) + # self.current_idx = None + # self.current_group = None + # self.dropped_obj = None + keyPressed = QtCore.pyqtSignal(int) def keyPressEvent(self, event): @@ -62,6 +74,11 @@ class KeySensitiveListView(QtWidgets.QTreeView): self.keyPressed.emit(event.key()) def dragEnterEvent(self, event): + # if event.source(): + # self.current_idx = self.currentIndex() + # self.current_group = self.model().group_items[self.current_idx.internalPointer().obj.kind] + # self.dropped_obj = self.current_idx.internalPointer().obj + if event.mimeData().hasUrls: event.accept() else: @@ -69,6 +86,7 @@ class KeySensitiveListView(QtWidgets.QTreeView): def dragMoveEvent(self, event): self.setDropIndicatorShown(True) + if event.mimeData().hasUrls: event.accept() else: @@ -77,6 +95,20 @@ class KeySensitiveListView(QtWidgets.QTreeView): def dropEvent(self, event): drop_indicator = self.dropIndicatorPosition() + # if event.source(): + # new_index = self.indexAt(event.pos()) + # new_group = self.model().group_items[new_index.internalPointer().obj.kind] + # if self.current_group == new_group: + # + # # delete it from the model + # deleted_obj_name = self.dropped_obj.options['name'] + # self.model().delete_by_name(deleted_obj_name) + # + # # add the object to the new index + # self.model().append(self.dropped_obj, to_index=new_index) + # + # return + m = event.mimeData() if m.hasUrls: event.accept() @@ -84,46 +116,46 @@ class KeySensitiveListView(QtWidgets.QTreeView): for url in m.urls(): self.filename = str(url.toLocalFile()) - # file drop from outside application - if drop_indicator == QtWidgets.QAbstractItemView.OnItem: - if self.filename == "": - self.app.inform.emit(_("Open cancelled.")) + # file drop from outside application + if drop_indicator == QtWidgets.QAbstractItemView.OnItem: + if self.filename == "": + self.app.inform.emit(_("Open cancelled.")) + else: + if self.filename.lower().rpartition('.')[-1] in self.app.grb_list: + self.app.worker_task.emit({'fcn': self.app.open_gerber, + 'params': [self.filename]}) + else: + event.ignore() + + if self.filename.lower().rpartition('.')[-1] in self.app.exc_list: + self.app.worker_task.emit({'fcn': self.app.open_excellon, + 'params': [self.filename]}) + else: + event.ignore() + + if self.filename.lower().rpartition('.')[-1] in self.app.gcode_list: + self.app.worker_task.emit({'fcn': self.app.open_gcode, + 'params': [self.filename]}) + else: + event.ignore() + + if self.filename.lower().rpartition('.')[-1] in self.app.svg_list: + object_type = 'geometry' + self.app.worker_task.emit({'fcn': self.app.import_svg, + 'params': [self.filename, object_type, None]}) + + if self.filename.lower().rpartition('.')[-1] in self.app.dxf_list: + object_type = 'geometry' + self.app.worker_task.emit({'fcn': self.app.import_dxf, + 'params': [self.filename, object_type, None]}) + + if self.filename.lower().rpartition('.')[-1] in self.app.prj_list: + # self.app.open_project() is not Thread Safe + self.app.open_project(self.filename) + else: + event.ignore() else: - if self.filename.lower().rpartition('.')[-1] in self.app.grb_list: - self.app.worker_task.emit({'fcn': self.app.open_gerber, - 'params': [self.filename]}) - else: - event.ignore() - - if self.filename.lower().rpartition('.')[-1] in self.app.exc_list: - self.app.worker_task.emit({'fcn': self.app.open_excellon, - 'params': [self.filename]}) - else: - event.ignore() - - if self.filename.lower().rpartition('.')[-1] in self.app.gcode_list: - self.app.worker_task.emit({'fcn': self.app.open_gcode, - 'params': [self.filename]}) - else: - event.ignore() - - if self.filename.lower().rpartition('.')[-1] in self.app.svg_list: - object_type = 'geometry' - self.app.worker_task.emit({'fcn': self.app.import_svg, - 'params': [self.filename, object_type, None]}) - - if self.filename.lower().rpartition('.')[-1] in self.app.dxf_list: - object_type = 'geometry' - self.app.worker_task.emit({'fcn': self.app.import_dxf, - 'params': [self.filename, object_type, None]}) - - if self.filename.lower().rpartition('.')[-1] in self.app.prj_list: - # self.app.open_project() is not Thread Safe - self.app.open_project(self.filename) - else: - event.ignore() - else: - pass + pass else: event.ignore() @@ -221,6 +253,7 @@ class ObjectCollection(QtCore.QAbstractItemModel): # will emit the name of the object that was just selected item_selected = QtCore.pyqtSignal(str) + update_list_signal = QtCore.pyqtSignal() root_item = None # app = None @@ -296,6 +329,8 @@ class ObjectCollection(QtCore.QAbstractItemModel): self.click_modifier = None + self.update_list_signal.connect(self.on_update_list_signal) + def promise(self, obj_name): FlatCAMApp.App.log.debug("Object %s has been promised." % obj_name) self.promises.add(obj_name) @@ -430,6 +465,18 @@ class ObjectCollection(QtCore.QAbstractItemModel): return icon else: return QtGui.QPixmap() + elif role == Qt.ToolTipRole: + try: + obj = index.internalPointer().obj + except AttributeError: + return None + + if obj: + text = obj.options['name'] + return text + else: + QtWidgets.QToolTip.hideText() + return None else: return None @@ -459,7 +506,10 @@ class ObjectCollection(QtCore.QAbstractItemModel): self.app.inform.emit(_("Object renamed from {old} to {new}").format(old=old_name, new=new_name)) - return True + self.dataChanged.emit(index, index) + return True + else: + return False def supportedDropActions(self): return Qt.MoveAction @@ -471,15 +521,17 @@ class ObjectCollection(QtCore.QAbstractItemModel): return Qt.ItemIsEnabled | default_flags # Prevent groups from selection - if not index.internalPointer().obj: + try: + if not index.internalPointer().obj: + return Qt.ItemIsEnabled + else: + return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable | \ + Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled + except AttributeError: return Qt.ItemIsEnabled - else: - return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable | \ - Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled - # return QtWidgets.QAbstractItemModel.flags(self, index) - def append(self, obj, active=False): + def append(self, obj, active=False, to_index=None): FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + " --> OC.append()") name = obj.options["name"] @@ -509,13 +561,19 @@ class ObjectCollection(QtCore.QAbstractItemModel): # Required before appending (Qt MVC) group = self.group_items[obj.kind] group_index = self.index(group.row(), 0, QtCore.QModelIndex()) - self.beginInsertRows(group_index, group.child_count(), group.child_count()) - # Append new item - obj.item = TreeItem(None, self.icons[obj.kind], obj, group) - - # Required after appending (Qt MVC) - self.endInsertRows() + if to_index is None: + self.beginInsertRows(group_index, group.child_count(), group.child_count()) + # Append new item + obj.item = TreeItem(None, self.icons[obj.kind], obj, group) + # Required after appending (Qt MVC) + self.endInsertRows() + else: + self.beginInsertRows(group_index, to_index.row()-1, to_index.row()-1) + # Append new item + obj.item = TreeItem(None, self.icons[obj.kind], obj, group) + # Required after appending (Qt MVC) + self.endInsertRows() # Expand group if group.child_count() == 1: @@ -671,7 +729,7 @@ class ObjectCollection(QtCore.QAbstractItemModel): # self.app.ui.code_editor.set_model_data(self.app.myKeywords) except Exception as e: log.debug( - "delete_active() --> Could not remove the old object name from auto-completer model list. %s" % str(e)) + "delete_by_name() --> Could not remove the old object name from auto-completer model list. %s" % str(e)) self.app.object_status_changed.emit(deleted.obj, 'delete', name) @@ -679,7 +737,7 @@ class ObjectCollection(QtCore.QAbstractItemModel): self.beginRemoveRows(self.index(group.row(), 0, QtCore.QModelIndex()), deleted.row(), deleted.row()) group.remove_child(deleted) # after deletion of object store the current list of objects into the self.app.all_objects_list - self.app.all_objects_list = self.get_list() + self.update_list_signal.emit() self.endRemoveRows() # ############ OBJECT DELETION FROM MODEL STOPS HERE #################### @@ -698,6 +756,9 @@ class ObjectCollection(QtCore.QAbstractItemModel): if not self.get_list(): self.app.ui.splitter.setSizes([0, 1]) + def on_update_list_signal(self): + self.app.all_objects_list = self.get_list() + def delete_all(self): FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.delete_all()") diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py index 8c9f41e2..0b7c44cb 100644 --- a/flatcamGUI/FlatCAMGUI.py +++ b/flatcamGUI/FlatCAMGUI.py @@ -4163,8 +4163,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow): def closeEvent(self, event): if self.app.save_in_progress: - self.app.inform.emit('[WARNING_NOTCL] %s' % - _("Application is saving the project. Please wait ...")) + self.app.inform.emit('[WARNING_NOTCL] %s' % _("Application is saving the project. Please wait ...")) else: grect = self.geometry()