def create(self, window: QtGui.QMainWindow, parent_menu: QtGui.QMenu): if self.disabled: return if callable(self.method_name): method = self.method_name else: method = getattr(window, self.method_name) if self.sep: parent_menu.addSeparator() if self.submenu: menu = QtGui.QMenu(self.verbose_name, p(parent_menu)) if self.icon: action = parent_menu.addMenu(get_icon(self.icon), menu) else: action = parent_menu.addMenu(menu) action.hovered.connect(functools.partial(self.fill_submenu, window, menu, method)) else: if self.icon: action = QtGui.QAction(get_icon(self.icon), self.verbose_name, p(parent_menu)) else: action = QtGui.QAction(self.verbose_name, p(parent_menu)) # noinspection PyUnresolvedReferences action.triggered.connect(method) parent_menu.addAction(action) if self.shortcut: action.setShortcut(self.shortcut) if self.help_text: action.setStatusTip(self.help_text)
class HierarchyTreeView(QTreeView): def __init__(self): super(HierarchyTreeView, self).__init__() #ukljucuje kontekstni meni self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.openMenu) def openMenu(self, position): self.contextMenu = QMenu() newMenu = QMenu("New") self.contextMenu.addMenu(newMenu) actionNewProj = QAction("NewProject", None) actionNewProj.triggered.connect(self.addNode) actionRename = QAction("Rename", None) actionRename.triggered.connect(self.renameNode) actionRemProj = QAction("Delete", None) actionRemProj.triggered.connect(self.removeNode) newMenu.addAction(actionNewProj) self.contextMenu.addAction(actionRename) self.contextMenu.addAction(actionRemProj) #prikaz kontekstnog menija self.contextMenu.exec_(self.viewport().mapToGlobal(position)) def addNode(self): model = self.model() node = Node("NoviCvor") if not self.currentIndex().isValid(): model.insertRow(model.rowCount(self.currentIndex()), node) else: model.insertRow(model.rowCount(self.currentIndex()), node, self.currentIndex()) self.expand(self.currentIndex()) def removeNode(self): model = self.model() model.removeRow(self.currentIndex().internalPointer().getIndex(), self.currentIndex().parent()) def renameNode(self): self.currentIndex().internalPointer().setName("NOVO") def mousePressEvent(self, event): if(self.selectionMode() == QAbstractItemView.SingleSelection): self.clearSelection() self.setCurrentIndex(QModelIndex()) super(HierarchyTreeView, self).mousePressEvent(event)
def as_QMenu(self): menu = QMenu() for item in self._items: if isinstance(item, Action): a = item.as_QAction() a.setEnabled(item.is_enabled()) menu.addAction(item) elif isinstance(item, Menu): menu.addMenu(item.as_QMenu()) return menu
def showHeaderMenu( self, pos ): header = self.horizontalHeader() column = header.logicalIndexAt(pos.x()) filterAction = QAction(self) filterAction.setText('Filter column') filterAction.triggered.connect(lambda: self.filterColumn(self.indexAt(pos))) symbolAction = QAction(self) symbolAction.setText('Symbol') symbolAction.triggered.connect(lambda: self.changeColumnDisplay(self.indexAt(pos),'symbol')) colourAction = QAction(self) colourAction.setText('Color') colourAction.triggered.connect(lambda: self.changeColumnDisplay(self.indexAt(pos),'brush')) sizeAction = QAction(self) sizeAction.setText('Size') sizeAction.triggered.connect(lambda: self.changeColumnDisplay(self.indexAt(pos),'size')) # show menu about the column menu = QMenu(self) displayMenu = menu.addMenu('Change graph display') displayMenu.addAction(symbolAction) displayMenu.addAction(colourAction) displayMenu.addAction(sizeAction) menu.addAction(filterAction) menu.popup(header.mapToGlobal(pos))
def __init__(self, icon, parent=None): QSystemTrayIcon.__init__(self, icon, parent) self.setToolTip("usb-resetter 1.0 (Left\Right-Click)") self.parent = parent self.activated.connect(self.toggleP) menu = QMenu(parent) self.fmenu = QMenu("Fast reset", parent) self.fmenu.setToolTip("List of filtered devices to fast reset") aboutAction = QAction("About", self) aboutAction.triggered.connect(parent.show_about) quitAction = QAction("Exit", self) quitAction.triggered.connect(parent.exitEvent) menu.addMenu(self.fmenu) menu.addSeparator() menu.addAction(aboutAction) menu.addAction(quitAction) self.setContextMenu(menu)
def showAttributeMenu(self, attribute): m = QMenu() m.addAction('Overlay/Filter') c = m.addMenu('Compare to') for h in self.headers: c.addAction(h) m.addAction('Sort...') choice = m.exec_(QCursor.pos()) if choice != None: choice = choice.text() if choice == 'Overlay/Filter': self.changeOverlay(attribute) elif choice == 'Sort...': # TODO pass else: self.showScatterplot(choice,attribute)
class MainWindow(QMainWindow): """docstring for MainWindow""" def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.serviceProvider = 0 self.popupMenu = None self.mapControlButtons = [] self.mapControlTypes = [] self.markerObjects = [] self.setWindowTitle(self.tr('Map Viewer Demo')) self.routingManager = None self.mapManager = None self.mapWidget = None self.markerIcon = None self.slider = None manager = QNetworkConfigurationManager() canStartIAP = manager.capabilities() & QNetworkConfigurationManager.CanStartAndStopInterfaces configuration = manager.defaultConfiguration() if not configuration.isValid or (not canStartIAP and configuration.starte() != QNetworkConfiguration.Active): QMessageBox.information(self, self.tr('Map Viewer Demo'), self.tr('Available Access Points not found.')) return self.session = QNetworkSession(configuration, self) self.session.opened.connect(self.networkSessionOpened) self.session.error.connect(self.error) self.session.open() self.session.waitForOpened() self.setProvider('nokia') self.setupUi() def networkSessionOpened(self): pass def sliderValueChanged(self, value): self.mapWidget.setZoomLevel(value) def mapZoomLevelChanged(self, level): self.slider.setSliderPosition(int(level)) def mapTypeChanged(self, newType): index = self.mapControlTypes.index(newType) if index != -1: self.mapControButtons[index].setChecked(True) def mapTypeToggled(self, checked): if checked: button = self.sender() index = self.mapControlButtons.index(button) if index != -1: print index, self.mapControlTypes[index] self.mapWidget.setMapType(self.mapControlTypes[index]) def updateCoords(self, coords): if not coords.isValid(): return self.latitudeEdit.setText('%f' % coords.latitude()) self.longitudeEdit.setText('%f' % coords.longitude()) def setCoordsClicked(self): lat = float(self.latitudeEdit.text()) lon = float(self.longitudeEdit.text()) self.mapWidget.setCenter(QGeoCoordinate(lat, lon)) def setProvider(self, providerId): self.serviceProvider = QGeoServiceProvider(providerId) if self.serviceProvider.error() != QGeoServiceProvider.NoError: QMessageBox.information(self, self.tr('MapViewer Example'), self.tr('Unable to dinf the %s geoservices plugin.' % providerId)) qApp.quit() return self.mapManager = self.serviceProvider.mappingManager() self.routingManager = self.serviceProvider.routingManager() def error(self, error): if error == QNetworkSession.UnknownSessionError: msgBox = QMessageBox(self.parent()) msgBox.setText('This application requires network access to function.') msgBox.setInformativeText('Press Cancel to quit the application.') msgBox.setStandardButtons(QMessageBox.Retry | QMessageBox.Cancel) msgBox.setIcon(QMessageBox.Information) msgBox.setDefaultButton(QMessageBox.Retry) ret = msgBox.exec_() if ret == QMessageBox.Retry: QTimer.singleShot(0, self.session.open) elif ret == QMessageBox.Cancel: self.close() elif error == QNetworkSession.SessionAbortedError: msgBox = QMessageBox(self.parent()) msgBox.setText('Out of range of network') msgBox.setInformativeText('Move back into range and press Retry, or press Cancel to quit the application') msgBox.setStandardButtons(QMessageBox.Retry | QMessageBox.Cancel) msgBox.setIcon(QMessageBox.Information) msgBox.setDefaultButton(QMessageBox.Retry) ret = msgBox.exec_() if ret == QMessageBox.Retry: QTimer.singleShot(0, self.session.open) elif ret == QMessageBox.Cancel: self.close() def setupUi(self): scene = QGraphicsScene(self) self.view = QGraphicsView(scene, self) self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setVisible(True) self.view.setInteractive(True) self.createPixmapIcon() self.mapWidget = MapWidget(self.mapManager) scene.addItem(self.mapWidget) self.mapWidget.setCenter(QGeoCoordinate(-8.1, -34.95)) self.mapWidget.setZoomLevel(5) #... self.slider = QSlider(Qt.Vertical, self) self.slider.setTickInterval(1) self.slider.setTickPosition(QSlider.TicksBothSides) self.slider.setMaximum(self.mapManager.maximumZoomLevel()) self.slider.setMinimum(self.mapManager.minimumZoomLevel()) self.slider.valueChanged[int].connect(self.sliderValueChanged) self.mapWidget.zoomLevelChanged[float].connect(self.mapZoomLevelChanged) mapControlLayout = QVBoxLayout() self.mapWidget.mapTypeChanged.connect(self.mapTypeChanged) for mapType in self.mapWidget.supportedMapTypes(): radio = QRadioButton(self) if mapType == QGraphicsGeoMap.StreetMap: radio.setText('Street') elif mapType == QGraphicsGeoMap.SatelliteMapDay: radio.setText('Sattelite') elif mapType == QGraphicsGeoMap.SatelliteMapNight: radio.setText('Sattelite - Night') elif mapType == QGraphicsGeoMap.TerrainMap: radio.setText('Terrain') if mapType == self.mapWidget.mapType(): radio.setChecked(True) radio.toggled[bool].connect(self.mapTypeToggled) self.mapControlButtons.append(radio) self.mapControlTypes.append(mapType) mapControlLayout.addWidget(radio) self.latitudeEdit = QLineEdit() self.longitudeEdit = QLineEdit() formLayout = QFormLayout() formLayout.addRow('Latitude', self.latitudeEdit) formLayout.addRow('Longitude', self.longitudeEdit) self.captureCoordsButton = QToolButton() self.captureCoordsButton.setText('Capture coordinates') self.captureCoordsButton.setCheckable(True) self.captureCoordsButton.toggled[bool].connect( self.mapWidget.setMouseClickCoordQuery) self.mapWidget.coordQueryResult.connect(self.updateCoords) self.setCoordsButton = QPushButton() self.setCoordsButton.setText('Set coordinates') self.setCoordsButton.clicked.connect(self.setCoordsClicked) buttonLayout = QHBoxLayout() buttonLayout.addWidget(self.captureCoordsButton) buttonLayout.addWidget(self.setCoordsButton) coordControlLayout = QVBoxLayout() coordControlLayout.addLayout(formLayout) coordControlLayout.addLayout(buttonLayout) widget = QWidget(self) layout = QGridLayout() layout.setRowStretch(0, 1) layout.setRowStretch(1, 0) topLayout = QGridLayout() bottomLayout = QGridLayout() topLayout.setColumnStretch(0, 0) topLayout.setColumnStretch(1, 1) bottomLayout.setColumnStretch(0, 0) bottomLayout.setColumnStretch(1, 1) topLayout.addWidget(self.slider, 0, 0) topLayout.addWidget(self.view, 0, 1) bottomLayout.addLayout(mapControlLayout, 0, 0) bottomLayout.addLayout(coordControlLayout, 0, 1) layout.addLayout(topLayout, 0, 0) layout.addLayout(bottomLayout, 1, 0) self.layout = layout widget.setLayout(layout) self.setCentralWidget(widget) self.view.setContextMenuPolicy(Qt.CustomContextMenu) self.view.customContextMenuRequested.connect(self.customContextMenuRequest) def createPixmapIcon(self): self.markerIcon = QPixmap(MARKER_WIDTH, MARKER_HEIGHT) self.markerIcon.fill(Qt.transparent) painter = QPainter(self.markerIcon) p1 = QPoint(MARKER_WIDTH / 2, MARKER_HEIGHT - 1) p2 = QPoint(MARKER_WIDTH / 2, MARKER_HEIGHT - 1 - MARKER_PIN_LEN) pen = QPen(Qt.black) pen.setWidth(2) pen.setCosmetic(True) painter.setPen(pen) painter.drawLine(p1, p2) ellipse = QRect(0, 0, MARKER_WIDTH - 1, MARKER_HEIGHT - 1) pen.setWidth(1) painter.setPen(pen) color = QColor(Qt.green) color.setAlpha(127) brush = QBrush(color) painter.setBrush(brush) painter.drawEllipse(ellipse) def resizeEvent(self, event): self.view.setSceneRect(QRectF(QPointF(0.0, 0.0), self.view.size())) self.mapWidget.resize(self.view.size()) def showEvent(self, event): self.view.setSceneRect(QRectF(QPointF(0.0, 0.0), self.view.size())) self.mapWidget.resize(self.view.size()) def createMenus(self): self.popupMenu = QMenu(self) # Markers subMenuItem = QMenu(self.tr('Marker'), self) self.popupMenu.addMenu(subMenuItem) menuItem = QAction(self.tr('Set marker'), self) subMenuItem.addAction(menuItem) menuItem.triggered[bool].connect(self.drawPixmap) menuItem = QAction(self.tr('Remove marker'), self) subMenuItem.addAction(menuItem) menuItem.triggered[bool].connect(self.removePixmaps) menuItem = QAction(self.tr('Select objects'), self) subMenuItem.addAction(menuItem) menuItem.triggered[bool].connect(self.selectObjects) # Draw subMenuItem = QMenu(self.tr('Draw'), self) self.popupMenu.addMenu(subMenuItem) menuItem = QAction(self.tr('Rectangle'), self) subMenuItem.addAction(menuItem) menuItem.triggered[bool].connect(self.drawRect) menuItem = QAction(self.tr('Polyline'), self) subMenuItem.addAction(menuItem) menuItem.triggered[bool].connect(self.drawPolyline) menuItem = QAction(self.tr('Polygon'), self) subMenuItem.addAction(menuItem) menuItem.triggered[bool].connect(self.drawPolygon) menuItem = QAction(self.tr('Circle'), self) subMenuItem.addAction(menuItem) menuItem.triggered[bool].connect(self.drawCircle) menuItem = QAction(self.tr('Text'), self) subMenuItem.addAction(menuItem) menuItem.triggered[bool].connect(self.drawText) # Routing subMenuItem = QMenu(self.tr('Route'), self) self.popupMenu.addMenu(subMenuItem) menuItem = QAction(self.tr('Calculate route'), self) subMenuItem.addAction(menuItem) menuItem.triggered[bool].connect(self.calculateRoute) def selectObjects(self): for obj in self.mapWidget.mapObjects(): obj.setSelected(False) if len(self.markerObjects) < 2: return bottomRight = self.markerObjects.pop() topLeft = self.markerObjects.pop() self.mapWidget.removeMapObject(topLeft) self.mapWidget.removeMapObject(bottomRight) selectedObjects = self.mapWidget.mapObjectsInScreenRect( QRectF(self.mapWidget.coordinateToScreenPosition(topLeft.coordinate()), self.mapWidget.coordinateToScreenPosition(bottomRight.coordinate())) ) for obj in selectedObjects: obj.setSelected(True) def drawRect(self): if len(self.markerObjects) < 2: return p1, p2 = self.markerObjects[:2] pen = QPen(Qt.white) pen.setWidth(2) pen.setCosmetic(True) fill = QColor(Qt.black) fill.setAlpha(65) rectangle = QGeoMapRectangleObject(p1.coordinate(), p2.coordinate()) rectangle.setPen(pen) rectangle.setBrush(QBrush(fill)) self.mapWidget.addMapObject(rectangle) def drawPolyline(self): path = [mark.coordinate() for mark in self.markerObjects] pen = QPen(Qt.white) pen.setWidth(2) pen.setCosmetic(True) polyline = QGeoMapPolylineObject() polyline.setPen(pen) polyline.setPath(path) self.mapWidget.addMapObject(polyline) def drawPolygon(self): path = [mark.coordinate() for mark in self.markerObjects] pen = QPen(Qt.white) pen.setWidth(2) pen.setCosmetic(True) polygon = QGeoMapPolygonObject() polygon.setPen(pen) fill = QColor(Qt.black) fill.setAlpha(65) polygon.setBrush(QBrush(fill)) polygon.setPath(path) self.mapWidget.addMapObject(polygon) def drawCircle(self): if not len(self.markerObjects): return p1 = self.markerObjects[0] center = p1.coordinate() radius = 3000 # Meters if len(self.markerObjects) >= 2: radius = center.distanceTo(self.markerObjects[1].coordinate()) pen = QPen(Qt.white) pen.setWidth(2) pen.setCosmetic(True) circle = QGeoMapCircleObject(center, radius) circle.setPen(pen) fill = QColor(Qt.black) fill.setAlpha(65) circle.setBrush(QBrush(fill)) self.mapWidget.addMapObject(circle) def drawText(self): if not len(self.markerObjects): return start = self.markerObjects[0].coordinate() text = QGeoMapTextObject(start, 'Text') fill = QColor(Qt.black) text.setBrush(fill) self.mapWidget.addMapObject(text) def calculateRoute(self): if len(self.markerObjects) < 2: return waypoints = [x.coordinate() for x in self.markerObjects[:2]] request = QGeoRouteRequest(waypoints) self.routeReply = self.routingManager.calculateRoute(request) self.routeReply.finished.connect(self.routeFinished) def routeFinished(self): if not self.routeReply.routes(): return route = QGeoMapRouteObject(self.routeReply.routes()[0]) routeColor = QColor(Qt.blue) routeColor.setAlpha(127) pen = QPen(routeColor) pen.setWidth(7) pen.setCosmetic(True) pen.setCapStyle(Qt.RoundCap) route.setPen(pen) self.mapWidget.addMapObject(route) def drawPixmap(self): marker = QGeoMapPixmapObject(self.mapWidget.screenPositionToCoordinate(self.lastClicked), QPoint(-(MARKER_WIDTH / 2), -MARKER_HEIGHT), self.markerIcon) self.mapWidget.addMapObject(marker) self.markerObjects.append(marker) def removePixmaps(self): for i in range(len(self.markerObjects)): marker = self.markerObjects.pop() self.mapWidget.removeMapObject(marker) marker.deleteLater() def customContextMenuRequest(self, point): self.lastClicked = point if self.focusWidget() == self.view: if not self.popupMenu: self.createMenus() self.popupMenu.popup(self.view.mapToGlobal(self.lastClicked))
class MenuNode(object): _currentMenuContext = None """docstring for MenuNode""" def __init__(self, option, parent, menubar = None): if isinstance(option ,(str,unicode)): blobs = option.split('|') _option={ 'label':blobs[0] } l = len(blobs) if l>1: _option['shortcut'] = blobs[1] if l>2: _option['help'] = blobs[2] option = _option self.qtmenubar = menubar self.qtaction = None self.qtmenu = None # self.qtaction = None self.owner = None self.parent = parent signal = option.get( 'signal', None ) self.setSignal(signal) self.mgr = parent and parent.mgr self.owner = parent and parent.owner self.children = [] self.label = option.get('label', 'UNNAMED') self.name = option.get('name',self.label.replace('&','').replace(' ','_')) self.name = self.name.lower() self.shortcut = option.get( 'shortcut', False ) self.help = option.get( 'help', '' ) self.priority = option.get( 'priority', 0 ) self.itemType = option.get( 'type', False ) self.onClick = option.get( 'on_click', None ) self.cmd = option.get( 'command', None ) self.cmdArgs = option.get( 'command_args', None ) self.link = None self.menuType = self.qtmenubar and 'menubar' or 'item' children = option.get( 'children', None ) link = option.get( 'link', None ) if children or self.itemType == 'menu': if self.menuType != 'menubar': self.menuType = 'menu' self.itemType = False elif link: self.link = link if self.menuType != 'menubar': self.menuType = 'link' elif parent and parent.menuType == 'menubar': self.menuType = 'menu' if self.menuType == 'menu' : self.qtmenu = QMenu(self.label) if not parent or parent.menuType == 'root': return parent.addChildControl(self) if self.itemType == 'check': checked = option.get('checked',False) self.setValue(checked or False) if children: for data in children: self.addChild(data) # self.mgr.addNodeIndex(self) def getFullName(self): if parent: return parent.getFullName()+'/'+self.name return self.name def addChild( self, option, owner = None ): if option=='----': if self.qtmenu: self.qtmenu.addSeparator() elif isinstance(option, list): output=[] for data in option: n = self.addChild(data) if n : output.append(n) if owner: n.owner = owner return output else: node = MenuNode(option, self) if owner: node.owner = owner self.children.append(node) return node def addChildControl(self, child): childType = child.menuType selfType = self.menuType if selfType=='menu': if childType=='menu': child.qtaction = self.qtmenu.addMenu(child.qtmenu) elif child.link: qtmenu = child.link.qtmenu child.qtaction = self.qtmenu.addMenu(qtmenu) else: action = QtGui.QAction(child.label, None, shortcut = child.shortcut, statusTip = child.help, checkable = child.itemType=='check', triggered = child.handleEvent ) self.qtmenu.addAction(action) child.qtaction = action elif selfType=='menubar': if childType=='menu': self.qtmenubar.addMenu(child.qtmenu) child.qtaction = child.qtmenu.menuAction() else: logging.warning('attempt to add menuitem/link to a menubar') return else: logging.warning('menuitem has no child') def setEnabled(self, enabled): #todo: set state of linked item selfType = self.menuType if selfType == 'menubar': self.qtmenubar.setEnable(enabled) return if self.qtmenu: self.qtmenu.setEnabled(enabled) else: self.qtaction.setEnabled(enabled) def remove(self): self.clear() self.parent.children.remove(self) selfType = self.menuType if not self.parent: return if selfType=='menubar': return parentType = self.parent.menuType if parentType == 'menu': self.parent.qtmenu.removeAction( self.qtaction ) elif parentType == 'menubar': self.parent.qtmenubar.removeAction( self.qtaction ) logging.info('remove menunode:' + self.name ) def clear( self ): if self.menuType in [ 'menu', 'menubar' ]: for node in self.children[:]: node.remove() def findChild(self,name): name = name.lower() for c in self.children: if c.name==name: return c return None def getValue(self): if self.itemType in ('check','radio'): return self.qtaction.isChecked() return True def setValue(self, v): if self.itemType in ('check','radio'): self.qtaction.setChecked(v and True or False) def setSignal(self, signal): if isinstance(signal, (str, unicode)): signal = signals.get(signal) self.signal = signal def popUp( self, **option ): if self.qtmenu: context = option.get( 'context', None ) MenuNode._currentMenuContext = context self.qtmenu.exec_(QtGui.QCursor.pos()) def getContext( self ): return MenuNode._currentMenuContext def setOnClick(self, onClick): self.onClick = onClick def handleEvent(self): itemtype = self.itemType value = self.getValue() logging.debug( 'menu event:' + self.name ) if self.owner: if hasattr( self.owner, 'onMenu' ): self.owner.onMenu( self ) if self.signal: self.signal(value) if self.onClick != None: self.onClick(value) if self.cmd: args = self.cmdArgs or {} app.doCommand( self.cmd, **args ) MenuNode._currentMenuContext = None
class Indicator(QSystemTrayIcon): def __init__(self, *args, **kwargs): QSystemTrayIcon.__init__(self, *args, **kwargs) self.app = QApplication.instance() self.menu = QMenu() self.setContextMenu(self.menu) self.menu.aboutToShow.connect(self.update) self.opened_notes = {} self.activated.connect(self._activated) self.settings = QSettings('everpad', 'everpad-pad') # Configure logger. self.logger = logging.getLogger('everpad-indicator') self.logger.setLevel(logging.DEBUG) fh = logging.FileHandler( os.path.expanduser('~/.everpad/logs/everpad.log')) fh.setLevel(logging.DEBUG) formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setFormatter(formatter) self.logger.addHandler(fh) def _activated(self, reason): if reason == QSystemTrayIcon.Trigger: self.menu.popup(QCursor().pos()) def _add_note(self, menu, struct): note = Note.from_tuple(struct) title = note.title[:40].replace('&', '&&') menu.addAction(title, Slot()(partial(self.open, note=note))) @Slot() def update(self): self.menu.clear() try: version = self.app.provider.get_api_version() except ( # dbus raise some magic dbus.exceptions.UnknownMethodException, dbus.exceptions.DBusException, ): version = -1 if version != API_VERSION: action = self.menu.addAction( self.tr('API version missmatch, please restart'), ) action.setEnabled(False) if version < API_VERSION: handler = self.app.provider.kill else: handler = partial(os.execlp, 'everpad', '--replace') self.menu.addAction( self.tr('Restart everpad'), handler, ) return if self.app.provider.is_authenticated(): pin_notes = self.app.provider.find_notes( '', dbus.Array([], signature='i'), dbus.Array([], signature='i'), 0, 20, Note.ORDER_UPDATED_DESC, 1, ) sort_by_notebook = bool( int( self.app.provider.get_settings_value('sort-by-notebook') or 0)) has_notes = False if not sort_by_notebook: notes = self.app.provider.find_notes( '', dbus.Array([], signature='i'), dbus.Array([], signature='i'), 0, 20 - len(pin_notes), Note.ORDER_UPDATED_DESC, 0, ) has_notes = bool(notes) else: notebooks = self.app.provider.list_notebooks() notes = {} for notebook_struct in notebooks: notebook = Notebook.from_tuple(notebook_struct) _notes = self.app.provider.find_notes( '', [notebook.id], dbus.Array([], signature='i'), 0, 20 - len(pin_notes), Note.ORDER_UPDATED_DESC, 0, ) notes[notebook] = _notes if _notes: has_notes = True first_sync = not (has_notes or len(pin_notes) or self.app.provider.is_first_synced()) # Rate Limit indication added # STATUS_RATE = -1 # Rate Limit status # STATUS_NONE = 0 # STATUS_SYNC = 1 # status_syncing = self.app.provider.get_status() == STATUS_SYNC status_syncing = self.app.provider.get_status() if status_syncing < 0: sync_label = self.tr('Rate Limit') elif status_syncing and first_sync: sync_label = self.tr('Wait, first sync in progress') elif status_syncing and not first_sync: sync_label = self.tr('Sync in progress') elif not status_syncing and first_sync: sync_label = self.tr('Please perform first sync') else: last_sync = self.app.provider.get_last_sync() delta_sync = (datetime.now() - datetime.strptime( last_sync, '%H:%M')).seconds // 60 if delta_sync == 0: sync_label = self.tr('Last Sync: Just now') elif delta_sync == 1: sync_label = self.tr('Last Sync: %s min ago') % delta_sync else: sync_label = self.tr('Last Sync: %s mins ago') % delta_sync menu_items = { 'create_note': [self.tr('Create Note'), self.create], 'all_notes': [self.tr('All Notes'), self.show_all_notes], 'sync': [sync_label, Slot()(self.app.provider.sync)], 'pin_notes': pin_notes, 'notes': notes, } for item in self.app.settings.value('menu-order', DEFAULT_INDICATOR_LAYOUT): if item == 'pin_notes' or item == 'notes': if not first_sync and len(menu_items[item]): self.menu.addSeparator() if item == 'notes' and sort_by_notebook: for notebook in menu_items[item]: sub_menu = self.menu.addMenu(notebook.name) _notes = menu_items[item][notebook] for struct in _notes: self._add_note(sub_menu, struct) else: for struct in menu_items[item]: self._add_note(self.menu, struct) self.menu.addSeparator() else: action = self.menu.addAction(menu_items[item][0], menu_items[item][1]) if status_syncing and item == 'sync': action.setEnabled(False) self.menu.addSeparator() self.menu.addAction(self.tr('Settings and Management'), self.show_management) self.menu.addAction(self.tr('Exit'), self.exit) def open(self, note, search_term=''): self.logger.debug('Opening note: "%s".' % note.title) old_note_window = self.opened_notes.get(note.id, None) if old_note_window and not getattr(old_note_window, 'closed', True): editor = self.opened_notes[note.id] # hide and show for bringing to front editor.hide() editor.show() else: editor = Editor(note) editor.show() self.opened_notes[note.id] = editor if search_term: editor.findbar.set_search_term(search_term) editor.findbar.show() editor.raise_() editor.activateWindow() return editor @Slot() def create(self, attach=None, notebook_id=NONE_ID): self.logger.debug('Creating new note.') note_struct = Note( # maybe replace NONE's to somthing better id=NONE_ID, title=self.tr('New note'), content=self.tr("New note content"), tags=dbus.Array([], signature='i'), notebook=notebook_id, created=NONE_VAL, updated=NONE_VAL, conflict_parent=NONE_VAL, conflict_items=dbus.Array([], signature='i'), place='', share_date=NONE_VAL, share_url='', ).struct note = Note.from_tuple(self.app.provider.create_note(note_struct), ) editor = self.open(note) if attach: editor.resource_edit.add_all_attach(attach) @Slot() def show_all_notes(self): if not hasattr(self, 'list') or getattr(self.list, 'closed', True): self.list = List() self.list.show() else: self.list.activateWindow() @Slot() def show_management(self): if not hasattr(self, 'management') or getattr(self.management, 'closed', True): self.management = Management() self.management.show() else: self.management.activateWindow() @Slot() def exit(self): self.app.quit()
def handleEvents(self, event, signals): att = self.axisOrder[self.findAxisIndex(event.x)] # context menu if event.contextRequested: contextMenu = QMenu(self) contextMenu.addAction(u'Select all') contextMenu.addAction(u'Select none') contextMenu.addSeparator() act = QAction(u'Hide Axis', self) contextMenu.addAction(act) if len(self.axisOrder) <= 1: act.setEnabled(False) axesMenu = QMenu(u'Show/Hide Axes', self) axesActions = QActionGroup(self) for a in self.axisOrder: act = QAction(a,self,checkable=True) if self.axes[a].visible: act.toggle() if len(self.axisOrder) <= 1: act.setEnabled(False) axesActions.addAction(act) for act in axesActions.actions(): axesMenu.addAction(act) contextMenu.addMenu(axesMenu) contextMenu.addSeparator() contextMenu.addAction(u'Use as X axis') contextMenu.addAction(u'Use as Y axis') resultAction = contextMenu.exec_(QCursor.pos()) if resultAction != None and resultAction != 0: # Select all if resultAction.text() == u'Select all': self.app.intMan.newOperation(operation.ALL,att=att.dataAxis) # Select none if resultAction.text() == u'Select none': self.app.intMan.newOperation(operation.NONE,att=att.dataAxis) # Hide axis if resultAction.text() == u'Hide Axis': self.toggleVisible(att) # Toggle axis if resultAction.actionGroup() == axesActions: self.toggleVisible(resultAction.text()) # X axis if resultAction.text() == u'Use as X axis': if self.app.currentYattribute != self.app.currentXattribute: self.axes[self.app.currentXattribute].visAxis.handle.background.setAttribute('fill',self.normalHandleColor) self.axes[self.app.currentXattribute].visAxis.handle.originalBackgroundColor = self.normalHandleColor self.axes[att].visAxis.handle.background.setAttribute('fill',self.activeHandleColor) self.axes[att].visAxis.handle.originalBackgroundColor = self.activeHandleColor self.app.notifyAxisChange(att,xAxis=True) # Y axis if resultAction.text() == u'Use as Y axis': if self.app.currentXattribute != self.app.currentYattribute: self.axes[self.app.currentYattribute].visAxis.handle.background.setAttribute('fill',self.normalHandleColor) self.axes[self.app.currentYattribute].visAxis.handle.originalBackgroundColor = self.normalHandleColor self.axes[att].visAxis.handle.background.setAttribute('fill',self.activeHandleColor) self.axes[att].visAxis.handle.originalBackgroundColor = self.activeHandleColor self.app.notifyAxisChange(att,xAxis=False) #if linesMoved: # self.highlightedLayer.refreshLines(self.app.highlightedRsNumbers) return signals
class Indicator(QSystemTrayIcon): def __init__(self, *args, **kwargs): QSystemTrayIcon.__init__(self, *args, **kwargs) self.app = QApplication.instance() self.menu = QMenu() self.setContextMenu(self.menu) self.menu.aboutToShow.connect(self.update) self.opened_notes = {} self.activated.connect(self._activated) self.settings = QSettings('everpad', 'everpad-pad') def _activated(self, reason): if reason == QSystemTrayIcon.Trigger: self.menu.popup(QCursor().pos()) def _add_note(self, menu, struct): note = Note.from_tuple(struct) title = note.title[:40].replace('&', '&&') menu.addAction(title, Slot()( partial(self.open, note=note) )) @Slot() def update(self): self.menu.clear() try: version = self.app.provider.get_api_version() except ( # dbus raise some magic dbus.exceptions.UnknownMethodException, dbus.exceptions.DBusException, ): version = -1 if version != API_VERSION: action = self.menu.addAction( self.tr('API version missmatch, please restart'), ) action.setEnabled(False) if version < API_VERSION: handler = self.app.provider.kill else: handler = partial(os.execlp, 'everpad', '--replace') self.menu.addAction( self.tr('Restart everpad'), handler, ) return if self.app.provider.is_authenticated(): pin_notes = self.app.provider.find_notes( '', dbus.Array([], signature='i'), dbus.Array([], signature='i'), 0, 20, Note.ORDER_UPDATED_DESC, 1, ) sort_by_notebook = bool(int( self.app.provider.get_settings_value('sort-by-notebook') or 0)) has_notes = False if not sort_by_notebook: notes = self.app.provider.find_notes( '', dbus.Array([], signature='i'), dbus.Array([], signature='i'), 0, 20 - len(pin_notes), Note.ORDER_UPDATED_DESC, 0, ) has_notes = bool(notes) else: notebooks = self.app.provider.list_notebooks() notes = {} for notebook_struct in notebooks: notebook = Notebook.from_tuple(notebook_struct) _notes = self.app.provider.find_notes('', [notebook.id], dbus.Array([], signature='i'), 0, 20 - len(pin_notes), Note.ORDER_UPDATED_DESC, 0, ) notes[notebook] = _notes if _notes: has_notes = True first_sync = not ( has_notes or len(pin_notes) or self.app.provider.is_first_synced() ) status_syncing = self.app.provider.get_status() == STATUS_SYNC if status_syncing and first_sync: sync_label = self.tr('Wait, first sync in progress') elif status_syncing and not first_sync: sync_label = self.tr('Sync in progress') elif not status_syncing and first_sync: sync_label = self.tr('Please perform first sync') else: last_sync = self.app.provider.get_last_sync() delta_sync = ( datetime.now() - datetime.strptime(last_sync, '%H:%M') ).seconds // 60 if delta_sync == 0: sync_label = self.tr('Last Sync: Just now') elif delta_sync == 1: sync_label = self.tr('Last Sync: %s min ago') % delta_sync else: sync_label = self.tr('Last Sync: %s mins ago') % delta_sync menu_items = { 'create_note': [self.tr('Create Note'), self.create], 'all_notes': [self.tr('All Notes'), self.show_all_notes], 'sync': [sync_label, Slot()(self.app.provider.sync)], 'pin_notes': pin_notes, 'notes': notes, } for item in self.app.settings.value('menu-order', DEFAULT_INDICATOR_LAYOUT): if item == 'pin_notes' or item == 'notes': if not first_sync and len(menu_items[item]): self.menu.addSeparator() if item == 'notes' and sort_by_notebook: for notebook in menu_items[item]: sub_menu = self.menu.addMenu(notebook.name) _notes = menu_items[item][notebook] for struct in _notes: self._add_note(sub_menu, struct) else: for struct in menu_items[item]: self._add_note(self.menu, struct) self.menu.addSeparator() else: action = self.menu.addAction(menu_items[item][0], menu_items[item][1]) if status_syncing and item == 'sync': action.setEnabled(False) self.menu.addSeparator() self.menu.addAction(self.tr('Settings and Management'), self.show_management) self.menu.addAction(self.tr('Exit'), self.exit) def open(self, note, search_term=''): old_note_window = self.opened_notes.get(note.id, None) if old_note_window and not getattr(old_note_window, 'closed', True): editor = self.opened_notes[note.id] # hide and show for bringing to front editor.hide() editor.show() else: editor = Editor(note) editor.show() self.opened_notes[note.id] = editor if search_term: editor.findbar.set_search_term(search_term) editor.findbar.show() editor.raise_() editor.activateWindow() return editor @Slot() def create(self, attach=None, notebook_id=NONE_ID): note_struct = Note( # maybe replace NONE's to somthing better id=NONE_ID, title=self.tr('New note'), content=self.tr("New note content"), tags=dbus.Array([], signature='i'), notebook=notebook_id, created=NONE_VAL, updated=NONE_VAL, conflict_parent=NONE_VAL, conflict_items=dbus.Array([], signature='i'), place='', share_date=NONE_VAL, share_url='', ).struct note = Note.from_tuple( self.app.provider.create_note(note_struct), ) editor = self.open(note) if attach: editor.resource_edit.add_all_attach(attach) @Slot() def show_all_notes(self): if not hasattr(self, 'list') or getattr(self.list, 'closed', True): self.list = List() self.list.show() else: self.list.activateWindow() @Slot() def show_management(self): if not hasattr(self, 'management') or getattr(self.management, 'closed', True): self.management = Management() self.management.show() else: self.management.activateWindow() @Slot() def exit(self): self.app.quit()
class Status(QWidget, Ui_Status): def __init__(self, parent=None): super(Status, self).__init__(parent) self.setupUi(self) self.base = parent self.wait_anim = QMovie(":/stuff/wait.gif") self.anim_lbl.setMovie(self.wait_anim) self.anim_lbl.hide() self.show_menu = QMenu(self) for i in [ self.act_page, self.act_date, self.act_text, self.act_comment ]: self.show_menu.addAction(i) # noinspection PyUnresolvedReferences i.triggered.connect(self.on_show_items) i.setChecked(True) sort_menu = QMenu(self) ico_sort = QIcon(":/stuff/sort.png") group = QActionGroup(self) action = QAction(_("Date"), sort_menu) action.setCheckable(True) action.setChecked(not self.base.high_by_page) action.triggered.connect(self.base.set_highlight_sort) action.setData(False) group.addAction(action) sort_menu.addAction(action) action = QAction(_("Page"), sort_menu) action.setCheckable(True) action.setChecked(self.base.high_by_page) action.triggered.connect(self.base.set_highlight_sort) action.setData(True) group.addAction(action) sort_menu.addAction(action) sort_menu.setIcon(ico_sort) sort_menu.setTitle(_("Sort by")) self.show_menu.addMenu(sort_menu) self.show_items_btn.setMenu(self.show_menu) def on_show_items(self): """ Show/Hide elements of the highlight info """ try: idx = self.base.file_table.selectionModel().selectedRows()[-1] except IndexError: # nothing selected return item = self.base.file_table.item(idx.row(), 0) self.base.on_file_table_itemClicked(item) def animation(self, run): """ Creates or deletes temporary files and folders :type run: bool :param run: Start/stop animation """ # if action == "start": if run: self.anim_lbl.show() self.wait_anim.start() else: self.anim_lbl.hide() self.wait_anim.stop()
class MTTSettingsMenu(QMenu): def __init__(self, parent=None): super(MTTSettingsMenu, self).__init__(parent) self.view = parent self.is_master_cmd = False # power user state self.power_user = MTTSettings.value('powerUser') self.__create_actions() self.__populate_menu() def keyPressEvent(self, event): if event.modifiers() == Qt.ControlModifier: self.is_master_cmd = True super(MTTSettingsMenu, self).keyPressEvent(event) def keyReleaseEvent(self, event): self.is_master_cmd = False super(MTTSettingsMenu, self).keyReleaseEvent(event) def __create_actions(self): def add_action(lbl, tip, cmd, checkable=False, checked=False): a = QAction(lbl, self) a.setStatusTip(tip) a.triggered.connect(cmd) if checkable: a.setCheckable(True) a.setChecked(checked) return a self.help_a = add_action( 'Help', 'Opens the online Help page', self.on_settings_help) self.switch_edit_a = add_action( 'Switch Edit/Source', 'Replace "Edit" button by "Source" button', self.on_switch_source_edit_menu, True, MTTSettings.value('switchEdit')) self.heads_up_a = add_action( 'HeadsUp Message', 'Show HeadsUp Message in viewport', self.on_toggle_headsup, True, MTTSettings.value('showHeadsUp')) self.focus_filter_a = add_action( 'Focus Filter Field at Startup', 'Focus filter field at startup', self.on_toggle_focus, True, MTTSettings.value('filterFocus')) self.force_relative_path_a = add_action( 'Force Relative Path', 'Set a relative path when selecting a new file', self.on_force_relative_path, True, MTTSettings.value('forceRelativePath')) self.show_real_attr_value_a = add_action( 'Show Real Attribute Value', 'Show fullpath instead of filtering path as Attribute Editor', self.on_show_real_attribute_value, True, MTTSettings.value('showRealAttributeValue')) self.manage_quick_filter_a = add_action( 'Manage Quick Filters', 'Manage filters that popup with right clic in filter field', self.on_filter_manage_quick_filter) self.clear_completion_cache_a = add_action( 'Clear Completion Cache', 'Erase auto completion cache of filter field', self.on_filter_clear_completion_cache) self.override_panels_a = add_action( 'Add CreateNode Button to Editors', ('Add "Create Node" to HyperShade and ' 'Node Editor for the current session'), self.on_override_panels) self.export_to_csv = add_action( 'Export Texture List as CSV', 'Export current textures into a csv file', self.view.model.export_as_csv) self.about = add_action( 'About', 'About', self.on_settings_about) def __populate_menu(self): self.addAction(self.help_a) self.addSeparator() self.addAction(self._get_menu_header('SETTINGS')) self.addAction(self.switch_edit_a) self.addAction(self.heads_up_a) self.addAction(self.focus_filter_a) self.addAction(self.force_relative_path_a) self.addAction(self.show_real_attr_value_a) self.addMenu(self._create_instance_menu()) self.addMenu(self._create_theme_menu()) self.addSeparator() self.addAction(self._get_menu_header('FILTER OPTIONS')) self.addAction(self.manage_quick_filter_a) self.addAction(self.clear_completion_cache_a) self.addSeparator() self.addAction(self._get_menu_header('MISC')) self.addAction(self.override_panels_a) self.addAction(self.export_to_csv) self.addSeparator() self.addAction(self._get_menu_header('DEBUG')) self.addMenu(self._create_debug_menu()) self.addSeparator() self.addAction(self.about) def _get_menu_header(self, title): header = QAction(title, self) header.setEnabled(False) return header def _create_instance_menu(self): self.instance_menu = QMenu(self) self.instance_menu.setTitle('Prompt Instance Delay') self.instance_menu.aboutToShow.connect( self.on_show_prompt_instance_delay_menu) return self.instance_menu def _create_theme_menu(self): theme_menu = QMenu(self) theme_menu.setTitle('Buttons Theme') theme_menu.setTearOffEnabled(True) theme_menu.setWindowTitle(TAG) theme_actions = QActionGroup(self) theme_actions.setExclusive(True) # create ordered theme list custom_order_theme = sorted(THEMES.iterkeys()) custom_order_theme.remove('Maya Theme') custom_order_theme.insert(0, 'Maya Theme') default_item = True for theme in custom_order_theme: current_theme_action = QAction(theme, theme_actions) current_theme_action.setCheckable(True) current_theme_action.setChecked( MTTSettings.value('theme', 'Maya Theme') == theme) current_theme_action.triggered.connect(self.on_change_theme) theme_menu.addAction(current_theme_action) if default_item: theme_menu.addSeparator() default_item = False return theme_menu def _create_debug_menu(self): self.debug_menu = QMenu(self) self.debug_menu.setTitle('Debug Menu') self.debug_menu.aboutToShow.connect(self.on_show_debug_menu) return self.debug_menu def on_change_theme(self): self.view.on_choose_theme(self.sender().text()) def on_show_debug_menu(self): self.debug_menu.clear() if self.is_master_cmd or self.power_user: power_user_mode = QAction('Power User Mode', self) power_user_mode.setCheckable(True) power_user_mode.setChecked(MTTSettings.value('powerUser')) power_user_mode.triggered.connect(self.__on_toggle_power_user) self.debug_menu.addAction(power_user_mode) self.is_master_cmd = False self.debug_menu.addSeparator() open_pref_folder_action = QAction('Open Preferences Folder', self) open_pref_folder_action.setStatusTip('Open MTT preference folder') open_pref_folder_action.triggered.connect(self.on_open_preference_folder) self.debug_menu.addAction(open_pref_folder_action) self.debug_menu.addSeparator() database_dump_csv = QAction('Dump Database as CSV', self) database_dump_csv.triggered.connect(self.view.model.database_dump_csv) self.debug_menu.addAction(database_dump_csv) database_dump_sql = QAction('Dump Database as SQL', self) database_dump_sql.triggered.connect(self.view.model.database_dump_sql) self.debug_menu.addAction(database_dump_sql) self.debug_menu.addSeparator() support_info = QMenu(self) support_info.setTitle('Supported Node Type') support_info.aboutToShow.connect(self.on_show_supported_type) self.debug_menu.addMenu(support_info) def on_filter_clear_completion_cache(self): """ Clear filter auto completion cache """ self.view.on_filter_set_text('') MTTSettings.remove('filterCompletionWildcard') MTTSettings.remove('filterCompletionRegExp') self.view.completion_model.setStringList([]) def on_switch_source_edit_menu(self): state = MTTSettings.value('switchEdit') MTTSettings.set_value('switchEdit', not state) self.view.on_set_source_edit_menu(not state) def on_show_real_attribute_value(self): self.view.model.layoutAboutToBeChanged.emit() show_real_attribute_state = MTTSettings.value('showRealAttributeValue') MTTSettings.set_value( 'showRealAttributeValue', not show_real_attribute_state) self.view._layout_changed() def on_filter_manage_quick_filter(self): """ Open Quick Filter words manager and save its content """ manager = MTTQuickFilterManager(self) if manager.exec_(): lists = manager.get_lists() # save list in settings MTTSettings.set_value('filterQuickWordsWildcard', ';;'.join(lists[0])) MTTSettings.set_value('filterQuickWordsRegExp', ';;'.join(lists[1])) # set current list self.view.quick_filter_words = lists[MTTSettings.value('filterRE')] manager.deleteLater() @staticmethod def on_toggle_headsup(): state = MTTSettings.value('showHeadsUp') MTTSettings.set_value('showHeadsUp', not state) @staticmethod def on_toggle_focus(): state = MTTSettings.value('filterFocus') MTTSettings.set_value('filterFocus', not state) @staticmethod def on_force_relative_path(): state = MTTSettings.value('forceRelativePath') MTTSettings.set_value('forceRelativePath', not state) def on_show_supported_type(self): node_types = sorted( [n_type for (n_type, nice, attr) in MTTSettings.SUPPORTED_TYPE] + MTTSettings.UNSUPPORTED_TYPE) support_info = self.sender() support_info.clear() for node_type in node_types: current = QAction(node_type, self) current.setEnabled(False) current.setCheckable(True) current.setChecked(node_type not in MTTSettings.UNSUPPORTED_TYPE) support_info.addAction(current) def __on_toggle_power_user(self): state = MTTSettings.value('powerUser') MTTSettings.set_value('powerUser', not state) self.power_user = not state @staticmethod def on_open_preference_folder(): """ Open preference folder """ folder_path = os.path.dirname(MTTSettings.filename()) cmds.launchImageEditor(viewImageFile=folder_path) @staticmethod def on_override_panels(): """ Override HyperShade and NodeEditor creation callback""" override_info_box = QMessageBox() override_info_box.setWindowTitle(WINDOW_TITLE) override_info_box.setIcon(QMessageBox.Information) override_info_box.setText( 'Buttons will be added to HyperShade toolbar and Node Editor toolbar.<br/>' 'Changes will exists during this session.' ) override_info_box.setInformativeText('<i>Read Help to set this settings permanent</i>') override_info_box.setStandardButtons(QMessageBox.Ok) override_info_box.setDefaultButton(QMessageBox.Ok) override_info_box.exec_() mttOverridePanels.override_panels() def on_settings_about(self): special_list = map(lambda x: x.replace(' ', ' '), sorted([ u'Beno\xeet Stordeur', u'Fran\xe7ois Jumel', 'Jonathan Lorber', 'Norbert Cretinon', 'Gilles Hoff' ])) QMessageBox.about( self.parent(), WINDOW_TITLE, '<b>Maya Texture Toolkit v{:.02f}</b>' u'<p>{} - \xa9 2014 - 2016' '</p>' '<p>Special thanks to :<br/>' '<i>{}</i>' '</p>'.format(__version__, __author__, ', '.join(special_list)) ) @staticmethod def on_settings_help(): help_wiki = 'https://github.com/Bioeden/dbMayaTextureToolkit/wiki' webbrowser.open(help_wiki) def on_show_prompt_instance_delay_menu(self): prompt_instance_state = cmds.optionVar(query='MTT_prompt_instance_state') if prompt_instance_state == PROMPT_INSTANCE_WAIT: elapsed_time = time() - cmds.optionVar(query='MTT_prompt_instance_suspend') if elapsed_time > PROMPT_INSTANCE_WAIT_DURATION: prompt_instance_state = PROMPT_INSTANCE_ASK cmds.optionVar(iv=['MTT_prompt_instance_state', prompt_instance_state]) else: mtt_log('Remaining %.2fs' % (PROMPT_INSTANCE_WAIT_DURATION - elapsed_time)) elif prompt_instance_state == PROMPT_INSTANCE_SESSION: if 'mtt_prompt_session' not in __main__.__dict__: prompt_instance_state = PROMPT_INSTANCE_ASK cmds.optionVar(iv=['MTT_prompt_instance_state', prompt_instance_state]) self.instance_menu.clear() prompt_delay = QActionGroup(self) prompt_delay.setExclusive(True) for i in range(len(PROMPT_INSTANCE_STATE.keys())): current_delay_action = QAction(PROMPT_INSTANCE_STATE[i], prompt_delay) current_delay_action.setCheckable(True) current_delay_action.setChecked(prompt_instance_state == i) current_delay_action.triggered.connect( partial(self.view.on_choose_instance_delay, i, prompt=i != 0)) self.instance_menu.addAction(current_delay_action)
class PresenceOverviewWidget(HorsePanel): @Slot(QModelIndex) def cell_entered(self, ndx): employee_id = self._employee_id_on_row(ndx) if not employee_id: self._show_totals_day_off(None) elif employee_id: chrono.chrono_start() employee = None for i in self.employees: if i.employee_id == employee_id: employee = i break self.detail_subframe.set_title(employee.fullname) self._show_totals_day_off(employee_id) d = date( self.base_date.year, self.base_date.month, min( calendar.monthrange(self.base_date.year, self.base_date.month)[1], max(1, ndx.column()))) chrono.chrono_click("Retrieveing data") tars = dao.task_action_report_dao.get_reports_for_employee_id_on_date( employee_id, d) work_timetracks = dao.timetrack_dao.all_work_for_employee_date_manual( employee_id, d) presence_timetracks = dao.timetrack_dao.all_presence_for_employee_date_managed_by_code_full( employee_id, d) # employee = dao.employee_dao.find_by_id(employee_id) special_activities = dao.special_activity_dao.find_on_day( employee_id, d) chrono.chrono_click("Redrawing") self.time_report_view.redraw(datetime(d.year, d.month, d.day, 6, 0), tars, employee_id, work_timetracks, presence_timetracks, special_activities, view_title=_("Work on {}").format( date_to_dmy(d, full_month=True))) session().close( ) # FIXME Put his one line above; but that's tough ! SQLA doesn't help us much here ! chrono.chrono_click("Session closed") # for event_type, duration in self.day_event_totals[employee_id].items(): # mainlog.debug("{}{}".format(event_type, duration)) self._toggle_days_off_actions() def _employee_id_on_row(self, row_or_ndx): r = row_or_ndx if type(r) != int: r = row_or_ndx.row() return self._table_model.data(self._table_model.index(r, 0), Qt.UserRole) DAY_EVENT_PALETTE = { DayEventType.holidays: (Qt.GlobalColor.white, Qt.GlobalColor.red), DayEventType.day_off: (Qt.GlobalColor.white, Qt.GlobalColor.darkRed), DayEventType.unpaid_day_off: (Qt.GlobalColor.black, Qt.GlobalColor.magenta), DayEventType.free_day: (Qt.GlobalColor.white, Qt.GlobalColor.darkMagenta), DayEventType.overtime: (Qt.GlobalColor.black, Qt.GlobalColor.green), DayEventType.recuperation: (Qt.GlobalColor.white, Qt.GlobalColor.darkGreen), DayEventType.unemployment: (Qt.GlobalColor.white, Qt.GlobalColor.blue), DayEventType.unemployment_short: (Qt.GlobalColor.white, Qt.GlobalColor.darkBlue), DayEventType.work_accident: (Qt.GlobalColor.black, Qt.GlobalColor.yellow), DayEventType.sick_leave: (Qt.GlobalColor.white, Qt.GlobalColor.darkYellow) } MONTH_EVENT_COLUMN = 2 YEAR_EVENT_COLUMN = 3 def _make_total_days_off_panel(self): widget = QFrame() widget.setObjectName('HorseRegularFrame') widget.setFrameShape(QFrame.Panel) widget.setFrameShadow(QFrame.Sunken) layout = QVBoxLayout() #layout.addWidget(QLabel(_("Days off to date"))) self.day_off_total_duration_labels = dict() self.day_off_month_duration_labels = dict() self.day_off_labels = dict() self._day_off_table_model = QStandardItemModel(10, 3) self._day_off_table_model.setHorizontalHeaderLabels( [None, None, _("This\nmonth"), _("Before")]) self.day_off_table_view = QTableView(None) self.day_off_table_view.setModel(self._day_off_table_model) # self.day_off_table_view.setHorizontalHeader(self.headers_view) self.day_off_table_view.verticalHeader().hide() self.day_off_table_view.setAlternatingRowColors(True) self.day_off_table_view.setEditTriggers( QAbstractItemView.NoEditTriggers) self.day_off_table_view.hide() row = 0 for det in DayEventType.symbols(): ndx = self._day_off_table_model.index(row, 0) self._day_off_table_model.setData(ndx, det.description, Qt.DisplayRole) ndx = self._day_off_table_model.index(row, 1) fg, bg = self.DAY_EVENT_PALETTE[det] self._day_off_table_model.setData(ndx, QBrush(bg), Qt.BackgroundRole) self._day_off_table_model.setData(ndx, QBrush(fg), Qt.TextColorRole) self._day_off_table_model.setData(ndx, DayEventType.short_code(det), Qt.DisplayRole) row += 1 layout.addWidget(self.day_off_table_view) grid = QGridLayout() self.days_off_layout = grid grid.setColumnStretch(3, 1) row = 0 grid.addWidget(QLabel(_('Year')), row, self.YEAR_EVENT_COLUMN) grid.addWidget(QLabel(_('Month')), row, self.MONTH_EVENT_COLUMN) row += 1 for det in DayEventType.symbols(): self.day_off_total_duration_labels[det] = QLabel("-") self.day_off_month_duration_labels[det] = QLabel("-") self.day_off_labels[det] = QLabel(det.description) hlayout = QHBoxLayout() sl = QLabel() fg, bg = self.DAY_EVENT_PALETTE[det] def to_html_rgb(color): i = color.red() * 256 * 256 + color.green() * 256 + color.blue( ) return "#{:06X}".format(i) p = QPalette() p.setColor(QPalette.Window, QColor(bg)) p.setColor(QPalette.WindowText, QColor(fg)) sl.setPalette(p) sl.setAlignment(Qt.AlignCenter) sl.setStyleSheet("border: 2px solid black; background: {}".format( to_html_rgb(QColor(bg)))) t = DayEventType.short_code(det) mainlog.debug(t) sl.setAutoFillBackground(True) sl.setText(t) grid.addWidget(sl, row, 0) grid.addWidget(self.day_off_labels[det], row, 1) grid.addWidget(self.day_off_total_duration_labels[det], row, self.YEAR_EVENT_COLUMN) grid.addWidget(self.day_off_month_duration_labels[det], row, self.MONTH_EVENT_COLUMN) hlayout.addStretch() row += 1 layout.addLayout(grid) layout.addStretch() self.day_off_table_view.resizeColumnsToContents() # self.day_off_table_view.setMinimumWidth( self.day_off_table_view.width()) # self.day_off_table_view.resize( self.day_off_table_view.minimumWidth(), # self.day_off_table_view.minimumHeight(),) widget.setLayout(layout) return widget def _show_totals_day_off(self, employee_id): mainlog.debug("_show_totals_day_off : {}".format(employee_id)) def form_layout_row_set_visible(layout, row_ndx, is_visible): for i in range(layout.columnCount()): l = layout.itemAtPosition(row_ndx, i) if l and l.widget(): l.widget().setVisible(is_visible) det_to_show = dict() row = 0 for det in DayEventType.symbols(): yearly = 0 if employee_id in self.all_events_in_year: if det in self.all_events_in_year[employee_id]: yearly = nice_round( self.all_events_in_year[employee_id][det]) monthly = 0 if employee_id in self.day_event_totals: if det in self.day_event_totals[employee_id]: monthly = nice_round( self.day_event_totals[employee_id][det]) # ndx = self._day_off_table_model.index(row,self.YEAR_EVENT_COLUMN) # self._day_off_table_model.setData(ndx, v, Qt.DisplayRole) if yearly or monthly: det_to_show[det] = {'monthly': monthly, 'yearly': yearly} if det_to_show: # If there are some days spent on some counters, then we display # those counters *only* mainlog.debug("_show_totals_day_off : showing some events ".format( str(det_to_show))) row = 0 for det in DayEventType.symbols(): if det in det_to_show: monthly = det_to_show[det]['monthly'] yearly = det_to_show[det]['yearly'] form_layout_row_set_visible(self.days_off_layout, row + 1, True) self.day_off_total_duration_labels[det].setText(yearly or '-') self.day_off_month_duration_labels[det].setText(monthly or '-') else: form_layout_row_set_visible(self.days_off_layout, row + 1, False) else: # If there are no days spent on any counter, then we display # all counters at the 0 mark. mainlog.debug("_show_totals_day_off : showing no event") row = 0 for det in DayEventType.symbols(): form_layout_row_set_visible(self.days_off_layout, row + 1, True) row += 1 # self.day_off_table_view.resizeColumnsToContents() self.days_off_panel.parent().update() @Slot() def refresh_action(self): global dao # mainlog.debug("refresh action started") self.hours_per_pers_subframe.set_title(date_to_my( self.base_date, True)) chrono.chrono_start() all_events_in_month = people_admin_service.events_for_month( self.base_date) employee_with_events = [ event.employee_id for event in all_events_in_month ] # mainlog.debug(all_events_in_month) self.all_events_in_year = people_admin_service.events_for_year( self.base_date.year) self.all_presences = all_presences = dao.employee_dao.presence_overview_for_month( self.base_date) all_correction_times = dict() for s in dao.month_time_synthesis_dao.load_all_synthesis( self.base_date.year, self.base_date.month): all_correction_times[s.employee_id] = s.correction_time special_activities = dao.special_activity_dao.find_on_month( self.base_date) employees = list( filter( lambda e: e.is_active or e.employee_id in all_presences or e. employee_id in all_correction_times or e.employee_id in special_activities or e.employee_id in employee_with_events, dao.employee_dao.list_overview())) self.employees = employees chrono.chrono_click() day_max = calendar.monthrange(self.base_date.year, self.base_date.month)[1] t_start = datetime(self.base_date.year, self.base_date.month, 1) t_end = datetime(self.base_date.year, self.base_date.month, day_max, 23, 59, 59, 999999) self._table_model.setRowCount(len(employees)) self._table_model.setColumnCount(1 + day_max + 3) headers = QStandardItemModel(1, 1 + day_max + 3) headers.setHeaderData(0, Qt.Orientation.Horizontal, _("Employee")) for i in range(day_max): headers.setHeaderData(i + 1, Qt.Orientation.Horizontal, "{}".format(i + 1)) headers.setHeaderData(day_max + 1, Qt.Orientation.Horizontal, _("Correction")) headers.setHeaderData(day_max + 2, Qt.Orientation.Horizontal, _("Total")) headers.setHeaderData(day_max + 3, Qt.Orientation.Horizontal, _("Days off")) self.headers_view.setModel( headers) # qt's doc : The view does *not* take ownership self.header_model = headers self.headers_view.setModel( self.header_model) # qt's doc : The view does *not* take ownership # Compute all mondays indices monday = 0 if t_start.weekday() > 0: monday = 7 - t_start.weekday() all_mondays = [] while monday < day_max: all_mondays.append(monday) monday += 7 today = date.today() # mainlog.debug("Running on employees") for row in range(self._table_model.rowCount()): # Clear the line for col in range(0, 32): ndx = self._table_model.index(row, col) self._table_model.setData(ndx, None, Qt.BackgroundRole) self._table_model.setData(ndx, QBrush(Qt.GlobalColor.black), Qt.TextColorRole) self._table_model.setData(ndx, None, Qt.DisplayRole) self._table_model.setData(ndx, None, Qt.UserRole) self._table_model.setData(ndx, None, Qt.UserRole + 1) # else: # self._table_model.setData(ndx,None,Qt.BackgroundRole) # else: # self._table_model.setData(ndx,None,Qt.DisplayRole) # self._table_model.setData(ndx,None,Qt.BackgroundRole) # Mark mondays for col in all_mondays: # col + 1 to account for the employee column self._table_model.setData( self._table_model.index(row, col + 1), QBrush(QColor(230, 230, 255)), Qt.BackgroundRole) # Mark today if today.month == self.base_date.month and today.year == self.base_date.year: self._table_model.setData( self._table_model.index(row, today.day), QBrush(QColor(255, 255, 128)), Qt.BackgroundRole) row = 0 for employee in employees: # employees are sorted self._table_model.setData(self._table_model.index(row, 0), employee.fullname, Qt.DisplayRole) # FIXME Use a delegate self._table_model.setData(self._table_model.index(row, 0), employee.employee_id, Qt.UserRole) # FIXME Use a delegate correction = 0 if employee.employee_id in all_correction_times: correction = all_correction_times[employee.employee_id] self._table_model.setData( self._table_model.index(row, day_max + 1), duration_to_hm(correction, short_unit=True), Qt.DisplayRole) else: self._table_model.setData( self._table_model.index(row, day_max + 1), None, Qt.DisplayRole) presence = 0 if employee.employee_id in all_presences and len( all_presences[employee.employee_id]) > 0: import functools presence = functools.reduce( lambda acc, s: acc + s, all_presences[employee.employee_id], 0) presence += correction if presence != 0: self._table_model.setData(ndx, QBrush(Qt.GlobalColor.black), Qt.TextColorRole) self._table_model.setData( self._table_model.index(row, day_max + 2), duration_to_hm(presence, short_unit=True), Qt.DisplayRole) else: self._table_model.setData( self._table_model.index(row, day_max + 2), None, Qt.DisplayRole) if employee.employee_id in all_presences and len( all_presences[employee.employee_id]) > 0: for b in range(len(all_presences[employee.employee_id])): ndx = self._table_model.index(row, b + 1) p = all_presences[employee.employee_id][b] if p > 0: self._table_model.setData( ndx, duration_to_hm(p, short_unit=True), Qt.DisplayRole) self._table_model.setData(ndx, p, Qt.UserRole) if p >= 4 and p <= 8: # Regular work load self._table_model.setData( ndx, QBrush(QColor(192, 255, 192)), Qt.BackgroundRole) elif p > 8 or (p < 4 and p > 0): # Problematic work load self._table_model.setData( ndx, QBrush(QColor(255, 192, 192)), Qt.BackgroundRole) if employee.employee_id in special_activities: sa_of_employee = special_activities[employee.employee_id] for sa in sa_of_employee: start = max(t_start, sa.start_time) end = min(t_end, sa.end_time) for i in range(start.day, end.day + 1): ndx = self._table_model.index(row, i) self._table_model.setData(ndx, QBrush(QColor(255, 128, 0)), Qt.BackgroundRole) # self._table_model.setData(self._table_model.index(row,b+1),Qt.AlignRight | Qt.AlignVCenter,Qt.TextAlignmentRole) row += 1 # Display day events employee_id_to_row = dict() # little accelerator for row in range(len(employees)): employee_id_to_row[employees[row].employee_id] = row # Compute days off totals and show them self.day_event_totals = dict([(e.employee_id, dict()) for e in employees]) for day_event in all_events_in_month: # mainlog.debug("employee_id = {}".format(day_event.employee_id)) # if day_event.employee_id not in self.day_event_totals: # mainlog.debug(self.day_event_totals) t = self.day_event_totals[day_event.employee_id] if day_event.event_type not in t: t[day_event.event_type] = day_event.duration else: t[day_event.event_type] += day_event.duration for employee in employees: # employees are sorted t = self.day_event_totals[employee.employee_id] mainlog.debug(t) total_off = sum(t.values()) mainlog.debug(total_off) row = employee_id_to_row[employee.employee_id] mainlog.debug(row) if total_off: self._table_model.setData( self._table_model.index(row, day_max + 3), nice_round(total_off), Qt.DisplayRole) else: self._table_model.setData( self._table_model.index(row, day_max + 3), None, Qt.DisplayRole) # Show days off for day_event in all_events_in_month: row = employee_id_to_row[day_event.employee_id] col = day_event.date.day fg = bg = None if day_event.event_type in self.DAY_EVENT_PALETTE: fg, bg = self.DAY_EVENT_PALETTE[day_event.event_type] else: fg, bg = Qt.GlobalColor.red, Qt.GlobalColor.gray ndx = self._table_model.index(row, col) self._table_model.setData(ndx, day_event.day_event_id, Qt.UserRole + 1) # The problem here is to nicely blend the fact # that you can have a day event mixed with actual work # the very same day. Here's a poor man solution. active_time = self._table_model.data(ndx, Qt.UserRole) if not active_time: self._table_model.setData( ndx, DayEventType.short_code(day_event.event_type), Qt.DisplayRole) self._table_model.setData(ndx, QBrush(fg), Qt.TextColorRole) self._table_model.setData(ndx, QBrush(bg), Qt.BackgroundRole) else: self._table_model.setData(ndx, QBrush(fg), Qt.TextColorRole) self._table_model.setData(ndx, QBrush(bg), Qt.BackgroundRole) self._table_model.setData( ndx, duration_to_hm(active_time, short_unit=True) + DayEventType.short_code(day_event.event_type), Qt.DisplayRole) chrono.chrono_click() #for i in range(len(all_mondays)): self.table_view.resizeColumnsToContents() # mainlog.debug("Reset selection") ndx = self.table_view.currentIndex() self.table_view.selectionModel().clear() # self.table_view.selectionModel().clearSelection() # self.table_view.selectionModel().select( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select) # self.table_view.selectionModel().select( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select) self.table_view.selectionModel().setCurrentIndex( self.table_view.model().index(ndx.row(), ndx.column()), QItemSelectionModel.Select) self.cell_entered(self.table_view.currentIndex()) @Slot() def edit_tars(self): employee_id = self._employee_id_on_row(self.table_view.currentIndex()) d = date( self.base_date.year, self.base_date.month, min( calendar.monthrange(self.base_date.year, self.base_date.month)[1], max(1, ndx.column()))) dialog = TimeReportingScannerDialog(self) dialog.set_data(datetime(d.year, d.month, d.day, 6, 0), employee_id) dialog.exec_() if dialog.result() == QDialog.Accepted: # pub.sendMessage('time_report.changed') self.timetrack_changed.emit() self.refresh_action() @Slot() def show_actions(self): button = self.action_menu.parent() p = button.mapToGlobal(QPoint(0, button.height())) self.action_menu.exec_(p) @Slot() def delete_holidays(self): ndx = self.table_view.currentIndex() employee_id = self._employee_id_on_row(ndx) d = date(self.base_date.year, self.base_date.month, ndx.column()) if dao.special_activity_dao.delete_by_employee_and_date( employee_id, d): self.refresh_panel() @Slot() def create_holidays(self): employee_id = self._employee_id_on_row(self.table_view.currentIndex()) left_col = 1000 right_col = 0 for ndx in self.table_view.selectionModel().selectedIndexes(): c = ndx.column() left_col = min(c, left_col) right_col = max(c, right_col) d_start = date( self.base_date.year, self.base_date.month, min( calendar.monthrange(self.base_date.year, self.base_date.month)[1], max(1, left_col))) d_end = date( self.base_date.year, self.base_date.month, min( calendar.monthrange(self.base_date.year, self.base_date.month)[1], max(1, right_col))) dialog = HolidaysDialog(self) sa = SpecialActivity() sa.employee_id = employee_id sa.reporter_id = user_session.user_id sa.encoding_date = date.today() sa.start_time = datetime(d_start.year, d_start.month, d_start.day, 6, 0) sa.end_time = datetime(d_end.year, d_end.month, d_end.day, 14, 0) dialog.setup(sa, dao.employee_dao.find_by_id(employee_id).fullname) # dialog.set_data(employee,self.base_date,c) dialog.exec_() if dialog.result() == QDialog.Accepted: dao.special_activity_dao.save(sa) self.refresh_action() @Slot() def edit_month_correction(self): employee_id = self._employee_id_on_row(self.table_view.currentIndex()) if employee_id: employee = dao.employee_dao.find_by_id(employee_id) c = dao.month_time_synthesis_dao.load_correction_time( employee_id, self.base_date.year, self.base_date.month) dialog = MonthTimeCorrectionDialog(self) dialog.set_data(employee.fullname, self.base_date, c) dialog.exec_() if dialog.result() == QDialog.Accepted: c = dao.month_time_synthesis_dao.save(employee_id, self.base_date.year, self.base_date.month, dialog.correction_time) self.refresh_action() @Slot() def month_today(self): self.base_date = date.today() self.refresh_action() @Slot() def month_before(self): m = self.base_date.month if m > 1: self.base_date = date(self.base_date.year, m - 1, 1) else: self.base_date = date(self.base_date.year - 1, 12, 1) self.refresh_action() @Slot() def month_after(self): m = self.base_date.month if self.base_date.year < date.today().year + 1 \ or m < date.today().month: if m < 12: self.base_date = date(self.base_date.year, m + 1, 1) else: self.base_date = date(self.base_date.year + 1, 1, 1) self.refresh_action() @Slot() def edit_timetrack_no_ndx(self): ndx = self.table_view.currentIndex() if ndx.isValid() and ndx.column() >= 0 and ndx.row() >= 0: self.edit_timetrack(ndx) else: showWarningBox(_("Can't edit"), _("You must first select a day/person.")) timetrack_changed = Signal() @Slot(QModelIndex) def edit_timetrack(self, ndx): global dao global user_session if ndx.column() >= 1: edit_date = date( self.base_date.year, self.base_date.month, ndx.column()) # +1 already in because of employee's names employee_id = self._employee_id_on_row(ndx) tars = dao.task_action_report_dao.get_reports_for_employee_id_on_date( employee_id, edit_date) if len(tars) == 0: d = EditTimeTracksDialog(self, dao, edit_date) d.set_employee_and_date(employee_id, edit_date) d.exec_() if d.result() == QDialog.Accepted: self.refresh_action() self.timetrack_changed.emit() d.deleteLater() else: edit_date = datetime(self.base_date.year, self.base_date.month, ndx.column(), hour=6) from koi.TimeReportingScanner import TimeReportingScannerDialog d = TimeReportingScannerDialog(self) d.set_data(edit_date, employee_id) # or 16 d.exec_() if d.result() == QDialog.Accepted: self.refresh_action() self.timetrack_changed.emit() d.deleteLater() @Slot() def editTaskActionReports(self): if not user_session.has_any_roles(['TimeTrackModify']): return m = self.base_date.month ndx = self.table_view.currentIndex() if ndx.isValid() and ndx.column() >= 0 and ndx.row() >= 0: edit_date = date( self.base_date.year, m, ndx.column()) # +1 already in because of employee's names employee = self._table_model.data( self._table_model.index(ndx.row(), 0), Qt.UserRole) # FIXME Use a delegate d = EditTaskActionReportsDialog(dao, self, edit_date) d.set_employee_date(employee, edit_date) d.exec_() if d.result() == QDialog.Accepted: self.refresh_action() d.deleteLater() else: showWarningBox(_("Can't edit"), _("You must first select a day/person.")) # @Slot(QModelIndex) # def timetrack_changed(self,ndx): # selected_timetrack = self.controller.model.object_at(ndx) # # Update the colors in the timetrack views # # to show what action reports correspond to the # # selected timetrack # self.controller_actions.model.current_timetrack = selected_timetrack # self.controller_actions.model.beginResetModel() # self.controller_actions.model.endResetModel() # # Make sure the first of the action reports is shown in the # # table # action_reports = self.controller_actions.model.objects # for i in range(len(action_reports)-1,-1,-1): # if action_reports[i] and action_reports[i].timetrack == selected_timetrack: # self.controller_actions.view.scrollTo(self.controller_actions.model.index(i,0)) # break def _make_table_header(self): pass def __init__(self, parent, find_order_action_slot): super(PresenceOverviewWidget, self).__init__(parent) self.set_panel_title(_("Presence overview")) self.base_date = date.today() headers = QStandardItemModel(1, 31 + 3) self._table_model = QStandardItemModel(1, 31 + 3, None) self.headers_view = QHeaderView(Qt.Orientation.Horizontal, self) self.header_model = headers self.headers_view.setResizeMode(QHeaderView.ResizeToContents) self.headers_view.setModel( self.header_model) # qt's doc : The view does *not* take ownership self.table_view = TableViewSignaledEvents(None) self.table_view.setModel(self._table_model) self.table_view.setHorizontalHeader(self.headers_view) self.table_view.verticalHeader().hide() self.table_view.setAlternatingRowColors(True) self.table_view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_view.setContextMenuPolicy(Qt.CustomContextMenu) self.table_view.customContextMenuRequested.connect( self.popup_context_menu) self.copy_action = QAction(_("Copy order parts"), self.table_view) self.copy_action.triggered.connect(self.copy_slot) self.copy_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_C)) self.copy_action.setShortcutContext(Qt.WidgetWithChildrenShortcut) self.table_view.addAction(self.copy_action) self.select_all_action = QAction(_("Select all"), self.table_view) self.select_all_action.triggered.connect(self.select_all_slot) self.select_all_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_A)) self.select_all_action.setShortcutContext( Qt.WidgetWithChildrenShortcut) self.table_view.addAction(self.select_all_action) # self.table_view.setSelectionBehavior(QAbstractItemView.SelectItems) # self.table_view.setSelectionMode(QAbstractItemView.SingleSelection) navbar = NavBar(self, [(_("Month before"), self.month_before), (_("Today"), self.month_today), (_("Action"), self.show_actions), (_("Month after"), self.month_after), (_("Find"), find_order_action_slot)]) self.action_menu = QMenu(navbar.buttons[2]) navbar.buttons[2].setObjectName("specialMenuButton") navbar.buttons[4].setObjectName("specialMenuButton") self._make_days_off_menu_and_action_group() list_actions = [ # (_("Edit"),self.edit_tars, None, None), (_("Edit"), self.edit_timetrack_no_ndx, None, None), (_("Month correction"), self.edit_month_correction, None, [RoleType.modify_monthly_time_track_correction]), (self.days_off_menu, None), (self.copy_action, None), (self.select_all_action, None) ] # (_("Insert holidays"),self.create_holidays, None, None), # (_("Delete holidays"),self.delete_holidays, None, None) ] populate_menu(self.action_menu, self, list_actions) # mainlog.debug("tile widget") self.title_box = TitleWidget(_("Presence Overview"), self, navbar) self.vlayout = QVBoxLayout(self) self.vlayout.setObjectName("Vlayout") self.vlayout.addWidget(self.title_box) self.hours_per_pers_subframe = SubFrame(_("Overview"), self.table_view, self) self.vlayout.addWidget(self.hours_per_pers_subframe) self.time_report_view = TimeReportView(self) self.days_off_panel = self._make_total_days_off_panel() vbox = QVBoxLayout() vbox.addWidget(self.days_off_panel) vbox.addStretch() vbox.setStretch(0, 0) vbox.setStretch(1, 1) hlayout = QHBoxLayout() hlayout.addWidget(self.time_report_view) hlayout.addLayout(vbox) hlayout.setStretch(0, 1) self.detail_subframe = SubFrame(_("Day"), hlayout, self) self.vlayout.addWidget(self.detail_subframe) self.setLayout(self.vlayout) # dbox = QVBoxLayout() # dbox.addWidget(QLabel("kjkljkj")) # self.total_active_hours = LabeledValue(_("Total activity")) # dbox.addWidget(self.total_active_hours) # hbox = QHBoxLayout() # hbox.addWidget(self.table_view) # hbox.addLayout(dbox) # self.selection_model = self.table_view.selectionModel() # mainlog.debug(m) #sm = QItemSelectionModel(self.table_view.model()) #sm.setModel(self.table_view.model()) # self.table_view.setSelectionModel(self.selection_model) self.table_view.selectionModel().currentChanged.connect( self.cell_entered) self.table_view.doubleClickedCell.connect(self.edit_timetrack) def _selection_to_period(self): left_col = 1000 right_col = 0 for ndx in self.table_view.selectionModel().selectedIndexes(): c = ndx.column() left_col = min(c, left_col) right_col = max(c, right_col) d_start = date( self.base_date.year, self.base_date.month, min( calendar.monthrange(self.base_date.year, self.base_date.month)[1], max(1, left_col))) d_end = date( self.base_date.year, self.base_date.month, min( calendar.monthrange(self.base_date.year, self.base_date.month)[1], max(1, right_col))) return d_start, d_end def _toggle_days_off_actions(self): day_max = calendar.monthrange(self.base_date.year, self.base_date.month)[1] ndx = self.table_view.currentIndex() can_add = can_remove = False if ndx.column() >= 1 and ndx.column() <= day_max: day_event_id = ndx.data(Qt.UserRole + 1) can_add = True # if not day_event_id: # day = ndx.column() - 1 # # employee_id = self._employee_id_on_row(ndx) # if employee_id in self.all_presences: # if not self.all_presences[employee_id][day]: # can_add = True # else: # can_add = True # else: # can_add = True can_remove = day_event_id is not None self.days_off_add_submenu.setEnabled(can_add) for actions in self.days_off_action_group.actions(): actions.setEnabled(can_add) self.day_off_remove_action.setEnabled(can_remove) def _add_day_off(self, action): if action.data() != 'Remove': day_event_type, day_event_duration = action.data() day_event_type = DayEventType.from_str(day_event_type) mainlog.debug("selected action {} {}".format( day_event_type, day_event_duration)) ndx = self.table_view.currentIndex() day_event_id = ndx.data(Qt.UserRole + 1) # if day_event_id: # showWarningBox(_("There's already a day off here")) # return employee_id = self._employee_id_on_row(ndx) if employee_id in self.all_presences: day = ndx.column() - 1 mainlog.debug("_add_day_off : employee_id={}, day={}".format( employee_id, day)) mainlog.debug(self.all_presences[employee_id]) mainlog.debug(type(self.all_presences[employee_id])) # if self.all_presences[employee_id][day]: # showWarningBox(_("One can't add day off where there is activity")) # return else: mainlog.debug( "_add_day_off : employee_id={} not yet known".format( employee_id)) day_event = DayEvent() day_event.employee_id = employee_id day_event.event_type = day_event_type day, last_day = self._selection_to_period() if day_event_duration in (0.5, 1): days_durations = [(day, day_event_duration)] else: days_durations = [] day, last_day = self._selection_to_period() while day <= last_day: days_durations.append( (day, 1)) # One full work day on the day day += timedelta(1) # mainlog.debug(days_durations) mainlog.debug("Creating day event of type {}".format( day_event.event_type)) try: people_admin_service.set_event_on_days(day_event, days_durations) except ServerException as ex: showErrorBox(ex.translated_message) self.refresh_action() def _remove_day_off(self): # Grab all the selected events event_ids = [] for ndx in self.table_view.selectionModel().selectedIndexes(): day_event_id = ndx.data(Qt.UserRole + 1) if day_event_id: mainlog.debug("Removing event: {}".format(day_event_id)) event_ids.append(day_event_id) # Remove them if event_ids: people_admin_service.remove_events(event_ids) self.refresh_action() def _make_days_off_menu_and_action_group(self): # We use a action group to be able to use the data() of actions # when action is tigerred # Call this ONLY ONCE because there are signal/slot connections. self.days_off_menu = QMenu(_("Day off")) self.days_off_add_submenu = QMenu(_("Set day off")) self.days_off_action_group = QActionGroup(self) for det in DayEventType.symbols(): a_one = QAction(_("Set one day"), self.days_off_action_group) a_one.setData((det.value, 1)) a_half = QAction(_("Set half day"), self.days_off_action_group) a_half.setData((det.value, 0.5)) a_period = QAction(_("Set period"), self.days_off_action_group) a_period.setData((det.value, 2)) self.days_off_action_group.addAction(a_one) self.days_off_action_group.addAction(a_half) self.days_off_action_group.addAction(a_period) m = QMenu(_("Set time off for {}").format(det.description)) m.addAction(a_one) m.addAction(a_half) m.addAction(a_period) self.days_off_add_submenu.addMenu(m) self.days_off_action_group.triggered.connect(self._add_day_off) self.day_off_remove_action = QAction(_("Remove day off"), self) self.day_off_remove_action.triggered.connect(self._remove_day_off) # Now we have the actions, we build the menu self.days_off_menu.addMenu(self.days_off_add_submenu) self.days_off_menu.addAction(self.day_off_remove_action) @Slot(QPoint) def popup_context_menu(self, position): self.days_off_menu.exec_(QCursor.pos()) @Slot() def select_all_slot(self): m = self.table_view.model() all = QItemSelection(m.index(0, 0), m.index(m.rowCount() - 1, m.columnCount() - 1)) self.table_view.selectionModel().select(all, QItemSelectionModel.Select) @Slot() def copy_slot(self): # Collect the rows indices indices = self.table_view.selectedIndexes() if not indices: return min_row = max_row = indices[0].row() min_col = max_col = indices[0].column() def min_max(minimum, v, maximum): if v < minimum: return v, maximum elif v > maximum: return minimum, v else: return minimum, maximum for ndx in self.table_view.selectedIndexes(): min_row, max_row = min_max(min_row, ndx.row(), max_row) min_col, max_col = min_max(min_col, ndx.column(), max_col) mainlog.debug("Copy from {},{} to {},{}".format( min_row, min_col, max_row, max_col)) day_max = calendar.monthrange(self.base_date.year, self.base_date.month)[1] s = "" for r in range(min_row, max_row + 1): d = [] for c in range(min_col, max_col + 1): ndx = self._table_model.item(r, c) if c == 0 or c > day_max: d.append(ndx.data(Qt.DisplayRole) or "") else: t = ndx.data(Qt.UserRole + 1) # Day off if t: t = ndx.data(Qt.DisplayRole) else: hours = ndx.data(Qt.UserRole) # Activity hours if hours is not None: t = str(hours).replace('.', ',') else: t = "" d.append(t) s += "\t".join(d) + u"\n" QApplication.clipboard().setText(s)
def showIndividualContextMenu(self, person): actionLookup = {} m = QMenu() actionLookup['Show Details'] = m.addAction('Show Details') # TODO: Add to / remove from path targets m.addSeparator() a = m.addMenu('Set A as') b = m.addMenu('Set B as') for label1 in AppState.ADDITION_ITERATOR_ORDER: a2 = a.addMenu(label1) b2 = b.addMenu(label1) for label2 in AppState.LEVEL_OPTION_ORDER: actionLookup[('Set A as', self.additionIterators[label1], AppState.LEVEL_OPTIONS[label2])] = a2.addAction(label2) actionLookup[('Set B as', self.additionIterators[label1], AppState.LEVEL_OPTIONS[label2])] = b2.addAction(label2) m.addSeparator() actionLookup['Trim Parents'] = m.addAction('Trim Parents') actionLookup['Trim Spouses'] = m.addAction('Trim Spouses') actionLookup['Trim Children'] = m.addAction('Trim Children') if not person in self.aSet and not person in self.bSet: actionLookup['Trim Parents'].setDisabled(True) actionLookup['Trim Spouses'].setDisabled(True) actionLookup['Trim Children'].setDisabled(True) m.addSeparator() for label1 in AppState.ADDITION_ITERATOR_ORDER: temp = m.addMenu('Expand '+label1) for label2 in AppState.LEVEL_OPTION_ORDER: actionLookup[('Expand', self.additionIterators[label1], AppState.LEVEL_OPTIONS[label2])] = temp.addAction(label2) choice = m.exec_(QCursor.pos()) if choice != None: for menus,action in actionLookup.iteritems(): if action == choice: if menus == 'Show Details': self.showIndividualDetails(person) elif menus == 'Trim Parents': self.snip(person, [self.ped.CHILD_TO_PARENT]) elif menus == 'Trim Spouses': self.snip(person, [self.ped.HUSBAND_TO_WIFE, self.ped.WIFE_TO_HUSBAND]) elif menus == 'Trim Children': self.snip(person, [self.ped.PARENT_TO_CHILD]) else: assert isinstance(menus,tuple) newSet = set(menus[1](person,level=menus[2])) if menus[0] == 'Set A as': historyID = self.addPedigree(newSet) self.changePedigreeA(historyID) elif menus[0] == 'Set B as': historyID = self.addPedigree(newSet) self.changePedigreeB(historyID) elif menus[0] == 'Expand': self.expand(person, newSet) break
class MTTSettingsMenu(QMenu): def __init__(self, parent=None): super(MTTSettingsMenu, self).__init__(parent) self.view = parent self.is_master_cmd = False # power user state self.power_user = MTTSettings.value('powerUser') self.__create_actions() self.__populate_menu() def keyPressEvent(self, event): if event.modifiers() == Qt.ControlModifier: self.is_master_cmd = True super(MTTSettingsMenu, self).keyPressEvent(event) def keyReleaseEvent(self, event): self.is_master_cmd = False super(MTTSettingsMenu, self).keyReleaseEvent(event) def __create_actions(self): def add_action(lbl, tip, cmd, checkable=False, checked=False): a = QAction(lbl, self) a.setStatusTip(tip) a.triggered.connect(cmd) if checkable: a.setCheckable(True) a.setChecked(checked) return a self.help_a = add_action('Help', 'Opens the online Help page', self.on_settings_help) self.switch_edit_a = add_action( 'Switch Edit/Source', 'Replace "Edit" button by "Source" button', self.on_switch_source_edit_menu, True, MTTSettings.value('switchEdit')) self.heads_up_a = add_action('HeadsUp Message', 'Show HeadsUp Message in viewport', self.on_toggle_headsup, True, MTTSettings.value('showHeadsUp')) self.focus_filter_a = add_action('Focus Filter Field at Startup', 'Focus filter field at startup', self.on_toggle_focus, True, MTTSettings.value('filterFocus')) self.force_relative_path_a = add_action( 'Force Relative Path', 'Set a relative path when selecting a new file', self.on_force_relative_path, True, MTTSettings.value('forceRelativePath')) self.show_real_attr_value_a = add_action( 'Show Real Attribute Value', 'Show fullpath instead of filtering path as Attribute Editor', self.on_show_real_attribute_value, True, MTTSettings.value('showRealAttributeValue')) self.manage_quick_filter_a = add_action( 'Manage Quick Filters', 'Manage filters that popup with right clic in filter field', self.on_filter_manage_quick_filter) self.clear_completion_cache_a = add_action( 'Clear Completion Cache', 'Erase auto completion cache of filter field', self.on_filter_clear_completion_cache) self.override_panels_a = add_action( 'Add CreateNode Button to Editors', ('Add "Create Node" to HyperShade and ' 'Node Editor for the current session'), self.on_override_panels) self.export_to_csv = add_action( 'Export Texture List as CSV', 'Export current textures into a csv file', self.view.model.export_as_csv) self.about = add_action('About', 'About', self.on_settings_about) def __populate_menu(self): self.addAction(self.help_a) self.addSeparator() self.addAction(self._get_menu_header('SETTINGS')) self.addAction(self.switch_edit_a) self.addAction(self.heads_up_a) self.addAction(self.focus_filter_a) self.addAction(self.force_relative_path_a) self.addAction(self.show_real_attr_value_a) self.addMenu(self._create_instance_menu()) self.addMenu(self._create_theme_menu()) self.addSeparator() self.addAction(self._get_menu_header('FILTER OPTIONS')) self.addAction(self.manage_quick_filter_a) self.addAction(self.clear_completion_cache_a) self.addSeparator() self.addAction(self._get_menu_header('MISC')) self.addAction(self.override_panels_a) self.addAction(self.export_to_csv) self.addSeparator() self.addAction(self._get_menu_header('DEBUG')) self.addMenu(self._create_debug_menu()) self.addSeparator() self.addAction(self.about) def _get_menu_header(self, title): header = QAction(title, self) header.setEnabled(False) return header def _create_instance_menu(self): self.instance_menu = QMenu(self) self.instance_menu.setTitle('Prompt Instance Delay') self.instance_menu.aboutToShow.connect( self.on_show_prompt_instance_delay_menu) return self.instance_menu def _create_theme_menu(self): theme_menu = QMenu(self) theme_menu.setTitle('Buttons Theme') theme_menu.setTearOffEnabled(True) theme_menu.setWindowTitle(TAG) theme_actions = QActionGroup(self) theme_actions.setExclusive(True) # create ordered theme list custom_order_theme = sorted(THEMES.iterkeys()) custom_order_theme.remove('Maya Theme') custom_order_theme.insert(0, 'Maya Theme') default_item = True for theme in custom_order_theme: current_theme_action = QAction(theme, theme_actions) current_theme_action.setCheckable(True) current_theme_action.setChecked( MTTSettings.value('theme', 'Maya Theme') == theme) current_theme_action.triggered.connect(self.on_change_theme) theme_menu.addAction(current_theme_action) if default_item: theme_menu.addSeparator() default_item = False return theme_menu def _create_debug_menu(self): self.debug_menu = QMenu(self) self.debug_menu.setTitle('Debug Menu') self.debug_menu.aboutToShow.connect(self.on_show_debug_menu) return self.debug_menu def on_change_theme(self): self.view.on_choose_theme(self.sender().text()) def on_show_debug_menu(self): self.debug_menu.clear() if self.is_master_cmd or self.power_user: power_user_mode = QAction('Power User Mode', self) power_user_mode.setCheckable(True) power_user_mode.setChecked(MTTSettings.value('powerUser')) power_user_mode.triggered.connect(self.__on_toggle_power_user) self.debug_menu.addAction(power_user_mode) self.is_master_cmd = False self.debug_menu.addSeparator() open_pref_folder_action = QAction('Open Preferences Folder', self) open_pref_folder_action.setStatusTip('Open MTT preference folder') open_pref_folder_action.triggered.connect( self.on_open_preference_folder) self.debug_menu.addAction(open_pref_folder_action) self.debug_menu.addSeparator() database_dump_csv = QAction('Dump Database as CSV', self) database_dump_csv.triggered.connect(self.view.model.database_dump_csv) self.debug_menu.addAction(database_dump_csv) database_dump_sql = QAction('Dump Database as SQL', self) database_dump_sql.triggered.connect(self.view.model.database_dump_sql) self.debug_menu.addAction(database_dump_sql) self.debug_menu.addSeparator() support_info = QMenu(self) support_info.setTitle('Supported Node Type') support_info.aboutToShow.connect(self.on_show_supported_type) self.debug_menu.addMenu(support_info) def on_filter_clear_completion_cache(self): """ Clear filter auto completion cache """ self.view.on_filter_set_text('') MTTSettings.remove('filterCompletionWildcard') MTTSettings.remove('filterCompletionRegExp') self.view.completion_model.setStringList([]) def on_switch_source_edit_menu(self): state = MTTSettings.value('switchEdit') MTTSettings.set_value('switchEdit', not state) self.view.on_set_source_edit_menu(not state) def on_show_real_attribute_value(self): self.view.model.layoutAboutToBeChanged.emit() show_real_attribute_state = MTTSettings.value('showRealAttributeValue') MTTSettings.set_value('showRealAttributeValue', not show_real_attribute_state) self.view._layout_changed() def on_filter_manage_quick_filter(self): """ Open Quick Filter words manager and save its content """ manager = MTTQuickFilterManager(self) if manager.exec_(): lists = manager.get_lists() # save list in settings MTTSettings.set_value('filterQuickWordsWildcard', ';;'.join(lists[0])) MTTSettings.set_value('filterQuickWordsRegExp', ';;'.join(lists[1])) # set current list self.view.quick_filter_words = lists[MTTSettings.value('filterRE')] manager.deleteLater() @staticmethod def on_toggle_headsup(): state = MTTSettings.value('showHeadsUp') MTTSettings.set_value('showHeadsUp', not state) @staticmethod def on_toggle_focus(): state = MTTSettings.value('filterFocus') MTTSettings.set_value('filterFocus', not state) @staticmethod def on_force_relative_path(): state = MTTSettings.value('forceRelativePath') MTTSettings.set_value('forceRelativePath', not state) def on_show_supported_type(self): node_types = sorted( [n_type for (n_type, nice, attr) in MTTSettings.SUPPORTED_TYPE] + MTTSettings.UNSUPPORTED_TYPE) support_info = self.sender() support_info.clear() for node_type in node_types: current = QAction(node_type, self) current.setEnabled(False) current.setCheckable(True) current.setChecked(node_type not in MTTSettings.UNSUPPORTED_TYPE) support_info.addAction(current) def __on_toggle_power_user(self): state = MTTSettings.value('powerUser') MTTSettings.set_value('powerUser', not state) self.power_user = not state @staticmethod def on_open_preference_folder(): """ Open preference folder """ folder_path = os.path.dirname(MTTSettings.filename()) cmds.launchImageEditor(viewImageFile=folder_path) @staticmethod def on_override_panels(): """ Override HyperShade and NodeEditor creation callback""" override_info_box = QMessageBox() override_info_box.setWindowTitle(WINDOW_TITLE) override_info_box.setIcon(QMessageBox.Information) override_info_box.setText( 'Buttons will be added to HyperShade toolbar and Node Editor toolbar.<br/>' 'Changes will exists during this session.') override_info_box.setInformativeText( '<i>Read Help to set this settings permanent</i>') override_info_box.setStandardButtons(QMessageBox.Ok) override_info_box.setDefaultButton(QMessageBox.Ok) override_info_box.exec_() mttOverridePanels.override_panels() def on_settings_about(self): special_list = map( lambda x: x.replace(' ', ' '), sorted([ u'Beno\xeet Stordeur', u'Fran\xe7ois Jumel', 'Jonathan Lorber', 'Norbert Cretinon', 'Gilles Hoff' ])) QMessageBox.about( self.parent(), WINDOW_TITLE, '<b>Maya Texture Toolkit v{:.02f}</b>' u'<p>{} - \xa9 2014 - 2016' '</p>' '<p>Special thanks to :<br/>' '<i>{}</i>' '</p>'.format(__version__, __author__, ', '.join(special_list))) @staticmethod def on_settings_help(): help_wiki = 'https://github.com/Bioeden/dbMayaTextureToolkit/wiki' webbrowser.open(help_wiki) def on_show_prompt_instance_delay_menu(self): prompt_instance_state = cmds.optionVar( query='MTT_prompt_instance_state') if prompt_instance_state == PROMPT_INSTANCE_WAIT: elapsed_time = time() - cmds.optionVar( query='MTT_prompt_instance_suspend') if elapsed_time > PROMPT_INSTANCE_WAIT_DURATION: prompt_instance_state = PROMPT_INSTANCE_ASK cmds.optionVar( iv=['MTT_prompt_instance_state', prompt_instance_state]) else: mtt_log('Remaining %.2fs' % (PROMPT_INSTANCE_WAIT_DURATION - elapsed_time)) elif prompt_instance_state == PROMPT_INSTANCE_SESSION: if 'mtt_prompt_session' not in __main__.__dict__: prompt_instance_state = PROMPT_INSTANCE_ASK cmds.optionVar( iv=['MTT_prompt_instance_state', prompt_instance_state]) self.instance_menu.clear() prompt_delay = QActionGroup(self) prompt_delay.setExclusive(True) for i in range(len(PROMPT_INSTANCE_STATE.keys())): current_delay_action = QAction(PROMPT_INSTANCE_STATE[i], prompt_delay) current_delay_action.setCheckable(True) current_delay_action.setChecked(prompt_instance_state == i) current_delay_action.triggered.connect( partial(self.view.on_choose_instance_delay, i, prompt=i != 0)) self.instance_menu.addAction(current_delay_action)