flatcam/ObjectCollection.py

990 lines
35 KiB
Python

# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
# ##########################################################
# ##########################################################
# File modified by: Dennis Hayrullin #
# File modified by: Marius Stanciu #
# ##########################################################
from PyQt5 import QtGui, QtCore, QtWidgets
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, \
FlatCAMObj
import inspect # TODO: Remove
import FlatCAMApp
import re
import logging
import collections
from copy import deepcopy
from numpy import Inf
import gettext
import FlatCAMTranslation as fcTranslate
import builtins
fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__:
_ = gettext.gettext
log = logging.getLogger('base')
class KeySensitiveListView(QtWidgets.QTreeView):
"""
QtGui.QListView extended to emit a signal on key press.
"""
def __init__(self, app, parent=None):
super(KeySensitiveListView, self).__init__(parent)
self.setHeaderHidden(True)
self.setEditTriggers(QtWidgets.QTreeView.SelectedClicked)
# self.setRootIsDecorated(False)
# self.setExpandsOnDoubleClick(False)
# Enable dragging and dropping onto the GUI
self.setAcceptDrops(True)
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):
# super(KeySensitiveListView, self).keyPressEvent(event)
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:
event.ignore()
def dragMoveEvent(self, event):
self.setDropIndicatorShown(True)
if event.mimeData().hasUrls:
event.accept()
else:
event.ignore()
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()
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(_("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:
pass
else:
event.ignore()
class TreeItem(KeySensitiveListView):
"""
Item of a tree model
"""
def __init__(self, data, icon=None, obj=None, parent_item=None):
super(TreeItem, self).__init__(parent_item)
self.parent_item = parent_item
self.item_data = data # Columns string data
self.icon = icon # Decoration
self.obj = obj # FlatCAMObj
self.child_items = []
if parent_item:
parent_item.append_child(self)
def append_child(self, item):
self.child_items.append(item)
item.set_parent_item(self)
def remove_child(self, item):
child = self.child_items.pop(self.child_items.index(item))
child.obj.clear(True)
child.obj.delete()
del child.obj
del child
def remove_children(self):
for child in self.child_items:
child.obj.clear()
child.obj.delete()
del child.obj
del child
self.child_items = []
def child(self, row):
return self.child_items[row]
def child_count(self):
return len(self.child_items)
def column_count(self):
return len(self.item_data)
def data(self, column):
return self.item_data[column]
def row(self):
return self.parent_item.child_items.index(self)
def set_parent_item(self, parent_item):
self.parent_item = parent_item
def __del__(self):
del self.icon
class ObjectCollection(QtCore.QAbstractItemModel):
"""
Object storage and management.
"""
groups = [
("gerber", "Gerber"),
("excellon", "Excellon"),
("geometry", "Geometry"),
("cncjob", "CNC Job"),
("script", "Scripts"),
("document", "Document"),
]
classdict = {
"gerber": FlatCAMGerber,
"excellon": FlatCAMExcellon,
"cncjob": FlatCAMCNCjob,
"geometry": FlatCAMGeometry,
"script": FlatCAMScript,
"document": FlatCAMDocument
}
icon_files = {
"gerber": "share/flatcam_icon16.png",
"excellon": "share/drill16.png",
"cncjob": "share/cnc16.png",
"geometry": "share/geometry16.png",
"script": "share/script_new16.png",
"document": "share/notes16_1.png"
}
# 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
def __init__(self, app, parent=None):
QtCore.QAbstractItemModel.__init__(self)
self.app = app
# ## Icons for the list view
self.icons = {}
for kind in ObjectCollection.icon_files:
self.icons[kind] = QtGui.QPixmap(
ObjectCollection.icon_files[kind].replace('share', self.app.resource_location))
# Create root tree view item
self.root_item = TreeItem(["root"])
# Create group items
self.group_items = {}
for kind, title in ObjectCollection.groups:
item = TreeItem([title], self.icons[kind])
self.group_items[kind] = item
self.root_item.append_child(item)
# Create test sub-items
# for i in self.root_item.m_child_items:
# print i.data(0)
# i.append_child(TreeItem(["empty"]))
# ## Data # ##
self.checked_indexes = []
# Names of objects that are expected to become available.
# For example, when the creation of a new object will run
# in the background and will complete some time in the
# future. This is a way to reserve the name and to let other
# tasks know that they have to wait until available.
self.promises = set()
# same as above only for objects that are plotted
self.plot_promises = set()
# ## View
self.view = KeySensitiveListView(self.app)
self.view.setModel(self)
self.view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.view.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
# self.view.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
# self.view.setDragEnabled(True)
# self.view.setAcceptDrops(True)
# self.view.setDropIndicatorShown(True)
settings = QSettings("Open Source", "FlatCAM")
if settings.contains("notebook_font_size"):
fsize = settings.value('notebook_font_size', type=int)
else:
fsize = 12
font = QtGui.QFont()
font.setPixelSize(fsize)
font.setFamily("Seagoe UI")
self.view.setFont(font)
# ## GUI Events
self.view.selectionModel().selectionChanged.connect(self.on_list_selection_change)
# self.view.activated.connect(self.on_item_activated)
self.view.keyPressed.connect(self.app.ui.keyPressEvent)
# self.view.clicked.connect(self.on_mouse_down)
self.view.customContextMenuRequested.connect(self.on_menu_request)
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)
def has_promises(self):
return len(self.promises) > 0
def plot_promise(self, plot_obj_name):
self.plot_promises.add(plot_obj_name)
def plot_remove_promise(self, plot_obj_name):
if plot_obj_name in self.plot_promises:
self.plot_promises.remove(plot_obj_name)
def has_plot_promises(self):
return len(self.plot_promises) > 0
def on_mouse_down(self, event):
FlatCAMApp.App.log.debug("Mouse button pressed on list")
def on_menu_request(self, pos):
sel = len(self.view.selectedIndexes()) > 0
self.app.ui.menuprojectenable.setEnabled(sel)
self.app.ui.menuprojectdisable.setEnabled(sel)
self.app.ui.menuprojectcolor.setEnabled(sel)
self.app.ui.menuprojectviewsource.setEnabled(sel)
self.app.ui.menuprojectcopy.setEnabled(sel)
self.app.ui.menuprojectedit.setEnabled(sel)
self.app.ui.menuprojectdelete.setEnabled(sel)
self.app.ui.menuprojectsave.setEnabled(sel)
self.app.ui.menuprojectproperties.setEnabled(sel)
if sel:
self.app.ui.menuprojectgeneratecnc.setVisible(True)
self.app.ui.menuprojectedit.setVisible(True)
self.app.ui.menuprojectsave.setVisible(True)
self.app.ui.menuprojectviewsource.setVisible(True)
self.app.ui.menuprojectcolor.setEnabled(False)
for obj in self.get_selected():
if type(obj) == FlatCAMGerber or type(obj) == FlatCAMExcellon:
self.app.ui.menuprojectcolor.setEnabled(True)
if type(obj) != FlatCAMGeometry:
self.app.ui.menuprojectgeneratecnc.setVisible(False)
if type(obj) != FlatCAMGeometry and type(obj) != FlatCAMExcellon and type(obj) != FlatCAMGerber:
self.app.ui.menuprojectedit.setVisible(False)
if type(obj) != FlatCAMGerber and type(obj) != FlatCAMExcellon and type(obj) != FlatCAMCNCjob:
self.app.ui.menuprojectviewsource.setVisible(False)
if type(obj) != FlatCAMGerber and type(obj) != FlatCAMGeometry and type(obj) != FlatCAMExcellon and \
type(obj) != FlatCAMCNCjob:
# meaning for Scripts and for Document type of FlatCAM object
self.app.ui.menuprojectenable.setVisible(False)
self.app.ui.menuprojectdisable.setVisible(False)
self.app.ui.menuprojectedit.setVisible(False)
self.app.ui.menuprojectproperties.setVisible(False)
self.app.ui.menuprojectgeneratecnc.setVisible(False)
else:
self.app.ui.menuprojectgeneratecnc.setVisible(False)
self.app.ui.menuproject.popup(self.view.mapToGlobal(pos))
def index(self, row, column=0, parent=None, *args, **kwargs):
if not self.hasIndex(row, column, parent):
return QtCore.QModelIndex()
# if not parent.isValid():
# parent_item = self.root_item
# else:
# parent_item = parent.internalPointer()
parent_item = parent.internalPointer() if parent.isValid() else self.root_item
child_item = parent_item.child(row)
if child_item:
return self.createIndex(row, column, child_item)
else:
return QtCore.QModelIndex()
def parent(self, index=None):
if not index.isValid():
return QtCore.QModelIndex()
parent_item = index.internalPointer().parent_item
if parent_item == self.root_item:
return QtCore.QModelIndex()
return self.createIndex(parent_item.row(), 0, parent_item)
def rowCount(self, index=None, *args, **kwargs):
if index.column() > 0:
return 0
if not index.isValid():
parent_item = self.root_item
else:
parent_item = index.internalPointer()
return parent_item.child_count()
def columnCount(self, index=None, *args, **kwargs):
if index.isValid():
return index.internalPointer().column_count()
else:
return self.root_item.column_count()
def data(self, index, role=None):
if not index.isValid():
return None
if role in [Qt.DisplayRole, Qt.EditRole]:
obj = index.internalPointer().obj
if obj:
return obj.options["name"]
else:
return index.internalPointer().data(index.column())
if role == Qt.ForegroundRole:
color = QColor(self.app.defaults['global_proj_item_color'])
color_disabled = QColor(self.app.defaults['global_proj_item_dis_color'])
obj = index.internalPointer().obj
if obj:
return QtGui.QBrush(color) if obj.options["plot"] else QtGui.QBrush(color_disabled)
else:
return index.internalPointer().data(index.column())
elif role == Qt.DecorationRole:
icon = index.internalPointer().icon
if icon:
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
def setData(self, index, data, role=None):
if index.isValid():
obj = index.internalPointer().obj
if obj:
old_name = deepcopy(obj.options['name'])
new_name = str(data)
if old_name != new_name and new_name != '':
# rename the object
obj.options["name"] = deepcopy(data)
self.app.object_status_changed.emit(obj, 'rename', old_name)
# update the SHELL auto-completer model data
try:
self.app.myKeywords.remove(old_name)
self.app.myKeywords.append(new_name)
self.app.shell._edit.set_model_data(self.app.myKeywords)
except Exception as e:
log.debug(
"setData() --> Could not remove the old object name from auto-completer model list. %s" %
str(e))
# obj.build_ui()
self.app.inform.emit(_("Object renamed from <b>{old}</b> to <b>{new}</b>").format(old=old_name,
new=new_name))
self.dataChanged.emit(index, index)
return True
else:
return False
def supportedDropActions(self):
return Qt.MoveAction
def flags(self, index):
default_flags = QtCore.QAbstractItemModel.flags(self, index)
if not index.isValid():
return Qt.ItemIsEnabled | default_flags
# Prevent groups from selection
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
# return QtWidgets.QAbstractItemModel.flags(self, index)
def append(self, obj, active=False, to_index=None):
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + " --> OC.append()")
name = obj.options["name"]
# Check promises and clear if exists
if name in self.promises:
self.promises.remove(name)
# FlatCAMApp.App.log.debug("Promised object %s became available." % name)
# FlatCAMApp.App.log.debug("%d promised objects remaining." % len(self.promises))
# Prevent same name
while name in self.get_names():
# ## Create a new name
# Ends with number?
FlatCAMApp.App.log.debug("new_object(): Object name (%s) exists, changing." % name)
match = re.search(r'(.*[^\d])?(\d+)$', name)
if match: # Yes: Increment the number!
base = match.group(1) or ''
num = int(match.group(2))
name = base + str(num + 1)
else: # No: add a number!
name += "_1"
obj.options["name"] = name
obj.set_ui(obj.ui_type(app=self.app))
# Required before appending (Qt MVC)
group = self.group_items[obj.kind]
group_index = self.index(group.row(), 0, QtCore.QModelIndex())
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:
self.view.setExpanded(group_index, True)
self.app.should_we_save = True
self.app.object_status_changed.emit(obj, 'append', name)
# decide if to show or hide the Notebook side of the screen
if self.app.defaults["global_project_autohide"] is True:
# always open the notebook on object added to collection
self.app.ui.splitter.setSizes([1, 1])
def get_names(self):
"""
Gets a list of the names of all objects in the collection.
:return: List of names.
:rtype: list
"""
# FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + " --> OC.get_names()")
return [x.options['name'] for x in self.get_list()]
def get_bounds(self):
"""
Finds coordinates bounding all objects in the collection.
:return: [xmin, ymin, xmax, ymax]
:rtype: list
"""
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.get_bounds()")
# TODO: Move the operation out of here.
xmin = Inf
ymin = Inf
xmax = -Inf
ymax = -Inf
# for obj in self.object_list:
for obj in self.get_list():
try:
gxmin, gymin, gxmax, gymax = obj.bounds()
xmin = min([xmin, gxmin])
ymin = min([ymin, gymin])
xmax = max([xmax, gxmax])
ymax = max([ymax, gymax])
except Exception as e:
FlatCAMApp.App.log.warning("DEV WARNING: Tried to get bounds of empty geometry. %s" % str(e))
return [xmin, ymin, xmax, ymax]
def get_by_name(self, name, isCaseSensitive=None):
"""
Fetches the FlatCAMObj with the given `name`.
:param name: The name of the object.
:type name: str
:param isCaseSensitive: whether searching of the object is done by name where the name is case sensitive
:return: The requested object or None if no such object.
:rtype: FlatCAMObj or None
"""
# FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.get_by_name()")
if isCaseSensitive is None or isCaseSensitive is True:
for obj in self.get_list():
if obj.options['name'] == name:
return obj
else:
for obj in self.get_list():
if obj.options['name'].lower() == name.lower():
return obj
return None
def delete_active(self, select_project=True):
selections = self.view.selectedIndexes()
if len(selections) == 0:
return
active = selections[0].internalPointer()
group = active.parent_item
# send signal with the object that is deleted
# self.app.object_status_changed.emit(active.obj, 'delete')
# some objects add a Tab on creation, close it here
for idx in range(self.app.ui.plot_tab_area.count()):
if self.app.ui.plot_tab_area.widget(idx).objectName() == active.obj.options['name']:
self.app.ui.plot_tab_area.removeTab(idx)
break
# update the SHELL auto-completer model data
name = active.obj.options['name']
try:
self.app.myKeywords.remove(name)
self.app.shell._edit.set_model_data(self.app.myKeywords)
# this is not needed any more because now the code editor is created on demand
# 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))
self.app.object_status_changed.emit(active.obj, 'delete', name)
# ############ OBJECT DELETION FROM MODEL STARTS HERE ####################
self.beginRemoveRows(self.index(group.row(), 0, QtCore.QModelIndex()), active.row(), active.row())
group.remove_child(active)
# 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.endRemoveRows()
# ############ OBJECT DELETION FROM MODEL STOPS HERE ####################
if self.app.is_legacy is False:
self.app.plotcanvas.redraw()
if select_project:
# always go to the Project Tab after object deletion as it may be done with a shortcut key
self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
self.app.should_we_save = True
# decide if to show or hide the Notebook side of the screen
if self.app.defaults["global_project_autohide"] is True:
# hide the notebook if there are no objects in the collection
if not self.get_list():
self.app.ui.splitter.setSizes([0, 1])
def delete_by_name(self, name, select_project=True):
obj = self.get_by_name(name=name)
item = obj.item
group = self.group_items[obj.kind]
group_index = self.index(group.row(), 0, QtCore.QModelIndex())
item_index = self.index(item.row(), 0, group_index)
deleted = item_index.internalPointer()
group = deleted.parent_item
# some objects add a Tab on creation, close it here
for idx in range(self.app.ui.plot_tab_area.count()):
if self.app.ui.plot_tab_area.widget(idx).objectName() == deleted.obj.options['name']:
self.app.ui.plot_tab_area.removeTab(idx)
break
# update the SHELL auto-completer model data
name = deleted.obj.options['name']
try:
self.app.myKeywords.remove(name)
self.app.shell._edit.set_model_data(self.app.myKeywords)
# this is not needed any more because now the code editor is created on demand
# self.app.ui.code_editor.set_model_data(self.app.myKeywords)
except Exception as e:
log.debug(
"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)
# ############ OBJECT DELETION FROM MODEL STARTS HERE ####################
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.update_list_signal.emit()
self.endRemoveRows()
# ############ OBJECT DELETION FROM MODEL STOPS HERE ####################
if self.app.is_legacy is False:
self.app.plotcanvas.redraw()
if select_project:
# always go to the Project Tab after object deletion as it may be done with a shortcut key
self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
self.app.should_we_save = True
# decide if to show or hide the Notebook side of the screen
if self.app.defaults["global_project_autohide"] is True:
# hide the notebook if there are no objects in the collection
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()")
self.app.object_status_changed.emit(None, 'delete_all', '')
try:
self.app.all_objects_list.clear()
self.app.geo_editor.clear()
self.app.exc_editor.clear()
self.app.dblsidedtool.reset_fields()
self.app.panelize_tool.reset_fields()
self.app.cutout_tool.reset_fields()
self.app.film_tool.reset_fields()
self.beginResetModel()
self.checked_indexes = []
for group in self.root_item.child_items:
group.remove_children()
self.endResetModel()
self.app.plotcanvas.redraw()
except Exception as e:
log.debug("ObjectCollection.delete_all() --> %s" % str(e))
def get_active(self):
"""
Returns the active object or None
:return: FlatCAMObj or None
"""
selections = self.view.selectedIndexes()
if len(selections) == 0:
return None
return selections[0].internalPointer().obj
def get_selected(self):
"""
Returns list of objects selected in the view.
:return: List of objects
"""
return [sel.internalPointer().obj for sel in self.view.selectedIndexes()]
def get_non_selected(self):
"""
Returns list of objects non-selected in the view.
:return: List of objects
"""
obj_list = self.get_list()
for sel in self.get_selected():
obj_list.remove(sel)
return obj_list
def set_active(self, name):
"""
Selects object by name from the project list. This triggers the
list_selection_changed event and call on_list_selection_changed.
:param name: Name of the FlatCAM Object
:return: None
"""
try:
obj = self.get_by_name(name)
item = obj.item
group = self.group_items[obj.kind]
group_index = self.index(group.row(), 0, QtCore.QModelIndex())
item_index = self.index(item.row(), 0, group_index)
self.view.selectionModel().select(item_index, QtCore.QItemSelectionModel.Select)
except Exception as e:
log.error("[ERROR] Cause: %s" % str(e))
raise
def set_all_active(self):
"""
Select all objects from the project list. This triggers the
list_selection_changed event and call on_list_selection_changed.
:return: None
"""
for name in self.get_names():
self.set_active(name)
def set_exclusive_active(self, name):
"""
Make the object with the name in parameters the only selected object
:param name: name of object to be selected and made the only active object
:return: None
"""
self.set_all_inactive()
self.set_active(name)
def set_inactive(self, name):
"""
Unselect object by name from the project list. This triggers the
list_selection_changed event and call on_list_selection_changed.
:param name: Name of the FlatCAM Object
:return: None
"""
# log.debug("ObjectCollection.set_inactive()")
obj = self.get_by_name(name)
item = obj.item
group = self.group_items[obj.kind]
group_index = self.index(group.row(), 0, QtCore.QModelIndex())
item_index = self.index(item.row(), 0, group_index)
self.view.selectionModel().select(item_index, QtCore.QItemSelectionModel.Deselect)
def set_all_inactive(self):
"""
Unselect all objects from the project list. This triggers the
list_selection_changed event and call on_list_selection_changed.
:return: None
"""
for name in self.get_names():
self.set_inactive(name)
def on_list_selection_change(self, current, previous):
# FlatCAMApp.App.log.debug("on_list_selection_change()")
# FlatCAMApp.App.log.debug("Current: %s, Previous %s" % (str(current), str(previous)))
try:
obj = current.indexes()[0].internalPointer().obj
self.item_selected.emit(obj.options['name'])
if obj.kind == 'gerber':
self.app.inform.emit('[selected]<span style="color:{color};">{name}</span> {tx}'.format(
color='green',
name=str(obj.options['name']),
tx=_("selected"))
)
elif obj.kind == 'excellon':
self.app.inform.emit('[selected]<span style="color:{color};">{name}</span> {tx}'.format(
color='brown',
name=str(obj.options['name']),
tx=_("selected"))
)
elif obj.kind == 'cncjob':
self.app.inform.emit('[selected]<span style="color:{color};">{name}</span> {tx}'.format(
color='blue',
name=str(obj.options['name']),
tx=_("selected"))
)
elif obj.kind == 'geometry':
self.app.inform.emit('[selected]<span style="color:{color};">{name}</span> {tx}'.format(
color='red',
name=str(obj.options['name']),
tx=_("selected"))
)
elif obj.kind == 'script':
self.app.inform.emit('[selected]<span style="color:{color};">{name}</span> {tx}'.format(
color='orange',
name=str(obj.options['name']),
tx=_("selected"))
)
elif obj.kind == 'document':
self.app.inform.emit('[selected]<span style="color:{color};">{name}</span> {tx}'.format(
color='darkCyan',
name=str(obj.options['name']),
tx=_("selected"))
)
except IndexError:
self.item_selected.emit('none')
# FlatCAMApp.App.log.debug("on_list_selection_change(): Index Error (Nothing selected?)")
self.app.inform.emit('')
try:
self.app.ui.selected_scroll_area.takeWidget()
except Exception as e:
FlatCAMApp.App.log.debug("Nothing to remove. %s" % str(e))
self.app.setup_component_editor()
return
if obj:
obj.build_ui()
def on_item_activated(self, index):
"""
Double-click or Enter on item.
:param index: Index of the item in the list.
:return: None
"""
a_idx = index.internalPointer().obj
if a_idx is None:
return
else:
try:
a_idx.build_ui()
except Exception as e:
self.app.inform.emit('[ERROR] %s: %s' % (_("Cause of error"), str(e)))
raise
def get_list(self):
"""
Will return a list of all objects currently opened.
:return:
"""
obj_list = []
for group in self.root_item.child_items:
for item in group.child_items:
obj_list.append(item.obj)
return obj_list
def update_view(self):
self.dataChanged.emit(QtCore.QModelIndex(), QtCore.QModelIndex())