Esempio n. 1
0
    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)
Esempio n. 3
0
File: Menu.py Progetto: wiz21b/koi
    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))
Esempio n. 5
0
 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)
Esempio n. 6
0
 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)
Esempio n. 7
0
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))
Esempio n. 8
0
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
Esempio n. 9
0
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
Esempio n. 11
0
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()
Esempio n. 12
0
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(' ', '&nbsp;'), 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)
Esempio n. 14
0
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)
Esempio n. 15
0
 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(' ', '&nbsp;'),
            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)