2019-10-13 15:13:39 +00:00
|
|
|
# ##########################################################
|
2019-01-03 19:25:08 +00:00
|
|
|
# FlatCAM: 2D Post-processing for Manufacturing #
|
|
|
|
# http://flatcam.org #
|
|
|
|
# Author: Juan Pablo Caram (c) #
|
|
|
|
# Date: 2/5/2014 #
|
|
|
|
# MIT Licence #
|
2019-10-13 15:13:39 +00:00
|
|
|
# ##########################################################
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-10-13 15:13:39 +00:00
|
|
|
# ##########################################################
|
2019-03-10 13:22:16 +00:00
|
|
|
# File modified by: Dennis Hayrullin #
|
2019-10-13 15:13:39 +00:00
|
|
|
# File modified by: Marius Stanciu #
|
|
|
|
# ##########################################################
|
2019-03-10 13:22:16 +00:00
|
|
|
|
2019-10-15 23:28:18 +00:00
|
|
|
from PyQt5 import QtGui, QtCore, QtWidgets
|
|
|
|
from PyQt5.QtCore import Qt, QSettings
|
|
|
|
from PyQt5.QtGui import QColor
|
2019-01-03 19:25:08 +00:00
|
|
|
# from PyQt5.QtCore import QModelIndex
|
2019-10-15 23:28:18 +00:00
|
|
|
|
2020-04-27 09:34:56 +00:00
|
|
|
from flatcamObjects.FlatCAMObj import FlatCAMObj
|
|
|
|
from flatcamObjects.FlatCAMCNCJob import CNCJobObject
|
|
|
|
from flatcamObjects.FlatCAMDocument import DocumentObject
|
|
|
|
from flatcamObjects.FlatCAMExcellon import ExcellonObject
|
|
|
|
from flatcamObjects.FlatCAMGeometry import GeometryObject
|
|
|
|
from flatcamObjects.FlatCAMGerber import GerberObject
|
|
|
|
from flatcamObjects.FlatCAMScript import ScriptObject
|
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
import inspect # TODO: Remove
|
2019-10-15 23:28:18 +00:00
|
|
|
|
|
|
|
import re
|
|
|
|
import logging
|
|
|
|
from copy import deepcopy
|
|
|
|
from numpy import Inf
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-03-07 23:32:18 +00:00
|
|
|
import gettext
|
|
|
|
import FlatCAMTranslation as fcTranslate
|
2019-05-30 18:15:09 +00:00
|
|
|
import builtins
|
2019-03-07 23:32:18 +00:00
|
|
|
|
2019-03-13 23:09:06 +00:00
|
|
|
fcTranslate.apply_language('strings')
|
2019-03-10 15:12:58 +00:00
|
|
|
if '_' not in builtins.__dict__:
|
|
|
|
_ = gettext.gettext
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-10-15 23:28:18 +00:00
|
|
|
log = logging.getLogger('base')
|
|
|
|
|
2019-03-11 01:31:33 +00:00
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
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
|
|
|
|
|
2020-04-20 09:02:01 +00:00
|
|
|
# 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
|
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
keyPressed = QtCore.pyqtSignal(int)
|
|
|
|
|
|
|
|
def keyPressEvent(self, event):
|
2019-02-08 13:55:32 +00:00
|
|
|
# super(KeySensitiveListView, self).keyPressEvent(event)
|
2019-01-03 19:25:08 +00:00
|
|
|
self.keyPressed.emit(event.key())
|
|
|
|
|
|
|
|
def dragEnterEvent(self, event):
|
2020-04-20 09:02:01 +00:00
|
|
|
# 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
|
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
if event.mimeData().hasUrls:
|
|
|
|
event.accept()
|
|
|
|
else:
|
|
|
|
event.ignore()
|
|
|
|
|
|
|
|
def dragMoveEvent(self, event):
|
2019-02-02 16:26:01 +00:00
|
|
|
self.setDropIndicatorShown(True)
|
2020-04-20 09:02:01 +00:00
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
if event.mimeData().hasUrls:
|
|
|
|
event.accept()
|
|
|
|
else:
|
|
|
|
event.ignore()
|
|
|
|
|
|
|
|
def dropEvent(self, event):
|
2019-02-02 16:26:01 +00:00
|
|
|
drop_indicator = self.dropIndicatorPosition()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2020-04-20 09:02:01 +00:00
|
|
|
# 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
|
|
|
|
|
2019-02-02 16:26:01 +00:00
|
|
|
m = event.mimeData()
|
|
|
|
if m.hasUrls:
|
|
|
|
event.accept()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-02-02 16:26:01 +00:00
|
|
|
for url in m.urls():
|
|
|
|
self.filename = str(url.toLocalFile())
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2020-04-20 09:02:01 +00:00
|
|
|
# file drop from outside application
|
|
|
|
if drop_indicator == QtWidgets.QAbstractItemView.OnItem:
|
|
|
|
if self.filename == "":
|
2020-04-24 04:23:14 +00:00
|
|
|
self.app.inform.emit(_("Cancelled."))
|
2019-02-02 16:26:01 +00:00
|
|
|
else:
|
2020-04-20 09:02:01 +00:00
|
|
|
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
|
2019-01-03 19:25:08 +00:00
|
|
|
else:
|
|
|
|
event.ignore()
|
|
|
|
|
2019-02-02 16:26:01 +00:00
|
|
|
|
2019-04-30 09:51:21 +00:00
|
|
|
class TreeItem(KeySensitiveListView):
|
2019-01-03 19:25:08 +00:00
|
|
|
"""
|
|
|
|
Item of a tree model
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, data, icon=None, obj=None, parent_item=None):
|
2019-04-30 09:51:21 +00:00
|
|
|
super(TreeItem, self).__init__(parent_item)
|
2019-01-03 19:25:08 +00:00
|
|
|
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"),
|
2019-10-01 15:24:15 +00:00
|
|
|
("cncjob", "CNC Job"),
|
|
|
|
("script", "Scripts"),
|
2019-10-02 14:58:48 +00:00
|
|
|
("document", "Document"),
|
2019-01-03 19:25:08 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
classdict = {
|
2020-04-27 09:34:56 +00:00
|
|
|
"gerber": GerberObject,
|
|
|
|
"excellon": ExcellonObject,
|
|
|
|
"cncjob": CNCJobObject,
|
|
|
|
"geometry": GeometryObject,
|
|
|
|
"script": ScriptObject,
|
|
|
|
"document": DocumentObject
|
2019-01-03 19:25:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
icon_files = {
|
2020-04-28 14:23:49 +00:00
|
|
|
"gerber": "assets/resources/flatcam_icon16.png",
|
|
|
|
"excellon": "assets/resources/drill16.png",
|
|
|
|
"cncjob": "assets/resources/cnc16.png",
|
|
|
|
"geometry": "assets/resources/geometry16.png",
|
|
|
|
"script": "assets/resources/script_new16.png",
|
|
|
|
"document": "assets/resources/notes16_1.png"
|
2019-01-03 19:25:08 +00:00
|
|
|
}
|
|
|
|
|
2019-10-21 12:55:49 +00:00
|
|
|
# will emit the name of the object that was just selected
|
|
|
|
item_selected = QtCore.pyqtSignal(str)
|
2020-04-20 09:02:01 +00:00
|
|
|
update_list_signal = QtCore.pyqtSignal()
|
2019-10-21 12:55:49 +00:00
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
root_item = None
|
|
|
|
# app = None
|
|
|
|
|
|
|
|
def __init__(self, app, parent=None):
|
|
|
|
|
|
|
|
QtCore.QAbstractItemModel.__init__(self)
|
|
|
|
|
2019-09-16 23:38:24 +00:00
|
|
|
self.app = app
|
|
|
|
|
2019-05-30 18:05:12 +00:00
|
|
|
# ## Icons for the list view
|
2019-01-03 19:25:08 +00:00
|
|
|
self.icons = {}
|
|
|
|
for kind in ObjectCollection.icon_files:
|
2019-12-15 14:28:36 +00:00
|
|
|
self.icons[kind] = QtGui.QPixmap(
|
2020-04-28 14:23:49 +00:00
|
|
|
ObjectCollection.icon_files[kind].replace('assets/resources', self.app.resource_location))
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
# 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"]))
|
|
|
|
|
2019-05-30 18:05:12 +00:00
|
|
|
# ## Data # ##
|
2019-01-03 19:25:08 +00:00
|
|
|
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()
|
|
|
|
|
2019-04-05 12:28:32 +00:00
|
|
|
# same as above only for objects that are plotted
|
|
|
|
self.plot_promises = set()
|
|
|
|
|
2019-05-30 18:05:12 +00:00
|
|
|
# ## View
|
2019-09-16 23:38:24 +00:00
|
|
|
self.view = KeySensitiveListView(self.app)
|
2019-01-03 19:25:08 +00:00
|
|
|
self.view.setModel(self)
|
2019-02-02 16:26:01 +00:00
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
self.view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
2019-02-02 16:26:01 +00:00
|
|
|
self.view.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
|
|
|
# self.view.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
|
|
|
|
# self.view.setDragEnabled(True)
|
|
|
|
# self.view.setAcceptDrops(True)
|
|
|
|
# self.view.setDropIndicatorShown(True)
|
|
|
|
|
2019-08-13 01:23:32 +00:00
|
|
|
settings = QSettings("Open Source", "FlatCAM")
|
|
|
|
if settings.contains("notebook_font_size"):
|
|
|
|
fsize = settings.value('notebook_font_size', type=int)
|
|
|
|
else:
|
|
|
|
fsize = 12
|
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
font = QtGui.QFont()
|
2019-08-13 01:23:32 +00:00
|
|
|
font.setPixelSize(fsize)
|
2019-01-03 19:25:08 +00:00
|
|
|
font.setFamily("Seagoe UI")
|
|
|
|
self.view.setFont(font)
|
|
|
|
|
2019-05-30 18:05:12 +00:00
|
|
|
# ## GUI Events
|
2019-01-03 19:25:08 +00:00
|
|
|
self.view.selectionModel().selectionChanged.connect(self.on_list_selection_change)
|
2019-06-17 14:01:27 +00:00
|
|
|
# self.view.activated.connect(self.on_item_activated)
|
2019-02-06 12:44:16 +00:00
|
|
|
self.view.keyPressed.connect(self.app.ui.keyPressEvent)
|
2019-06-17 14:01:27 +00:00
|
|
|
# self.view.clicked.connect(self.on_mouse_down)
|
2019-01-03 19:25:08 +00:00
|
|
|
self.view.customContextMenuRequested.connect(self.on_menu_request)
|
|
|
|
|
|
|
|
self.click_modifier = None
|
|
|
|
|
2020-04-20 09:02:01 +00:00
|
|
|
self.update_list_signal.connect(self.on_update_list_signal)
|
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
def promise(self, obj_name):
|
2020-04-27 07:03:22 +00:00
|
|
|
log.debug("Object %s has been promised." % obj_name)
|
2019-01-03 19:25:08 +00:00
|
|
|
self.promises.add(obj_name)
|
|
|
|
|
|
|
|
def has_promises(self):
|
|
|
|
return len(self.promises) > 0
|
|
|
|
|
2019-04-05 12:28:32 +00:00
|
|
|
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
|
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
def on_mouse_down(self, event):
|
2020-04-27 07:03:22 +00:00
|
|
|
log.debug("Mouse button pressed on list")
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
def on_menu_request(self, pos):
|
|
|
|
|
|
|
|
sel = len(self.view.selectedIndexes()) > 0
|
|
|
|
self.app.ui.menuprojectenable.setEnabled(sel)
|
|
|
|
self.app.ui.menuprojectdisable.setEnabled(sel)
|
2019-12-22 04:52:45 +00:00
|
|
|
self.app.ui.menuprojectcolor.setEnabled(sel)
|
2019-02-16 17:47:50 +00:00
|
|
|
self.app.ui.menuprojectviewsource.setEnabled(sel)
|
|
|
|
|
2019-01-24 10:31:42 +00:00
|
|
|
self.app.ui.menuprojectcopy.setEnabled(sel)
|
2019-01-24 18:58:36 +00:00
|
|
|
self.app.ui.menuprojectedit.setEnabled(sel)
|
2019-01-03 19:25:08 +00:00
|
|
|
self.app.ui.menuprojectdelete.setEnabled(sel)
|
2019-02-15 21:35:23 +00:00
|
|
|
self.app.ui.menuprojectsave.setEnabled(sel)
|
2019-01-24 18:58:36 +00:00
|
|
|
self.app.ui.menuprojectproperties.setEnabled(sel)
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
if sel:
|
|
|
|
self.app.ui.menuprojectgeneratecnc.setVisible(True)
|
2019-01-24 18:58:36 +00:00
|
|
|
self.app.ui.menuprojectedit.setVisible(True)
|
2019-02-15 21:35:23 +00:00
|
|
|
self.app.ui.menuprojectsave.setVisible(True)
|
2019-02-16 17:47:50 +00:00
|
|
|
self.app.ui.menuprojectviewsource.setVisible(True)
|
2019-12-22 04:52:45 +00:00
|
|
|
self.app.ui.menuprojectcolor.setEnabled(False)
|
2019-01-24 18:58:36 +00:00
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
for obj in self.get_selected():
|
2020-04-27 09:34:56 +00:00
|
|
|
if type(obj) == GerberObject or type(obj) == ExcellonObject:
|
2019-12-22 04:52:45 +00:00
|
|
|
self.app.ui.menuprojectcolor.setEnabled(True)
|
|
|
|
|
2020-04-27 09:34:56 +00:00
|
|
|
if type(obj) != GeometryObject:
|
2019-01-03 19:25:08 +00:00
|
|
|
self.app.ui.menuprojectgeneratecnc.setVisible(False)
|
2020-04-27 09:34:56 +00:00
|
|
|
if type(obj) != GeometryObject and type(obj) != ExcellonObject and type(obj) != GerberObject:
|
2019-01-24 18:58:36 +00:00
|
|
|
self.app.ui.menuprojectedit.setVisible(False)
|
2020-04-27 09:34:56 +00:00
|
|
|
if type(obj) != GerberObject and type(obj) != ExcellonObject and type(obj) != CNCJobObject:
|
2019-02-16 17:47:50 +00:00
|
|
|
self.app.ui.menuprojectviewsource.setVisible(False)
|
2020-04-27 09:34:56 +00:00
|
|
|
if type(obj) != GerberObject and type(obj) != GeometryObject and type(obj) != ExcellonObject and \
|
|
|
|
type(obj) != CNCJobObject:
|
2019-10-02 14:58:48 +00:00
|
|
|
# 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)
|
2019-01-03 19:25:08 +00:00
|
|
|
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()
|
|
|
|
|
2019-02-02 16:26:01 +00:00
|
|
|
# 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
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
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:
|
2019-05-01 00:33:15 +00:00
|
|
|
color = QColor(self.app.defaults['global_proj_item_color'])
|
2019-05-01 09:29:47 +00:00
|
|
|
color_disabled = QColor(self.app.defaults['global_proj_item_dis_color'])
|
2019-01-03 19:25:08 +00:00
|
|
|
obj = index.internalPointer().obj
|
|
|
|
if obj:
|
2019-05-01 09:29:47 +00:00
|
|
|
return QtGui.QBrush(color) if obj.options["plot"] else QtGui.QBrush(color_disabled)
|
2019-01-03 19:25:08 +00:00
|
|
|
else:
|
|
|
|
return index.internalPointer().data(index.column())
|
|
|
|
|
|
|
|
elif role == Qt.DecorationRole:
|
|
|
|
icon = index.internalPointer().icon
|
|
|
|
if icon:
|
|
|
|
return icon
|
|
|
|
else:
|
|
|
|
return QtGui.QPixmap()
|
2020-04-20 09:02:01 +00:00
|
|
|
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
|
2019-01-03 19:25:08 +00:00
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def setData(self, index, data, role=None):
|
|
|
|
if index.isValid():
|
|
|
|
obj = index.internalPointer().obj
|
2019-06-17 14:01:27 +00:00
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
if obj:
|
2019-06-17 14:01:27 +00:00
|
|
|
old_name = deepcopy(obj.options['name'])
|
2019-04-25 17:42:56 +00:00
|
|
|
new_name = str(data)
|
2019-04-30 09:51:21 +00:00
|
|
|
if old_name != new_name and new_name != '':
|
2019-04-25 17:42:56 +00:00
|
|
|
# rename the object
|
2019-05-30 18:05:12 +00:00
|
|
|
obj.options["name"] = deepcopy(data)
|
2019-04-25 17:42:56 +00:00
|
|
|
|
2019-10-04 14:18:07 +00:00
|
|
|
self.app.object_status_changed.emit(obj, 'rename', old_name)
|
|
|
|
|
2019-04-25 17:42:56 +00:00
|
|
|
# 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)
|
2019-05-30 18:05:12 +00:00
|
|
|
except Exception as e:
|
2019-04-25 17:42:56 +00:00
|
|
|
log.debug(
|
2019-05-30 18:05:12 +00:00
|
|
|
"setData() --> Could not remove the old object name from auto-completer model list. %s" %
|
|
|
|
str(e))
|
|
|
|
# obj.build_ui()
|
2019-04-25 17:42:56 +00:00
|
|
|
self.app.inform.emit(_("Object renamed from <b>{old}</b> to <b>{new}</b>").format(old=old_name,
|
|
|
|
new=new_name))
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2020-04-20 09:02:01 +00:00
|
|
|
self.dataChanged.emit(index, index)
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-02-02 16:26:01 +00:00
|
|
|
def supportedDropActions(self):
|
|
|
|
return Qt.MoveAction
|
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
def flags(self, index):
|
2019-02-02 16:26:01 +00:00
|
|
|
default_flags = QtCore.QAbstractItemModel.flags(self, index)
|
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
if not index.isValid():
|
2019-02-02 16:26:01 +00:00
|
|
|
return Qt.ItemIsEnabled | default_flags
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
# Prevent groups from selection
|
2020-04-20 09:02:01 +00:00
|
|
|
try:
|
|
|
|
if not index.internalPointer().obj:
|
|
|
|
return Qt.ItemIsEnabled
|
|
|
|
else:
|
|
|
|
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable | \
|
|
|
|
Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled
|
|
|
|
except AttributeError:
|
2019-01-03 19:25:08 +00:00
|
|
|
return Qt.ItemIsEnabled
|
2019-02-02 16:26:01 +00:00
|
|
|
# return QtWidgets.QAbstractItemModel.flags(self, index)
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2020-04-20 09:02:01 +00:00
|
|
|
def append(self, obj, active=False, to_index=None):
|
2020-04-27 07:03:22 +00:00
|
|
|
log.debug(str(inspect.stack()[1][3]) + " --> OC.append()")
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
name = obj.options["name"]
|
|
|
|
|
|
|
|
# Check promises and clear if exists
|
|
|
|
if name in self.promises:
|
|
|
|
self.promises.remove(name)
|
2020-04-27 07:03:22 +00:00
|
|
|
# log.debug("Promised object %s became available." % name)
|
|
|
|
# log.debug("%d promised objects remaining." % len(self.promises))
|
2019-02-22 01:28:04 +00:00
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
# Prevent same name
|
|
|
|
while name in self.get_names():
|
2019-05-30 18:05:12 +00:00
|
|
|
# ## Create a new name
|
2019-01-03 19:25:08 +00:00
|
|
|
# Ends with number?
|
2020-04-27 07:03:22 +00:00
|
|
|
log.debug("new_object(): Object name (%s) exists, changing." % name)
|
2019-01-03 19:25:08 +00:00
|
|
|
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
|
|
|
|
|
2020-02-03 00:18:28 +00:00
|
|
|
obj.set_ui(obj.ui_type(app=self.app))
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
# Required before appending (Qt MVC)
|
|
|
|
group = self.group_items[obj.kind]
|
|
|
|
group_index = self.index(group.row(), 0, QtCore.QModelIndex())
|
|
|
|
|
2020-04-20 09:02:01 +00:00
|
|
|
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()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
# Expand group
|
2020-04-01 15:45:20 +00:00
|
|
|
if group.child_count() == 1:
|
2019-01-03 19:25:08 +00:00
|
|
|
self.view.setExpanded(group_index, True)
|
|
|
|
|
2019-02-15 22:29:54 +00:00
|
|
|
self.app.should_we_save = True
|
|
|
|
|
2019-10-04 14:18:07 +00:00
|
|
|
self.app.object_status_changed.emit(obj, 'append', name)
|
2019-02-23 01:38:39 +00:00
|
|
|
|
2019-02-14 23:48:34 +00:00
|
|
|
# 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])
|
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
def get_names(self):
|
|
|
|
"""
|
|
|
|
Gets a list of the names of all objects in the collection.
|
|
|
|
|
|
|
|
:return: List of names.
|
|
|
|
:rtype: list
|
|
|
|
"""
|
|
|
|
|
2020-04-27 07:03:22 +00:00
|
|
|
# log.debug(str(inspect.stack()[1][3]) + " --> OC.get_names()")
|
2019-01-03 19:25:08 +00:00
|
|
|
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
|
|
|
|
"""
|
2020-04-27 07:03:22 +00:00
|
|
|
log.debug(str(inspect.stack()[1][3]) + "--> OC.get_bounds()")
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
# 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])
|
2019-05-30 18:15:09 +00:00
|
|
|
except Exception as e:
|
2020-04-27 07:03:22 +00:00
|
|
|
log.warning("DEV WARNING: Tried to get bounds of empty geometry. %s" % str(e))
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
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
|
2019-05-30 18:15:09 +00:00
|
|
|
:param isCaseSensitive: whether searching of the object is done by name where the name is case sensitive
|
2019-01-03 19:25:08 +00:00
|
|
|
:return: The requested object or None if no such object.
|
|
|
|
:rtype: FlatCAMObj or None
|
|
|
|
"""
|
2020-04-27 07:03:22 +00:00
|
|
|
# log.debug(str(inspect.stack()[1][3]) + "--> OC.get_by_name()")
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2019-02-22 01:28:04 +00:00
|
|
|
def delete_active(self, select_project=True):
|
2019-01-03 19:25:08 +00:00
|
|
|
selections = self.view.selectedIndexes()
|
|
|
|
if len(selections) == 0:
|
|
|
|
return
|
|
|
|
|
|
|
|
active = selections[0].internalPointer()
|
|
|
|
group = active.parent_item
|
|
|
|
|
2019-02-23 01:38:39 +00:00
|
|
|
# send signal with the object that is deleted
|
|
|
|
# self.app.object_status_changed.emit(active.obj, 'delete')
|
|
|
|
|
2019-10-02 14:58:48 +00:00
|
|
|
# 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
|
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
# 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)
|
2019-10-02 14:58:48 +00:00
|
|
|
# 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)
|
2019-05-30 18:15:09 +00:00
|
|
|
except Exception as e:
|
2019-01-03 19:25:08 +00:00
|
|
|
log.debug(
|
2019-05-30 18:15:09 +00:00
|
|
|
"delete_active() --> Could not remove the old object name from auto-completer model list. %s" % str(e))
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-10-04 14:18:07 +00:00
|
|
|
self.app.object_status_changed.emit(active.obj, 'delete', name)
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-10-04 14:18:07 +00:00
|
|
|
# ############ OBJECT DELETION FROM MODEL STARTS HERE ####################
|
|
|
|
self.beginRemoveRows(self.index(group.row(), 0, QtCore.QModelIndex()), active.row(), active.row())
|
2019-01-03 19:25:08 +00:00
|
|
|
group.remove_child(active)
|
|
|
|
# after deletion of object store the current list of objects into the self.app.all_objects_list
|
2020-01-29 01:14:46 +00:00
|
|
|
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(
|
2020-04-20 09:02:01 +00:00
|
|
|
"delete_by_name() --> Could not remove the old object name from auto-completer model list. %s" % str(e))
|
2020-01-29 01:14:46 +00:00
|
|
|
|
|
|
|
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
|
2020-04-20 09:02:01 +00:00
|
|
|
self.update_list_signal.emit()
|
2019-01-03 19:25:08 +00:00
|
|
|
self.endRemoveRows()
|
2019-10-04 14:18:07 +00:00
|
|
|
# ############ OBJECT DELETION FROM MODEL STOPS HERE ####################
|
|
|
|
|
2019-09-20 22:10:32 +00:00
|
|
|
if self.app.is_legacy is False:
|
|
|
|
self.app.plotcanvas.redraw()
|
2019-06-08 18:36:34 +00:00
|
|
|
|
2019-02-22 01:28:04 +00:00
|
|
|
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)
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-02-15 22:29:54 +00:00
|
|
|
self.app.should_we_save = True
|
|
|
|
|
2019-02-14 23:48:34 +00:00
|
|
|
# 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])
|
|
|
|
|
2020-04-20 09:02:01 +00:00
|
|
|
def on_update_list_signal(self):
|
|
|
|
self.app.all_objects_list = self.get_list()
|
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
def delete_all(self):
|
2020-04-27 07:03:22 +00:00
|
|
|
log.debug(str(inspect.stack()[1][3]) + "--> OC.delete_all()")
|
2019-10-04 14:18:07 +00:00
|
|
|
|
|
|
|
self.app.object_status_changed.emit(None, 'delete_all', '')
|
|
|
|
|
2019-09-25 00:26:34 +00:00
|
|
|
try:
|
|
|
|
self.app.all_objects_list.clear()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-09-25 00:26:34 +00:00
|
|
|
self.app.geo_editor.clear()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-09-25 00:26:34 +00:00
|
|
|
self.app.exc_editor.clear()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-09-25 00:26:34 +00:00
|
|
|
self.app.dblsidedtool.reset_fields()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-09-25 00:26:34 +00:00
|
|
|
self.app.panelize_tool.reset_fields()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-09-25 00:26:34 +00:00
|
|
|
self.app.cutout_tool.reset_fields()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-09-25 00:26:34 +00:00
|
|
|
self.app.film_tool.reset_fields()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-09-25 00:26:34 +00:00
|
|
|
self.beginResetModel()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-09-25 00:26:34 +00:00
|
|
|
self.checked_indexes = []
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-09-25 00:26:34 +00:00
|
|
|
for group in self.root_item.child_items:
|
|
|
|
group.remove_children()
|
2019-09-16 23:38:24 +00:00
|
|
|
|
2019-09-25 00:26:34 +00:00
|
|
|
self.endResetModel()
|
2019-09-16 23:38:24 +00:00
|
|
|
|
2019-09-25 00:26:34 +00:00
|
|
|
self.app.plotcanvas.redraw()
|
|
|
|
except Exception as e:
|
|
|
|
log.debug("ObjectCollection.delete_all() --> %s" % str(e))
|
2019-09-16 23:38:24 +00:00
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
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
|
|
|
|
"""
|
|
|
|
|
2019-05-30 18:15:09 +00:00
|
|
|
obj_list = self.get_list()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
for sel in self.get_selected():
|
2019-05-30 18:15:09 +00:00
|
|
|
obj_list.remove(sel)
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-05-30 18:15:09 +00:00
|
|
|
return obj_list
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2019-10-18 21:29:29 +00:00
|
|
|
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)
|
|
|
|
|
2019-10-04 14:18:07 +00:00
|
|
|
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)
|
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
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
|
|
|
|
"""
|
2019-08-17 23:04:36 +00:00
|
|
|
# log.debug("ObjectCollection.set_inactive()")
|
2019-05-01 00:33:15 +00:00
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
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):
|
2020-04-27 07:03:22 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
:param current: Current selected item
|
|
|
|
:param previous: Previously selected item
|
|
|
|
:return:
|
|
|
|
"""
|
|
|
|
|
|
|
|
# log.debug("on_list_selection_change()")
|
|
|
|
# log.debug("Current: %s, Previous %s" % (str(current), str(previous)))
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
obj = current.indexes()[0].internalPointer().obj
|
2019-10-21 12:55:49 +00:00
|
|
|
self.item_selected.emit(obj.options['name'])
|
2019-02-16 10:22:07 +00:00
|
|
|
|
|
|
|
if obj.kind == 'gerber':
|
2019-12-13 16:36:57 +00:00
|
|
|
self.app.inform.emit('[selected]<span style="color:{color};">{name}</span> {tx}'.format(
|
|
|
|
color='green',
|
|
|
|
name=str(obj.options['name']),
|
|
|
|
tx=_("selected"))
|
|
|
|
)
|
2019-02-16 10:22:07 +00:00
|
|
|
elif obj.kind == 'excellon':
|
2019-12-13 16:36:57 +00:00
|
|
|
self.app.inform.emit('[selected]<span style="color:{color};">{name}</span> {tx}'.format(
|
|
|
|
color='brown',
|
|
|
|
name=str(obj.options['name']),
|
|
|
|
tx=_("selected"))
|
|
|
|
)
|
2019-02-16 10:22:07 +00:00
|
|
|
elif obj.kind == 'cncjob':
|
2019-12-13 16:36:57 +00:00
|
|
|
self.app.inform.emit('[selected]<span style="color:{color};">{name}</span> {tx}'.format(
|
|
|
|
color='blue',
|
|
|
|
name=str(obj.options['name']),
|
|
|
|
tx=_("selected"))
|
|
|
|
)
|
2019-02-16 10:22:07 +00:00
|
|
|
elif obj.kind == 'geometry':
|
2019-12-13 16:36:57 +00:00
|
|
|
self.app.inform.emit('[selected]<span style="color:{color};">{name}</span> {tx}'.format(
|
|
|
|
color='red',
|
|
|
|
name=str(obj.options['name']),
|
|
|
|
tx=_("selected"))
|
|
|
|
)
|
2019-10-02 14:58:48 +00:00
|
|
|
elif obj.kind == 'script':
|
2019-12-13 16:36:57 +00:00
|
|
|
self.app.inform.emit('[selected]<span style="color:{color};">{name}</span> {tx}'.format(
|
|
|
|
color='orange',
|
|
|
|
name=str(obj.options['name']),
|
|
|
|
tx=_("selected"))
|
|
|
|
)
|
2019-10-02 14:58:48 +00:00
|
|
|
elif obj.kind == 'document':
|
2019-12-13 16:36:57 +00:00
|
|
|
self.app.inform.emit('[selected]<span style="color:{color};">{name}</span> {tx}'.format(
|
|
|
|
color='darkCyan',
|
|
|
|
name=str(obj.options['name']),
|
|
|
|
tx=_("selected"))
|
|
|
|
)
|
2019-01-03 19:25:08 +00:00
|
|
|
except IndexError:
|
2019-10-21 12:55:49 +00:00
|
|
|
self.item_selected.emit('none')
|
2020-04-27 07:03:22 +00:00
|
|
|
# log.debug("on_list_selection_change(): Index Error (Nothing selected?)")
|
2019-02-17 13:39:46 +00:00
|
|
|
self.app.inform.emit('')
|
2019-01-03 19:25:08 +00:00
|
|
|
try:
|
|
|
|
self.app.ui.selected_scroll_area.takeWidget()
|
2019-05-30 18:15:09 +00:00
|
|
|
except Exception as e:
|
2020-04-27 07:03:22 +00:00
|
|
|
log.debug("Nothing to remove. %s" % str(e))
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
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:
|
2019-12-08 14:16:02 +00:00
|
|
|
self.app.inform.emit('[ERROR] %s: %s' % (_("Cause of error"), str(e)))
|
2019-01-03 19:25:08 +00:00
|
|
|
raise
|
|
|
|
|
|
|
|
def get_list(self):
|
2020-04-13 17:28:39 +00:00
|
|
|
"""
|
|
|
|
Will return a list of all objects currently opened.
|
|
|
|
|
|
|
|
:return:
|
|
|
|
"""
|
2019-01-03 19:25:08 +00:00
|
|
|
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):
|
2019-05-01 09:29:47 +00:00
|
|
|
self.dataChanged.emit(QtCore.QModelIndex(), QtCore.QModelIndex())
|