Example #1
0
    def __showPyflakesContextMenu(self, pos):
        " Triggered when the icon context menu is requested "
        if self.__currentUUID is None:
            return
        if self.__currentUUID not in self.__flakesResults:
            return

        messages = self.__flakesResults[self.__currentUUID].messages
        if not messages:
            return

        # Check that there is at least one non -1 lineno message
        foundLinedMessage = False
        for item in messages:
            if item[1] != -1:
                foundLinedMessage = True
                break
        if not foundLinedMessage:
            return

        # OK, we have something to show
        contextMenu = QMenu(self.__uiLabel)
        for item in messages:
            act = contextMenu.addAction(
                PixmapCache().getIcon('pyflakesmsgmarker.png'),
                "Line " + str(item[1]) + ": " + item[0])
            act.setData(QVariant(item[1]))
        self.connect(contextMenu, SIGNAL("triggered(QAction*)"),
                     self.__onContextMenu)
        contextMenu.popup(self.__uiLabel.mapToGlobal(pos))
        return
 def contextMenuEvent(self, event):
     if event.reason() == event.Mouse:
         pos = event.globalPos()
         item = self.itemAt(event.pos())
     else:
         pos = None
         selection = self.selectedItems()
         if selection:
             item = selection[0]
         else:
             item = self.currentItem()
             if item is None:
                 item = self.invisibleRootItem().child(0)
         if item is not None:
             parent = item.parent()
             while parent is not None:
                 parent.setExpanded(True)
                 parent = parent.parent()
             itemrect = self.visualItemRect(item)
             portrect = self.viewport().rect()
             if not portrect.contains(itemrect.topLeft()):
                 self.scrollToItem(item, QTreeWidget.PositionAtCenter)
                 itemrect = self.visualItemRect(item)
             itemrect.setLeft(portrect.left())
             itemrect.setWidth(portrect.width())
             pos = self.mapToGlobal(itemrect.center())
     if pos is not None:
         menu = QMenu(self)
         menu.addAction(item.text(0))
         menu.popup(pos)
     event.accept()
Example #3
0
class centro(QGraphicsPixmapItem):
      def __init__(self, *args):
            QGraphicsPixmapItem.__init__(self, *args)
            self.setPixmap(QPixmap("sprites/calle/centro.png"))
            self.setTransformOriginPoint(self.boundingRect().width()/2.0,self.boundingRect().height()/2.0)
            self.setZValue(1)
            self.menu = QMenu()
            self.Actions =[] #arreglo de acciones 
            self.Actions.append( self.menu.addAction("girar clockwise") )
            self.Actions.append( self.menu.addAction("girar anti-clockwise") )
            self.Actions.append( self.menu.addAction("Duplicar") )
            self.Actions.append( self.menu.addAction("Eliminar") )
            self.menu.triggered[QAction].connect(self.test)
            self.offset=QPointF(0,0)
      def test(self,act):
            print act.text()
            if act.text()=="girar clockwise":
                  self.setRotation(self.rotation()-45)
            if act.text()=="girar anti-clockwise":
                  self.setRotation(self.rotation()+45)
            if act.text()=="Duplicar":
                  self.scene().addItem(centro())
            if act.text()=="Eliminar":
                  self.scene().removeItem(self)
      def contextMenuEvent(self,event):
            self.menu.popup(event.screenPos())
      def mousePressEvent(self, event):
            p = event.pos()
            self.offset= QPointF(p.x()*1.0,p.y()*1.0)
      def mouseMoveEvent(self, event):
            #print self.offset,event.scenePos()
            self.setPos(event.scenePos()-self.offset)
 def contextMenuEvent(self, event): 
     if event.reason() == event.Mouse: 
         pos = event.globalPos() 
         item = self.itemAt(event.pos()) 
     else: 
         pos = None 
         selection = self.selectedItems() 
         if selection: 
             item = selection[0] 
         else: 
             item = self.currentItem() 
             if item is None: 
                 item = self.invisibleRootItem().child(0) 
         if item is not None: 
             parent = item.parent() 
             while parent is not None: 
                 parent.setExpanded(True) 
                 parent = parent.parent() 
             itemrect = self.visualItemRect(item) 
             portrect = self.viewport().rect() 
             if not portrect.contains(itemrect.topLeft()): 
                 self.scrollToItem( 
                     item, QTreeWidget.PositionAtCenter) 
                 itemrect = self.visualItemRect(item) 
             itemrect.setLeft(portrect.left()) 
             itemrect.setWidth(portrect.width()) 
             pos = self.mapToGlobal(itemrect.center()) 
     if pos is not None: 
         menu = QMenu(self) 
         menu.addAction(item.text(0)) 
         menu.popup(pos) 
     event.accept() 
Example #5
0
 def onContextMenuEvent(self, event):
     """
     On context menu event
     """
     menu = QMenu(self)
     menu.addAction(self.copyAction)
     menu.popup(QCursor.pos())
Example #6
0
class BaseTabs(QTabWidget):
    def __init__(self, parent, actions=None, menu=None):
        QTabWidget.__init__(self, parent)
        if menu is None:
            self.menu = QMenu(self)
            if actions:
                add_actions(self.menu, actions)
        else:
            self.menu = menu
        
    def contextMenuEvent(self, event):
        """Override Qt method"""
        if self.menu:
            self.menu.popup(event.globalPos())
            
    def mousePressEvent(self, event):
        """Override Qt method"""
        if event.button() == Qt.MidButton:
            index = self.tabBar().tabAt(event.pos())
            if index >= 0:
                self.emit(SIGNAL("close_tab(int)"), index)
                event.accept()
                return
        QTabWidget.mousePressEvent(self, event)
        
    def keyPressEvent(self, event):
        """Override Qt method"""
        ctrl = event.modifiers() & Qt.ControlModifier
        key = event.key()
        handled = False
        if ctrl and self.count() > 0:
            index = self.currentIndex()
            if key == Qt.Key_PageUp and index > 0:
                self.setCurrentIndex(index-1)
                handled = True
            elif key == Qt.Key_PageDown and index < self.count()-1:
                self.setCurrentIndex(index+1)
                handled = True
        if handled:
            event.accept()
        else:
            QTabWidget.keyPressEvent(self, event)
        
    def set_close_function(self, func):
        """Setting Tabs close function
        None -> tabs are not closable"""
        state = func is not None
        if state:
            self.connect(self, SIGNAL("close_tab(int)"), func)
        try:
            # Assuming Qt >= 4.5
            QTabWidget.setTabsClosable(self, state)
            self.connect(self, SIGNAL("tabCloseRequested(int)"), func)
        except AttributeError:
            # Workaround for Qt < 4.5
            close_button = create_toolbutton(self, triggered=func,
                                             icon=get_icon("fileclose.png"),
                                             tip=translate("Tabs",
                                                           "Close current tab"))
            self.setCornerWidget(close_button if state else None)
Example #7
0
    def __showPyflakesContextMenu( self, pos ):
        " Triggered when the icon context menu is requested "
        if self.__currentUUID is None:
            return
        if self.__currentUUID not in self.__flakesResults:
            return

        messages = self.__flakesResults[ self.__currentUUID ].messages
        if not messages:
            return

        # Check that there is at least one non -1 lineno message
        foundLinedMessage = False
        for item in messages:
            if item[ 1 ] != -1:
                foundLinedMessage = True
                break
        if not foundLinedMessage:
            return

        # OK, we have something to show
        contextMenu = QMenu( self.__uiLabel )
        for item in messages:
            act = contextMenu.addAction(
                        PixmapCache().getIcon( 'pyflakesmsgmarker.png' ),
                        "Line " + str( item[ 1 ] ) + ": " + item[ 0 ] )
            act.setData( QVariant( item[ 1 ] ) )
        self.connect( contextMenu, SIGNAL( "triggered(QAction*)" ),
                      self.__onContextMenu )
        contextMenu.popup( self.__uiLabel.mapToGlobal( pos ) )
        return
 def _contextMenu(self, pos):
     # create actions
     delete_action = QAction("Delete", self)
     delete_action.triggered.connect(self._deleteSelectedInstance)
     # create context menu and add actions
     menu = QMenu(self.uiInstancesTableView)
     menu.addAction(delete_action)
     # show the menu
     menu.popup(self.uiInstancesTableView.viewport().mapToGlobal(pos))
Example #9
0
 def contextMenuEvent(self, event):
     menu = QMenu(self)
     add_actions( menu, (self.pageAction(QWebPage.Back),
                         self.pageAction(QWebPage.Forward), None,
                         self.pageAction(QWebPage.SelectAll),
                         self.pageAction(QWebPage.Copy), None,
                         self.zoom_in_action, self.zoom_out_action) )
     menu.popup(event.globalPos())
     event.accept()
Example #10
0
 def contextMenuEvent(self, event):
     menu = QMenu(self)
     add_actions(
         menu,
         (self.pageAction(QWebPage.Back), self.pageAction(
             QWebPage.Forward), None, self.pageAction(
                 QWebPage.SelectAll), self.pageAction(QWebPage.Copy), None,
          self.zoom_in_action, self.zoom_out_action))
     menu.popup(event.globalPos())
     event.accept()
Example #11
0
    def contextMenuEvent(self, event):
        if event.reason() == event.Mouse:
            pos = event.globalPos()
            item = self.ui.cloneList.itemAt(pos)

            if pos is not None:
                menu = QMenu(self)
                menu.addAction(item.text(0))
                menu.popup(Qcpos)

            event.accept()
Example #12
0
    def contextMenuEvent(self,event):
        if event.reason() == event.Mouse:
          pos = event.globalPos()
          item = self.ui.cloneList.itemAt(pos)

          if pos is not None:
                menu = QMenu(self)
                menu.addAction(item.text(0))
                menu.popup(Qcpos)

          event.accept()
Example #13
0
 def contextMenuEvent( self, event ):
     " Disables the default menu "
     testContent = self.page().mainFrame().hitTestContent( event.pos() )
     if testContent.linkUrl():
         menu = QMenu( self )
         menu.addAction( self.pageAction( QWebPage.CopyLinkToClipboard ) )
         menu.popup( self.mapToGlobal( event.pos() ) )
     elif self.page().selectedText() != "":
         menu = QMenu( self )
         menu.addAction( self.pageAction( QWebPage.Copy ) )
         menu.popup( self.mapToGlobal( event.pos() ) )
     return
Example #14
0
 def contextMenuEvent(self, event):
     " Disables the default menu "
     testContent = self.page().mainFrame().hitTestContent(event.pos())
     if testContent.linkUrl():
         menu = QMenu(self)
         menu.addAction(self.pageAction(QWebPage.CopyLinkToClipboard))
         menu.popup(self.mapToGlobal(event.pos()))
     elif self.page().selectedText() != "":
         menu = QMenu(self)
         menu.addAction(self.pageAction(QWebPage.Copy))
         menu.popup(self.mapToGlobal(event.pos()))
     return
Example #15
0
    def contextMenuEvent(self, event):
        """Constructs a `context menu`_ with a single action, *Save Pixmap*, that takes a screen shot of this widget, using :py:meth:`screenGrab <plexcore.QLabelWithSave.screenGrab>`.

        :param event: default :py:class:`QEvent <PyQt4.QtCore.QEvent>` argument needed to create a context menu. Is not used in this method.

        .. _context menu: https://en.wikipedia.org/wiki/Context_menu

        """
        menu = QMenu(self)
        savePixmapAction = QAction('Save Pixmap', menu)
        savePixmapAction.triggered.connect(self.screenGrab)
        menu.addAction(savePixmapAction)
        menu.popup(QCursor.pos())
Example #16
0
 def columnsVisibilityButtonClicked(self):
     items = self.model.column_menu_items()
     if not items:
         return
     menu = QMenu()
     for i, (display, marked) in enumerate(items):
         action = menu.addAction(display)
         action.setCheckable(True)
         action.setChecked(marked)
         action.setData(i)
         action.triggered.connect(self.columnsMenuItemWasClicked)
     self._columnMenuHolder = menu # we need to hold a reference to it while it popups
     button = self.columnsVisibilityButton
     menu.popup(button.parentWidget().mapToGlobal(button.geometry().topLeft()))
Example #17
0
    def _on_header_menu(self, point):
        menu = QMenu()
        for index, title in enumerate(self.model().header):
            action = QAction(self)
            action.setData(index)
            action.setText(title)
            action.setCheckable(True)
            action.setChecked(False if self.isColumnHidden(index) else True)
            action.triggered.connect(self._on_header_menu_action)

            menu.addAction(action)

        menu.popup(self.mapToGlobal(point))
        menu.exec_()
Example #18
0
 def showContextMenu(self, pos):
     menu = QMenu(self)
     action = menu.addAction('Copy Username')
     action.setShortcut(QKeySequence('CTRL-U'))
     action.triggered.connect(self.copyUsernameToClipboard)
     action = menu.addAction('Copy Password')
     action.setShortcut(QKeySequence('CTRL-C'))
     action.triggered.connect(self.copyPasswordToClipboard)
     menu.addSeparator()
     action = menu.addAction('Edit')
     action.triggered.connect(self.editPassword)
     action = menu.addAction('Delete')
     action.triggered.connect(self.deleteItem)
     menu.popup(self.mapToGlobal(pos))
Example #19
0
 def showContextMenu(self, pos):
     menu = QMenu(self)
     action = menu.addAction('Copy Username')
     action.setShortcut(QKeySequence('CTRL-U'))
     action.triggered.connect(self.copyUsernameToClipboard)
     action = menu.addAction('Copy Password')
     action.setShortcut(QKeySequence('CTRL-C'))
     action.triggered.connect(self.copyPasswordToClipboard)
     menu.addSeparator()
     action = menu.addAction('Edit')
     action.triggered.connect(self.editPassword)
     action = menu.addAction('Delete')
     action.triggered.connect(self.deleteItem)
     menu.popup(self.mapToGlobal(pos))
Example #20
0
    def contextMenuEvent(self, event):
        indexPos = self.indexAt(event.pos())
        menu = QMenu(self)
        if indexPos.model() is None:
            # On blank area.
            menu.addAction(self.win.ui.actionCreate)
        else:
            menu.addAction(self.win.ui.actionRun)
            menu.addSeparator()
            menu.addAction(self.win.ui.actionCreateDesktop)
            menu.addAction(self.win.ui.actionEdit)
            menu.addAction(self.win.ui.actionClearLocal)
            menu.addAction(self.win.ui.actionRemoveApp)

        menu.popup(event.globalPos())
Example #21
0
    def _iconOverlayEvent(self, event):
        popup = QMenu(self)
        layout = QVBoxLayout()
        layout.setContentsMargins(4, 4, 4, 4)
        popup.setLayout(layout)
        iconLabel = QLabel(popup)
        layout.addWidget(iconLabel)

        closeEvent = lambda event: popup.setParent(None)

        geometry = self.songIcon.geometry()
        songIcon = QPixmap(self.iconPath)
        iconLabel.setGeometry(geometry)
        iconLabel.setPixmap(songIcon)
        iconLabel.mousePressEvent = closeEvent
        popup.popup(event.globalPos() - event.pos())
Example #22
0
class OneColumnTree(QTreeWidget):
    def __init__(self, parent):
        QTreeWidget.__init__(self, parent)
        self.setItemsExpandable(True)
        self.setColumnCount(1)
        self.connect(self, SIGNAL('itemActivated(QTreeWidgetItem*,int)'),
                     self.activated)
        # Setup context menu
        self.menu = QMenu(self)
        self.common_actions = self.setup_common_actions()
                     
    def activated(self):
        raise NotImplementedError
                     
    def set_title(self, title):
        self.setHeaderLabels([title])
                     
    def setup_common_actions(self):
        """Setup context menu common actions"""
        collapse_act = create_action(self,
                    text=self.tr('Collapse all'),
                    icon=get_icon('collapse.png'),
                    triggered=self.collapseAll)
        expand_act = create_action(self,
                    text=self.tr('Expand all'),
                    icon=get_icon('expand.png'),
                    triggered=self.expandAll)
        return [collapse_act, expand_act]
                     
    def update_menu(self):
        self.menu.clear()
        actions = self.specific_actions()
        if actions:
            actions.append(None)
        actions += self.common_actions
        add_actions(self.menu, actions)
        
    def specific_actions(self):
        # Right here: add other actions if necessary
        # (reimplement this method)
        return []
                     
    def contextMenuEvent(self, event):
        """Override Qt method"""
        self.update_menu()
        self.menu.popup(event.globalPos())
Example #23
0
 def onclick(self,event):
     if event.inaxes and event.button==3:
         # populate menu
         menu = QMenu(self) 
         ac = QAction(menu)
         ac.setText(self.app.aw.popupadd)
         ac.key = ("add",event.xdata,event.ydata)
         menu.addAction(ac)
         if (self.lastMotionX and self.lastMotionY):
             ac = QAction(menu)
             ac.setText(self.app.aw.popupdelete)
             ac.key = ("delete",event.xdata,event.ydata)
             menu.addAction(ac)
         self.mousepress = False
         self.indexpoint = None
         # show menu
         menu.triggered.connect(self.event_popup_action)
         menu.popup(QCursor.pos())
Example #24
0
 def onclick(self, event):
     if event.inaxes and event.button == 3:
         # populate menu
         menu = QMenu(self)
         ac = QAction(menu)
         ac.setText(self.app.aw.popupadd)
         ac.key = ("add", event.xdata, event.ydata)
         menu.addAction(ac)
         if (self.lastMotionX and self.lastMotionY):
             ac = QAction(menu)
             ac.setText(self.app.aw.popupdelete)
             ac.key = ("delete", event.xdata, event.ydata)
             menu.addAction(ac)
         self.mousepress = False
         self.indexpoint = None
         # show menu
         menu.triggered.connect(self.event_popup_action)
         menu.popup(QCursor.pos())
Example #25
0
 def contextMenu(self, pos):
     item = self.itemAt(pos)
     if item is None:
         return
     menu = QMenu(self)
     if item.dev().isScsi():
         removeAction = MyAction(item.dev().remove, tr("umount all && remove"), menu)
         if self._ioThread.isRunning():
             QObject.connect(
                 removeAction,
                 SIGNAL("triggered(QString, PyQt_PyObject)"),
                 self._ioThread.actionHandler.doAction,
                 Qt.QueuedConnection,
             )
         menu.addAction(removeAction)
     if item.dev().inUse():
         umountAction = MyAction(item.dev().umount, tr("umount"), menu)
         if self._ioThread.isRunning():
             QObject.connect(
                 umountAction,
                 SIGNAL("triggered(QString, PyQt_PyObject)"),
                 self._ioThread.actionHandler.doAction,
                 Qt.QueuedConnection,
             )
         menu.addAction(umountAction)
     else:  # not in use
         mountAction = MyAction(item.dev().mount, tr("mount with truecrypt"), menu)
         if self._ioThread.isRunning():
             QObject.connect(
                 mountAction,
                 SIGNAL("triggered(QString, PyQt_PyObject)"),
                 self._ioThread.actionHandler.doAction,
                 Qt.QueuedConnection,
             )
         menu.addAction(mountAction)
     menu.addSeparator()
     refreshAction = QAction(tr("refresh all"), menu)
     QObject.connect(refreshAction, SIGNAL("triggered(bool)"), self.refreshAction)
     menu.addAction(refreshAction)
     # fix popup menu position
     pos = self.mapToGlobal(pos)
     pos.setY(pos.y() + self.header().sizeHint().height())
     menu.popup(pos)
    def __showTaskContextMenu(self, p):

        row = self.gui.ui.renderTaskTableWidget.itemAt(p).row()

        print "{}".format(row)

        idItem = self.gui.ui.renderTaskTableWidget.item(row, 0)

        taskId = "{}".format(idItem.text())

        ts = self.logic.getTask(taskId)

        print "{}".format(taskId)

        menu = QMenu()

        self.taskContextMenuCustomizer = TaskContextMenuCustomizer(
            menu, self.logic, ts)

        menu.popup(self.gui.ui.renderTaskTableWidget.viewport().mapToGlobal(p))
        menu.exec_()
Example #27
0
 def onInputUp(o, iev):
     if iev.isDrag:
         if iev.key in KEYS['select'] + KEYS['deselect']:
             frame = QRectF(o._drag_start, iev.lastScenePos).normalized()
             items = o.items(frame, Qt.ContainsItemBoundingRect,
                             Qt.AscendingOrder)
             # deselect on Shift+Select or Deselect key.
             select = True
             if iev.key in KEYS['deselect'] or (iev.modifiers
                                                & Qt.ShiftModifier):
                 select = False
             for item in items:
                 if not isinstance(item, ClusterWidget): continue
                 item.setSelected(select)
             o._drag_start = None
             o._rubberband.hide()
         if iev.key in KEYS['pan']:
             o.parent().togglePan(False)
     else:
         if iev.key in KEYS['select']:
             if not o.grab_active:
                 item = o.itemAt(iev.startScenePos)
                 if not item: return
                 widget = item.parentWidget()
                 widget.setSelected(not widget.isSelected())
         elif iev.key in KEYS['sel_clear']:
             o.clearSelection()
         elif iev.key in KEYS['grab']:
             o.toggle_grab_mode(iev.startScenePos)
         elif iev.key in KEYS['ctxmenu']:
             pos = iev.startScenePos
             piece_item = o.itemAt(iev.startScenePos)
             menu = QMenu()
             o.get_menu_items(menu, iev)
             if piece_item:
                 piece_item.get_menu_items(menu, o, iev)
             menu.popup(iev.startScreenPos)
             # store the variable, so it doesn't get GC'ed
             o.__menu = menu
Example #28
0
    def _on_row_menu(self, point):
        row = self.rowAt(point.y())
        task = self.get_task_by_row(row)

        if row < 0 or task is None:
            return

        menu = QMenu()

        load_action = QAction(self)
        load_action.setData(task.id)
        load_action.setText("Load parameters")
        load_action.triggered.connect(self._on_load_params_action)
        menu.addAction(load_action)

        delete_action = QAction(self)
        delete_action.setData(task.id)
        delete_action.setText('Delete')
        delete_action.triggered.connect(self._on_row_delete_action)
        menu.addAction(delete_action)

        menu.popup(self.mapToGlobal(point))
        menu.exec_()
Example #29
0
class AgentsTableView(QTableView, Logger.ClassLogger):
    """
    Agents table view
    """
    DataChanged = pyqtSignal() 
    def __init__(self, parent ):
        """
        Contructs ParametersTableView table view

        @param parent: 
        @type parent:
        """
        QTableView.__init__(self, parent)

        self.model = None
        self.__mime__ = "application/x-%s-test-config-agents" % Settings.instance().readValue( key='Common/acronym' ).lower()
        self.datasetView = False
        self.itemsPasted = []
        
        self.createWidgets()
        self.createConnections()
        self.createActions()

    def keyPressEvent(self, event):
        """
        Reimplemented from tableview
        """ 
        return QTableView.keyPressEvent(self, event)
    
    def startDrag(self, dropAction):
        """
        Start drag

        @param dropAction:
        @type dropAction:
        """
        indexes = self.selectedIndexes()
        if not indexes:
            return
        for index in indexes:
            if not index.isValid():
                return
        rowVal = self.model.getValueRow( indexes[0] )
        if len(rowVal) > 1 :
            if self.datasetView:
                meta = "__%s__" % rowVal['name']
            else:
                meta = "agent('%s')" % rowVal['name']
            # create mime data object
            mime = QMimeData()
            mime.setData('application/x-%s-agent-item' % Settings.instance().readValue( key='Common/acronym' ).lower() , meta )
            # start drag )
            drag = QDrag(self)
            drag.setMimeData(mime) 
            
            drag.exec_(Qt.CopyAction)

    def createWidgets (self):
        """
        QtWidgets creation
        """
        self.model = AgentsTableModel(self)
        self.setModel(self.model)

        self.setDragDropMode(QAbstractItemView.DragDrop)
        self.setDragEnabled(True)

        self.setFrameShape(QFrame.NoFrame)
        self.setShowGrid(True)
        self.setGridStyle (Qt.DotLine)

        self.setItemDelegateForColumn( COL_NAME, NameDelegate(self, COL_NAME) )
        # empty value is to indicate a separator
        self.setItemDelegateForColumn( COL_VALUE, ComboValueDelegate(self, COL_VALUE) )
        self.setItemDelegateForColumn( COL_DESCRIPTION, DescriptionsDelegate(self, COL_DESCRIPTION) )

        self.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setAlternatingRowColors(True)
        self.setStyleSheet("alternate-background-color: #FFFFBF;")
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.verticalHeader().setVisible(False)
        self.horizontalHeader().setHighlightSections(False)
        self.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)     
        self.horizontalHeader().setStretchLastSection(True)
        
        self.adjustRows()

        # adjust default columns
        self.setColumnWidth(COL_ID, 25)
        self.setColumnWidth(COL_NAME, 60)
        self.setColumnWidth(COL_VALUE, 50)
        self.setColumnWidth(COL_DESCRIPTION, 100)

    def createConnections (self):
        """
        Create qt connections
        """
        self.customContextMenuRequested.connect(self.onPopupMenu)
        self.clicked.connect(self.onAbstractItemClicked)
        QApplication.clipboard().dataChanged.connect(self.onClipboardUpdated) 
        
    def createActions (self):
        """
        Actions defined:
         * add 
         * del
         * copy
         * paste
         * clear
        """
        self.addAction = QtHelper.createAction(self, self.tr("&Add"), self.addAgent, 
                                        icon = QIcon(":/tc-add.png"), tip = 'Add a new agent' )
        self.delAction = QtHelper.createAction(self, self.tr("&Delete"), self.removeItem, 
                                        icon = QIcon(":/tc-del.png"), tip = 'Delete the selected agent' )
        self.copyAction = QtHelper.createAction(self, self.tr("Copy"), self.copyItem, 
                                        icon = QIcon(":/param-copy.png"),  tip = 'Copy the selected agent', shortcut='Ctrl+C' )
        self.pasteAction = QtHelper.createAction(self, self.tr("Paste"), self.pasteItem, 
                                        icon = QIcon(":/param-paste.png"), tip = 'Paste agent', shortcut='Ctrl+V')
        self.undoPasteAction = QtHelper.createAction(self, self.tr("Undo"), self.undoPasteItem, 
                                        icon = QIcon(":/test-parameter-undo.png"), tip = self.tr('Undo paste agent') )
        self.clearAction = QtHelper.createAction(self, self.tr("Clear"), self.clearItems, 
                                        icon = QIcon(":/param-delete.png"), tip = 'Clear all agents' )
        
        # then disable all
        self.defaultActions()

    def undoPasteItem(self):
        """
        Undo paste item
        """
        # flush the list and disable action
        self.itemsPasted = []
        self.undoPasteAction.setEnabled(False)
        
    def defaultActions(self):
        """
        Set default actions
        """
        self.addAction.setEnabled(True)
        self.delAction.setEnabled(False)
        self.copyAction.setEnabled(False)
        self.pasteAction.setEnabled(False)
        self.clearAction.setEnabled(True)
        self.undoPasteAction.setEnabled(False)

    def onAbstractItemClicked(self):
        """
        Called on abstract item clicked
        """
        self.delAction.setEnabled(True)
        self.copyAction.setEnabled(True)

    def onPopupMenu(self, pos):
        """
        Display menu on right click

        @param pos: 
        @type pos:
        """
        self.menu = QMenu(self)
        index = self.currentIndex()
        indexes = self.selectedIndexes()
        if not indexes:
            self.menu.addAction( self.addAction )
            self.menu.addSeparator()
            self.menu.addAction( self.pasteAction )
            self.menu.addAction( self.undoPasteAction )
            self.menu.addSeparator()
            self.menu.addAction( self.clearAction )
        else:
            self.menu.addAction( self.delAction )
            self.menu.addAction( self.addAction )
            self.menu.addSeparator()
            self.menu.addAction( self.copyAction )
            self.menu.addAction( self.pasteAction )
            self.menu.addAction( self.undoPasteAction )
            self.menu.addSeparator()
            self.menu.addAction( self.clearAction )
        self.menu.popup( self.mapToGlobal(pos) )

    def copyItem(self):
        """
        Copy the selected row to the clipboard
        """
        indexes = self.selectedIndexes()
        if not indexes:
            return
        # retrieve data from model      
        rowData = []
        for id in self.selectionModel().selectedRows():
            rowData.append(self.model.getData()[id.row()])

        # pickle data
        mimeData = QMimeData()
        if sys.version_info > (3,):
            mimeData.setData( self.__mime__, pickle.dumps(rowData))
        else:
            mimeData.setData( QString(self.__mime__) , pickle.dumps(rowData))
        # copy to clipboard
        QApplication.clipboard().setMimeData(mimeData)

    def pasteItem(self):
        """
        Paste item
        """
        self.itemsPasted = []
        
        mimeData = QApplication.clipboard().mimeData()
        if not mimeData.hasFormat(self.__mime__):
            return None
        data = mimeData.data(self.__mime__)
        if not data:
            return None
        try:
            objects = pickle.loads(data.data())
            for o in objects:
                self.insertItem( newData=o, insertFromPaste=True )
        except Exception as e:
            self.error( "unable to deserialize %s" % str(e) )
            return None
        
        self.undoPasteAction.setEnabled(True)
        
    def onClipboardUpdated(self):
        """
        Called on clipboard updated
        """
        c = QApplication.clipboard()
        if c.mimeData().hasFormat(self.__mime__):
            self.pasteAction.setEnabled(True)
        else:
            self.pasteAction.setEnabled(False)

    def addAgent(self):
        """
        Add agent
        """
        addDialog = AddAgentDialog(parent=self, datasetView=self.datasetView)
        if addDialog.exec_() == QDialog.Accepted:
            parameter = addDialog.getParameterValue()
            self.insertItem(newData=parameter)

    def insertItem(self, newData=False, insertFromPaste=False):
        """
        Insert item

        @param newData: 
        @type newData: boolean
        """
        index = self.currentIndex()
        if not index.isValid():
            row = self.model.rowCount()
        else:
            row = index.row()
        data = self.model.getData()
        
        #
        if newData:
            tpl = newData
        else:
            tpl =   {'name': 'AGENT', 'description': '', 'value': 'agent-dummy01', 'type': 'dummy'}
        
        # name must be unique
        for it in data:
            if it['name'] == tpl['name']:
                tpl['name'] += '_1'
        
        if insertFromPaste:
            self.itemsPasted.append( tpl['name'] )
            
        # add data to model
        data.insert(row + 1, tpl)
        data.sort(key=operator.itemgetter('name'))
        # self.model.reset()
        self.model.beginResetModel()
        self.model.endResetModel()
        self.setData()

        # select item #Enhancement 183
        for i in  xrange(len(data)):
            if data[i]['name'] == tpl['name']:
                self.selectRow(i)
                break
        
    def clearItems(self):
        """
        Clear items
        """
        reply = QMessageBox.question(self, "Clear all", "Are you sure ?",
                        QMessageBox.Yes | QMessageBox.No )
        if reply == QMessageBox.Yes:
            data = self.model.getData()
            try:
                for i in xrange(len(data)):
                    data.pop()
            except Exception as e:
                pass
            # self.model.reset()
            self.model.beginResetModel()
            self.model.endResetModel()
            self.setData()
            self.delAction.setEnabled(False)

    def clear (self):
        """
        Clear contents
        """
        self.model.setDataModel( [] )

    def removeItem (self):
        """
        Removes the selected row 
        """
        indexes = self.selectedIndexes()
        if not indexes:
            return
        for index in indexes:
            if not index.isValid():
                return
        answer = QMessageBox.question(self,  "Remove",  "Do you want to remove selected agent?", 
                QMessageBox.Yes | QMessageBox.No)
        if answer == QMessageBox.Yes:
            self.removeValues(indexes)

    def adjustColumns(self):
        """
        Resize two first columns to contents
        """
        for col in [COL_NAME, COL_VALUE, COL_TYPE, COL_DESCRIPTION]:
            self.resizeColumnToContents(col)
        self.setColumnWidth(COL_DESCRIPTION, 100)
    
    def adjustRows (self):
        """
        Resize row to contents
        """
        data = self.model.getData()
        for row in xrange(len(data)):
            self.resizeRowToContents(row)

    def loadData (self, data):
        """
        Load data

        @param data: 
        @type data:
        """
        params = data['agent']
        params.sort(key=operator.itemgetter('name'))
        self.model.setDataModel( params )
        self.setData( signal = False )

    def setData(self, signal = True):
        """
        Set table data

        @param signal: 
        @type signal: boolean
        """
        self.adjustColumns()
        self.adjustRows()
        if signal: self.DataChanged.emit()

    def removeValues(self, indexes):
        """
        Remove values from data

        @param indexes: 
        @type indexes:
        """
        indexes = self.selectedIndexes()
        if not indexes:
            return
        
        # extract name, name are unique
        datas = self.model.getData()
        allNames = []
        for i in xrange(0, len(indexes), len(HEADERS) ):
            allNames.append( datas[indexes[i].row()]['name'] )
        
        for paramName in allNames:
            self.removeValue( paramName=paramName )
        self.setData( signal = True )

    def removeValue(self, paramName):
        """
        Remove one parameter according to the name passed on argument
        """
        datas = self.model.getData()
        i = None
        for i in xrange(len(datas)):
            if datas[i]['name'] == paramName:
                break
        if i is not None:
            param = datas.pop( i )
            del param
        # self.model.reset()
        self.model.beginResetModel()
        self.model.endResetModel()
Example #30
0
class DictValueDialog(QtHelper.EnhancedQDialog, Logger.ClassLogger):
    """
    Dict dialog 
    """
    def __init__(self, parent, testParams, variables, advancedMode=False ):
        """
        Operator to fill parameter description

        @param dataArgs: 
        @type dataArgs: 

        @param parent: 
        @type parent:
        """
        super(DictValueDialog, self).__init__(parent)
        self.advancedMode = advancedMode
        self.testParams = testParams
        self.variables = variables

        self.createDialog()
        self.createConnections()
        self.createActions()
        
    def createDialog (self):
        """
        Create qt dialog
        """
        self.buttonBox = QDialogButtonBox(self)
        self.buttonBox.setStyleSheet( """QDialogButtonBox { 
            dialogbuttonbox-buttons-have-icons: 1;
            dialog-ok-icon: url(:/ok.png);
            dialog-cancel-icon: url(:/test-close-black.png);
        }""")
        self.buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)

        mainLayout = QVBoxLayout()
        
        self.dictTable = QTableView(self)
        self.model = DictTableModel(self, advancedMode=self.advancedMode)
        self.dictTable.setModel(self.model)
        self.dictTable.setFrameShape(QFrame.StyledPanel)
        self.dictTable.setShowGrid(True)
        self.dictTable.setGridStyle (Qt.DotLine)

        self.dictTable.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.dictTable.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.dictTable.setContextMenuPolicy(Qt.CustomContextMenu)
        self.dictTable.verticalHeader().setVisible(False)
        self.dictTable.horizontalHeader().setHighlightSections(False)
        self.dictTable.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
        self.dictTable.horizontalHeader().setStretchLastSection(True)
        self.dictTable.setColumnWidth(COL_KEY, 200)

        # delegate item on advanced mode
        if self.advancedMode:
            self.dictTable.setItemDelegateForColumn( COL_KEY, ItemComboDelegate(self, COL_KEY) )
            self.dictTable.setItemDelegateForColumn( COL_VALUE, ItemComboDelegate(self, COL_VALUE) )


        mainLayout.addWidget(self.dictTable)
        mainLayout.addWidget(self.buttonBox)
        self.setLayout(mainLayout)

        self.setWindowTitle(self.tr("Dict configuration"))

        self.setMinimumWidth(500)
        self.center()


    def getInputs(self):
        """
        Get test inputs 
        """
        return self.testParams.parameters.table().model.getData()

    def getOutputs(self):
        """
        Get test outputs 
        """
        return self.testParams.parametersOutput.table().model.getData()


    def createConnections (self):
        """
        Create qt connections
        """
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        self.dictTable.customContextMenuRequested.connect(self.onPopupMenu)
        
    def getValue(self):
        """
        Return value
        """
        return self.model.getData()

    def createActions (self):
        """
        Actions defined:
         * add 
         * del
        """
        self.addAction = QtHelper.createAction(self, self.tr("&Add"), self.addKey, icon = QIcon(":/test-parameter-add.png"),
                                tip = self.tr('Add a new key') )
        self.delAction = QtHelper.createAction(self, self.tr("&Delete"), self.delKey, icon = QIcon(":/test-parameter-del.png"), 
                                tip = self.tr('Delete the selected key') )
        self.delAllAction = QtHelper.createAction(self, self.tr("&Delete All"), self.delKeys, icon = QIcon(":/test-parameter-del.png"),
                                tip = self.tr('Delete the selected key') )
    
    
    def addKey(self):
        """
        Add key
        """
        self.delAllAction.setEnabled(True)
        
        index = self.dictTable.currentIndex()
        if not index.isValid():
            row = self.model.rowCount()
        else:
            row = index.row()

        data = self.model.getData()
        
        if self.advancedMode:
            tpl =   { 'key': { 'operator': '', 'value': '', 'type': '' }, 'value': { 'operator': '', 'value': '', 'type': '' } }
        else:
            tpl =   { 'key': 'my key', 'value': 'my value' }
                
        # add data to model
        data.insert(row + 1, tpl)
        self.model.reset()

    def clear (self):
        """
        clear contents
        """
        self.model.setDataModel( [] )
    
    def delKey(self):
        """
        Delete key
        """
        # get selected proxy indexes
        indexes = self.dictTable.selectedIndexes()
        if not indexes:
            return
         
        if indexes:
            answer = QMessageBox.question(self,  self.tr("Remove"),  self.tr("Do you want to remove selected key?"), 
                    QMessageBox.Yes | QMessageBox.No)
            if answer == QMessageBox.Yes:
                self.removeValues(indexes)

    def removeValues(self, indexes):
        """
        Remove values from data

        @param indexes: 
        @type indexes:
        """
        if not indexes:
            return
        
        # extract name, name are unique
        datas = self.model.getData()
        allNames = []

        # remove duplicate index
        cleanIndexes = {}
        for index in indexes:
            if index.row() not in cleanIndexes:
                cleanIndexes[index.row()] = index
                
        #for cleanIndex in cleanIndexes.keys():
        for cleanIndex in list(cleanIndexes.keys()): # for python3 support
            allNames.append( datas[cleanIndex]['key'] )

        self.trace('Key to remove: %s' % allNames)
        for paramName in allNames:
            self.removeValue( paramName=paramName )

    def removeValue(self, paramName):
        """
        Remove one parameter according to the name passed on argument
        """
        datas = self.model.getData()
        i = None
        for i in xrange(len(datas)):
            if datas[i]['key'] == paramName:
                break
        if i is not None:
            param = datas.pop( i )
            del param
        self.model.reset()
        
    def delKeys(self):
        """
        Clear all keys
        """
        reply = QMessageBox.question(self, 
                        self.tr("Clear all keys"), self.tr("Are you sure ?"),
                        QMessageBox.Yes | QMessageBox.No 
                )
        if reply == QMessageBox.Yes:
            data = self.model.getData()
            try:
                for i in xrange(len(data)):
                    data.pop()
            except Exception as e:
                pass
            self.model.reset()
            self.delAllAction.setEnabled(False)

            
    def onPopupMenu(self, pos):
        """
        Display menu on right click

        @param pos: 
        @type pos:
        """
        self.menu = QMenu(self.dictTable)
        index = self.dictTable.currentIndex()
        indexes = self.dictTable.selectedIndexes()
        if not indexes:
            self.menu.addAction( self.delAction )
            self.menu.addAction( self.addAction )
            self.menu.addSeparator()
            self.menu.addAction( self.delAllAction )
            self.menu.addSeparator()
        else:
            self.menu.addAction( self.delAction )
            self.menu.addAction( self.addAction )
            self.menu.addSeparator()
            self.menu.addAction( self.delAllAction )
            self.menu.addSeparator()

        self.menu.popup( self.mapToGlobal(pos) )

    def loadData(self, data):
        """
        Load data
        """
        if isinstance(data, dict):
            data = [data]
        self.model.setDataModel( data )
Example #31
0
class LogSParserMain(QMainWindow):
    """
    This is the main class in the application. It's responsible for displaying
    the log data in a tabular format as well as allowing the user to filter the
    logs displayed.
    """
    per_column_filter_out_set_list = list()
    per_column_filter_in_set_list = list()
    header = list()
    table_conditional_formatting_config = None
    def __init__(self):
        QMainWindow.__init__(self)
        
        self.graph_window_dict = {}
        self.menuFilter = None
        self.proxy_model = None
        self.table_data = None
        self.user_interface = Ui_Siraj()  
        self.user_interface.setupUi(self) 
        
        self.user_interface.mnuActionOpen.triggered.connect(self.menu_open_file)
        self.user_interface.mnuActionLoadConfigs.triggered.connect(self.menu_load_configs)
        self.user_interface.mnuActionExit.triggered.connect(self.menu_exit)
        self.user_interface.mnuActionAbout.triggered.connect(self.menu_about)
        self.user_interface.centralwidget.setLayout(self.user_interface.verticalLayout)
        self.user_interface.dckSourceContents.setLayout(self.user_interface.lytSource)
        self.user_interface.tblLogData.doubleClicked.connect(self.cell_double_clicked)
        self.user_interface.tblLogData.clicked.connect(self.cell_left_clicked)
        self.user_interface.tblLogData.keyPressEvent = self.cell_key_pressed
        self.user_interface.tblLogData.setContextMenuPolicy(Qt.CustomContextMenu)
        self.user_interface.tblLogData.customContextMenuRequested.connect(self.cell_right_clicked)
        self.user_interface.txtSourceFile.setReadOnly(True)

        self.is_table_visible = True
        self.is_source_visible = True
        
        self.user_interface.tblLogData.resizeColumnsToContents() 
        self.user_interface.tblLogData.resizeRowsToContents() 
        
        self.setup_context_menu()
        self.setup_toolbars()
        
        self.clipboard = QApplication.clipboard()
        self.is_filtering_mode_out = True
        
        self.matched_row_list = []
        self.search_criteria_updated = True
        
        self.case_sensitive_search_type = Qt.CaseInsensitive
        self.is_wrap_search = True  
        self.is_match_whole_word = False

        self.graph_marker_list = []

        self.user_interface.tblLogData.setAcceptDrops(False)
        self.setAcceptDrops(True)

        self.load_configuration_file()

        self.toggle_source_view()
        
    def setup_toolbars(self):
        source_toolbar = self.addToolBar('SourceToolbar')
        
        self.user_interface.tbrActionToggleSourceView = QAction('C/C++', self)
        self.user_interface.tbrActionToggleSourceView.triggered.connect(self.toggle_source_view)
        self.user_interface.tbrActionToggleSourceView.setToolTip("Toggle source code view")
        self.user_interface.tbrActionToggleSourceView.setCheckable(True)
        self.user_interface.tbrActionToggleSourceView.setChecked(True)
        
        source_toolbar.addAction(self.user_interface.tbrActionToggleSourceView)
        
        search_toolbar = self.addToolBar("SearchToolbar")
        search_toolbar.setAllowedAreas(Qt.TopToolBarArea | Qt.BottomToolBarArea)
        self.ledSearchBox = QLineEdit()
        self.ledSearchBox.textChanged.connect(self.invalidate_search_criteria)
        self.ledSearchBox.keyPressEvent = self.search_box_key_pressed

        search_toolbar.addWidget(self.ledSearchBox)
        
        tbrActionPrevSearchMatch = QAction('<<', self)                               
        tbrActionPrevSearchMatch.triggered.connect(functools.partial(self.select_search_match, False))
        tbrActionPrevSearchMatch.setToolTip("Go to previous search match")                  

        tbrActionNextSearchMatch = QAction('>>', self)                               
        tbrActionNextSearchMatch.triggered.connect(functools.partial(self.select_search_match, True))             
        tbrActionNextSearchMatch.setToolTip("Go to next search match")                  

        tbrActionIgnoreCase = QAction('Ignore Case', self)                               
        tbrActionIgnoreCase.setCheckable(True)
        tbrActionIgnoreCase.setChecked(True)
        tbrActionIgnoreCase.triggered.connect(self.set_search_case_sensitivity, tbrActionIgnoreCase.isChecked())            
        tbrActionIgnoreCase.setToolTip("Ignore case") 
        
        tbrActionWrapSearch = QAction('Wrap Search', self)                               
        tbrActionWrapSearch.setCheckable(True)
        tbrActionWrapSearch.setChecked(True)
        tbrActionWrapSearch.triggered.connect(self.set_search_wrap, tbrActionWrapSearch.isChecked())             
        tbrActionWrapSearch.setToolTip("Wrap Search") 
        
        tbrActionMatchWholeWord = QAction('Match Whole Word', self)                               
        tbrActionMatchWholeWord.setCheckable(True)
        tbrActionMatchWholeWord.setChecked(False)
        tbrActionMatchWholeWord.triggered.connect(self.set_match_whole_word, tbrActionMatchWholeWord.isChecked())             
        tbrActionMatchWholeWord.setToolTip("Match Whole Word") 
                                               
        search_toolbar.addAction(tbrActionPrevSearchMatch)
        search_toolbar.addAction(tbrActionNextSearchMatch)
        search_toolbar.addAction(tbrActionIgnoreCase)
        search_toolbar.addAction(tbrActionMatchWholeWord)
        search_toolbar.addAction(tbrActionWrapSearch)

    def set_search_case_sensitivity(self, ignore_case):
        self.invalidate_search_criteria()
        if(ignore_case):
            self.case_sensitive_search_type = Qt.CaseInsensitive
        else:
            self.case_sensitive_search_type = Qt.CaseSensitive

    def set_search_wrap(self, wrap_search):
        self.invalidate_search_criteria()
        self.is_wrap_search = wrap_search
        
    def set_match_whole_word(self, match_whole_word):
        self.invalidate_search_criteria()
        self.is_match_whole_word = match_whole_word
  
    def invalidate_search_criteria(self):
        self.search_criteria_updated = True;
        self.matched_row_list.clear()
        
    def get_matched_row_list(self, key_column, search_criteria, case_sensitivity):
        search_proxy = QSortFilterProxyModel()
        search_proxy.setSourceModel(self.user_interface.tblLogData.model())
        search_proxy.setFilterCaseSensitivity(case_sensitivity)
        search_proxy.setFilterKeyColumn(key_column)
        if self.is_match_whole_word:
            search_criteria = r"\b{}\b".format(search_criteria)
            
        search_proxy.setFilterRegExp(search_criteria)
        matched_row_list = []
        for proxy_row in range(search_proxy.rowCount()):
            match_index = search_proxy.mapToSource(search_proxy.index(proxy_row, key_column))
            matched_row_list.append(match_index.row())
        self.search_criteria_updated = False    
        return matched_row_list

    def select_search_match(self, is_forward):
        selected_indexes = self.get_selected_indexes()
        
        if(len(selected_indexes) == 0):
            self.display_message_box(
                "No selection", 
                "Please select a cell from the column you want to search", 
                QMessageBox.Warning)
        else:
            index = self.get_selected_indexes()[0]
            row = index.row()
            column = index.column()
            search_criteria = self.ledSearchBox.text()
            if(self.search_criteria_updated):
                self.matched_row_list = self.get_matched_row_list(column, search_criteria, self.case_sensitive_search_type)
            if(len(self.matched_row_list) > 0):    
                is_match_found = False
                if(is_forward):
                    matched_row_index = bisect_left(self.matched_row_list, row)
                    if((matched_row_index < len(self.matched_row_list) - 1)):
                        if(self.matched_row_list[matched_row_index] == row):
                            matched_row_index += 1
                        is_match_found = True
                    elif(self.is_wrap_search):
                        matched_row_index = 0
                        is_match_found = True
                else:
                    matched_row_index = bisect_right(self.matched_row_list, row)
                    if(matched_row_index > 0):
                        matched_row_index -= 1
                    if((matched_row_index > 0)):
                        if((self.matched_row_list[matched_row_index] == row)):
                            matched_row_index -= 1
                        is_match_found = True
                    elif(self.is_wrap_search):
                        matched_row_index = len(self.matched_row_list) - 1
                        is_match_found = True
                if(is_match_found):
                    self.select_cell_by_row_and_column(self.matched_row_list[matched_row_index], column)
            else:
                self.display_message_box(
                     "No match found", 
                     'Search pattern "{}" was not found in column "{}"'.format(search_criteria, self.header[column]), 
                     QMessageBox.Warning)

    def reset_per_config_file_data(self):
        self.graph_window_dict.clear()
        self.reset_per_log_file_data()
        self.table_data = None
        self.table_model = None
        self.proxy_model = None
        
    def load_configuration_file(self, config_file_path="siraj_configs.json"):
        self.reset_per_config_file_data()
        self.config = LogSParserConfigs(config_file_path)
        self.log_file_full_path = self.config.get_config_item("log_file_full_path")
        self.log_trace_regex_pattern = self.config.get_config_item("log_row_pattern")
        self.time_stamp_column = self.config.get_config_item("time_stamp_column_number_zero_based")
        self.user_data_column_zero_based = self.config.get_config_item("user_data_column_zero_based")

        self.external_editor_configs = self.config.get_config_item("external_editor_configs")
        
        cross_reference_configs = self.config.get_config_item("source_cross_reference_configs")
        
        self.file_column = cross_reference_configs["file_column_number_zero_based"]
        self.file_column_pattern = cross_reference_configs["file_column_pattern"]
        self.line_column = cross_reference_configs["line_column_number_zero_based"]
        self.line_column_pattern = cross_reference_configs["line_column_pattern"]
        
        self.graph_configs = self.config.get_config_item("graph_configs")

        self.root_source_path_prefix = cross_reference_configs["root_source_path_prefix"]
        self.syntax_highlighting_style = cross_reference_configs["pygments_syntax_highlighting_style"]
        
        self.table_conditional_formatting_config = self.config.get_config_item("table_conditional_formatting_configs")
        self.load_log_file(self.log_file_full_path)

    def load_graphs(self, graph_configs, table_data):

        pg.setConfigOption('background', QColor("white"))
        pg.setConfigOption('foreground', QColor("black"))
        pg.setConfigOptions(antialias=True)

        window_dict = graph_configs["window_dict"]
        series_list = []

        for window_name in window_dict:
            window_handle = pg.GraphicsWindow(title=window_name)
            self.graph_window_dict[window_name] = window_handle
            window_handle.show()
            plot_dict = window_dict[window_name]["plot_dict"]
            first_plot_name_in_the_window = ""
            for plot_name in plot_dict:
                plot_row = plot_dict[plot_name]["row"]
                # plot_column = plot_dict[plot_name]["column"]
                # plot_row_span = plot_dict[plot_name]["row_span"]
                # plot_column_span = plot_dict[plot_name]["column_span"]

                plot_handle = window_handle.addPlot(
                    name=plot_name,
                    title=plot_name,
                    row=plot_row,
                    col=1,#plot_column,
                    rowspan=1,#plot_row_span,
                    colspan=1)#plot_column_span)

                plot_handle.addLegend()

                if first_plot_name_in_the_window == "":
                    first_plot_name_in_the_window = plot_name
                plot_handle.setXLink(first_plot_name_in_the_window)

                marker = pg.InfiniteLine(angle=90, movable=False, pen=pg.mkPen(width=1, color=QColor("red")))
                plot_handle.addItem(marker, ignoreBounds=True)
                self.graph_marker_list.append(marker)
                plot_handle.scene().sigMouseClicked.connect(functools.partial(self.graph_mouse_clicked, plot_handle))
                plot_handle.scene().setClickRadius(50)

                series_dict = plot_dict[plot_name]["series_dict"]
                for series_name in series_dict:
                    series_symbol = series_dict[series_name]["symbol"]
                    series_color = series_dict[series_name]["color"]
                    series_pattern = series_dict[series_name]["pattern"]
                    series_list.append((series_name, series_symbol, series_color, series_pattern, [], [], plot_handle))

        for row_number, row_data in enumerate(table_data):
            for (series_name, series_symbol, series_color, series_pattern, x_point_list, y_point_list, plot_handle) in series_list:
                cell_to_match = row_data[self.user_data_column_zero_based]
                m = re.search(series_pattern, cell_to_match)
                if m is not None:
                    x_point_list.append(row_number)
                    y_point_list.append(int(m.group(1)))

        for (series_name, series_symbol, series_color, series_pattern, x_point_list, y_point_list, plot_handle) in series_list:
            plot_handle.plot(
                x_point_list,
                y_point_list,
                pen=pg.mkPen(width=1, color=QColor(series_color)),
                symbol=series_symbol,
                symbolPen='w',
                symbolBrush=QColor(series_color), name=series_name)

    # graphs = list(sorted(graph_configs.keys(), key=lambda k: graph_configs[k]["index"]))
        # graph_data = [([], [],) for _ in graphs]
        #
        # self.graph_marker_list = []
        #
        # for row_number, row_data in enumerate(table_data):
        #     for graph_number, graph_name in enumerate(graphs):
        #         cell_to_match = row_data[graph_configs[graph_name]["column"]]
        #         m = re.search(graph_configs[graph_name]["pattern"], cell_to_match)
        #         if (m is not None):
        #             graph_data[graph_number][0].append(row_number)  # X-Axis value
        #             graph_data[graph_number][1].append(int(m.group(1)))  # Y-Axis value
        #
        # for graph in graphs:
        #     window = None
        #     wnd = graph_configs[graph]["window"]
        #     if (wnd in self.graph_window_dict):
        #         window = self.graph_window_dict[wnd]
        #         window.clear()
        #
        # is_new_window = False
        # first_plot_name = None
        # for graph_number, graph in enumerate(graphs):
        #     window = None
        #     wnd = graph_configs[graph]["window"]
        #     if (wnd in self.graph_window_dict):
        #         window = self.graph_window_dict[wnd]
        #         is_new_window = False
        #     else:
        #         is_new_window = True
        #         window = pg.GraphicsWindow(title=wnd)
        #
        #         self.graph_window_dict[wnd] = window
        #
        #     p = window.addPlot(name=graph, title=graph)
        #
        #     p.plot(graph_data[graph_number][0],
        #            graph_data[graph_number][1],
        #            pen=pg.mkPen(width=1, color=QColor(graph_configs[graph]["color"])),
        #            symbol=graph_configs[graph]["symbol"], symbolPen='w',
        #            symbolBrush=QColor(graph_configs[graph]["color"]), name=graph)
        #     p.showGrid(x=True, y=True)
        #     if first_plot_name == None:
        #         first_plot_name = graph
        #     p.setXLink(first_plot_name)
        #     marker = pg.InfiniteLine(angle=90, movable=False)
        #     p.addItem(marker, ignoreBounds=True)
        #     self.graph_marker_list.append(marker)
        #     p.scene().sigMouseClicked.connect(functools.partial(self.graph_mouse_clicked, p))
        #
        #     window.nextRow()

    def graph_mouse_clicked(self, plt, evt):
        point = plt.vb.mapSceneToView(evt.scenePos())
        self.select_cell_by_row_and_column(int(round(point.x())), self.user_data_column_zero_based)
        self.update_graph_markers()

    def setup_context_menu(self):
        self.menuFilter = QMenu(self)
        
        self.hide_action                 = QAction('Hide selected values', self)
        self.show_only_action            = QAction('Show only selected values', self)
        self.clear_all_filters_action    = QAction('Clear all filters', self)
        self.copy_selection_action       = QAction('Copy selection', self)
       
        self.unhide_menu = QMenu('Unhide item from selected column', self.menuFilter)

        self.hide_action.triggered.connect(self.hide_rows_based_on_selected_cells)
        self.show_only_action.triggered.connect(self.show_rows_based_on_selected_cells)
        self.clear_all_filters_action.triggered.connect(self.clear_all_filters)
        self.copy_selection_action.triggered.connect(self.prepare_clipboard_text)
        
        self.menuFilter.addAction(self.hide_action)
        self.menuFilter.addMenu(self.unhide_menu)
        self.menuFilter.addAction(self.show_only_action)
        self.menuFilter.addAction(self.clear_all_filters_action)
        self.menuFilter.addSeparator()
        self.menuFilter.addAction(self.copy_selection_action)

        self.hide_action.setShortcut('Ctrl+H')
        self.show_only_action.setShortcut('Ctrl+O')
        self.clear_all_filters_action.setShortcut('Ctrl+Del')
        self.copy_selection_action.setShortcut("Ctrl+C")
        
    def toggle_source_view(self):
        self.is_source_visible = not self.is_source_visible
        self.user_interface.tbrActionToggleSourceView.setChecked(self.is_source_visible)

        self.user_interface.dckSource.setVisible(self.is_source_visible)
        logging.info("Source view is now {}".format("Visible" if self.is_source_visible else "Invisible"))

    def display_message_box(self, title, message, icon):
        """
        Show the about box.
        """   
        message_box = QMessageBox(self);
        message_box.setWindowTitle(title);
        message_box.setTextFormat(Qt.RichText);   
        message_box.setText(message)
        message_box.setIcon(icon)
        message_box.exec_()
                
    def menu_about(self):
        """
        Show the about box.
        """

        about_text = """
        
Copyright 2015 Mohamed Galal El-Din Ebrahim (<a href="mailto:[email protected]">[email protected]</a>)
<br>
<br>
siraj is free software: you can redistribute it and/or modify it under the 
terms of the GNU General Public License as published by the Free Software 
Foundation, either version 3 of the License.
<br>
<br>
siraj is distributed in the hope that it will be useful, but WITHOUT ANY 
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
PARTICULAR PURPOSE.  See the GNU General Public License for more details.
<br>
<br>
You should have received a copy of the GNU General Public License along with 
siraj.  If not, see 
<a href="http://www.gnu.org/licenses">http://www.gnu.org/licenses</a>.
        
"""        
        self.display_message_box("About", about_text, QMessageBox.Information)
    
    def menu_exit(self):
        """
        Handles the exit menu clicked event.
        """
        exit(0)
        
    def menu_open_file(self):
        """
        Handles the open menu clicked event.
        """
        self.log_file_full_path = QFileDialog.getOpenFileName(
            self,
            'Open Log File',
            os.getcwd())
        if(self.log_file_full_path != ''):
            self.load_log_file(self.log_file_full_path)
        
    def menu_load_configs(self):
        """
        Loads a new configuration file.
        """
        self.config_file_full_path = QFileDialog.getOpenFileName(
            self,
            'Open Config File',
            os.getcwd())
        if(self.config_file_full_path != ''):
            self.load_configuration_file(self.config_file_full_path)
            
        
    def reset_per_log_file_data(self):
        self.invalidate_search_criteria()
        
    def load_log_file(self, log_file_full_path):
        """
        Loads the given log file into the table.
        """
        self.reset_per_log_file_data()
        if (log_file_full_path == ""):
            pass
        elif (os.path.isfile(log_file_full_path)):
            with open(log_file_full_path, "r") as log_file_handle:
                log_file_content_lines = log_file_handle.read().splitlines()
            
            pattern = re.compile(self.log_trace_regex_pattern)        
            
            self.table_data = []
            most_recent_valid_table_entry = []
            for line in log_file_content_lines:
                m = pattern.match(line)
                if(m is not None):
                    most_recent_valid_table_entry = [group.strip() for group in m.groups()]
                    self.table_data.append(list(most_recent_valid_table_entry))
                else:
                    if(self.user_data_column_zero_based != -1):
                        temp_list = list(most_recent_valid_table_entry)
                        temp_list[self.user_data_column_zero_based] = line
                        self.table_data.append(temp_list)                    
            
            m = re.search(self.log_trace_regex_pattern, log_file_content_lines[1])
            self.header = [group_name for group_name in sorted(m.groupdict().keys(), key=lambda k: m.start(k))]
            self.table_model = MyTableModel(self.table_data, self.header, self.table_conditional_formatting_config, self)
            logging.info("Headers: %s", self.header)
            logging.info("%s has %d lines", self.log_file_full_path, len(self.table_data))
            self.proxy_model = MySortFilterProxyModel(self)
            self.proxy_model.setSourceModel(self.table_model)
            self.user_interface.tblLogData.setModel(self.proxy_model)
            if(len(self.per_column_filter_out_set_list) == 0):
                self.per_column_filter_out_set_list = [set() for column in range(len(self.table_data[0]))]
            if(len(self.per_column_filter_in_set_list) == 0):
                self.per_column_filter_in_set_list = [set() for column in range(len(self.table_data[0]))]
            
            self.extract_column_dictionaries(self.header, self.table_data)
            self.load_graphs(self.graph_configs, self.table_data) 
            self.setWindowTitle("Siraj | {}".format(log_file_full_path))
            self.select_cell_by_row_and_column(0, self.user_data_column_zero_based)
        else:
            self.display_message_box(
                "File not Found!", 
                "File <b>`{}`</b> was not found. You can either: <br><br>1. Open a log file via the File menu. Or<br>2. Drag a log file from the system and drop it into the application".format(log_file_full_path), 
                QMessageBox.Critical)

            
    def extract_column_dictionaries(self, header_vector_list, data_matrix_list):
        """
        This function extracts a dictionary of dictionaries
        
        The extracted is a dictionary of columns where key is the column name, 
        and the data is another dictionary.
        
        The inner dictionary has a key equal to a specific cell value of the 
        current column, and the value is a list of row number where this value
        appeared in.
        
        This will be used to provide quick navigation through the log.        
        """
        column_count = len(header_vector_list)
        self.columns_dict = {}
        for column, column_name in enumerate(header_vector_list):
            self.columns_dict[column] = {}
            
        for row, log in enumerate(data_matrix_list):
            for column, field in enumerate(log):
                if(log[column] not in self.columns_dict[column]):
                    self.columns_dict[column][log[column]] = []
                self.columns_dict[column][log[column]].append(row)
    
    def cell_left_clicked(self, index):
        """
        Handles the event of clicking on a table cell.
        
        If the clicked column was the the column that contain the source file:line
        information from the log, the function also populate the the EditView
        with the source file contents with a marker highlighting the line.
        
        This is only done if the source view is visible.
        """
        index = self.proxy_model.mapToSource(index)

        if(self.is_source_visible):
            logging.info("cell[%d][%d] = %s", index.row(), index.column(), index.data())
            row = index.row()
            
            file_matcher = re.search(self.file_column_pattern, self.table_data[row][self.file_column])
            line_matcher = re.search(self.line_column_pattern, self.table_data[row][self.line_column])
            
            if((file_matcher is not None) and (line_matcher is not None)):
                file = file_matcher.group(1)
                line = line_matcher.group(1)
                full_path = "{}{}".format(self.root_source_path_prefix, file.strip())
                self.load_source_file(full_path, line)
                self.user_interface.tblLogData.setFocus() 
        self.update_status_bar()
        self.update_graph_markers()


    def load_source_file(self, file, line):    
        code = open(file).read()
        lexer = get_lexer_for_filename(file)
        formatter = HtmlFormatter(
                                  linenos = True,
                                  full = True,
                                  style = self.syntax_highlighting_style,
                                  hl_lines = [line])
        result = highlight(code, lexer, formatter)
        self.user_interface.txtSourceFile.setHtml(result)
        
        text_block = self.user_interface.txtSourceFile.document().findBlockByLineNumber(int(line))      
        text_cursor = self.user_interface.txtSourceFile.textCursor()
        text_cursor.setPosition(text_block.position())        
        self.user_interface.txtSourceFile.setTextCursor(text_cursor)
        self.user_interface.txtSourceFile.ensureCursorVisible()

    def get_selected_indexes(self):
        """
        Returns a list of the currently selected indexes mapped to the source numbering.
        
        mapToSource is needed to retrive the actual row number regardless of whether filtering is applied or not.
        """
        return [self.proxy_model.mapToSource(index) for index in self.user_interface.tblLogData.selectedIndexes()]
                    
    def update_status_bar(self):
        """
        Updates the status bar with relevant information
        """
        selected_indexes = self.get_selected_indexes()
        
        if(len(selected_indexes) == 1):
            selected_cell_index = selected_indexes[0]
            number_of_occurances = len(self.columns_dict[selected_cell_index.column()][selected_cell_index.data()])
            self.user_interface.statusbar.showMessage(
                '["{}"] occurred {} time(s) ~ {}%'.format(
                selected_cell_index.data(), 
                number_of_occurances,
                number_of_occurances * 100 // len(self.table_data)))
        elif(len(selected_indexes) == 2):
            row_1 = selected_indexes[0].row()
            row_2 = selected_indexes[1].row()
            time_stamp1 = float(self.table_data[row_1][self.time_stamp_column])
            time_stamp2 = float(self.table_data[row_2][self.time_stamp_column])
            self.user_interface.statusbar.showMessage("Time difference = {}".format(abs(time_stamp2 - time_stamp1)))
        else:
            self.user_interface.statusbar.showMessage("")

    def cell_right_clicked(self, point):
        """
        Handle the event of right-clicking on a table cell.

        This function is responsible for showing the context menu for the user
        to choose from.
        """
        index = self.proxy_model.mapToSource(
            self.user_interface.tblLogData.indexAt(point))
        logging.debug("Cell[%d, %d] was right-clicked. Contents = %s", index.row(), index.column(), index.data())

        self.right_clicked_cell_index = index
        self.populate_unhide_context_menu(index.column())

        self.prepare_clipboard_text()
        
        self.menuFilter.popup(QCursor.pos())
        
    def populate_unhide_context_menu(self, column):    
        self.unhide_menu.clear()
        if(self.is_filtering_mode_out):
            filtered_out_set = self.per_column_filter_out_set_list[column]
        else:
            filtered_out_set = set(self.columns_dict[column].keys()) - self.per_column_filter_in_set_list[column]
        
        if(len(filtered_out_set) > 0):
            self.unhide_menu.setEnabled(True)
            for filtered_string in filtered_out_set:
                temp_action = QAction(filtered_string, self.unhide_menu)
                temp_action.triggered.connect(functools.partial(self.unhide_selected_rows_only_based_on_column, self.right_clicked_cell_index.column(), filtered_string))
                self.unhide_menu.addAction(temp_action)
        else:
            self.unhide_menu.setEnabled(False)
            

    def cell_double_clicked(self, index):
        """
        Handles the event of double-clicking on a table cell.
        
        If the double clicked cell was at the column of file:line, the function
        triggers external text editor (currently this is gedit on Linux) and make 
        it point on the corresponding line.
        """
        
        index = self.proxy_model.mapToSource(index)

        logging.info("cell[%d][%d] = %s", index.row(), index.column(), index.data())
        row = index.row()
        
        file_matcher = re.search(self.file_column_pattern, self.table_data[row][self.file_column])
        line_matcher = re.search(self.line_column_pattern, self.table_data[row][self.line_column])
        
        if((file_matcher is not None) and (line_matcher is not None)):
            file = file_matcher.group(1)
            line = line_matcher.group(1)
            full_path = "{}{}".format(self.root_source_path_prefix, file.strip())
            logging.info("Using external editor (gedit) to open %s at line %s", file, line)
            
            editor = self.external_editor_configs["editor"]
            editor_command_format = self.external_editor_configs["editor_command_format"]
            
            editor_command = editor_command_format.format(
                editor_executable=editor,
                line_number=line,
                file_name=full_path)
            
            call(editor_command,
                shell=True)
            self.user_interface.tblLogData.setFocus() 
        self.update_status_bar()

    def search_box_key_pressed(self, q_key_event):
        key = q_key_event.key()
        if (key in [Qt.Key_Enter, Qt.Key_Return]):
            if(Qt.ShiftModifier == (int(q_key_event.modifiers()) & (Qt.ShiftModifier))):
                self.select_search_match(False)
            else:
                self.select_search_match(True)
        else:
            QLineEdit.keyPressEvent(self.ledSearchBox, q_key_event)
                                        

    def cell_key_pressed(self, q_key_event):
        """
        Handles the event of pressing a keyboard key while on the table.
        """
        logging.warning("A key was pressed!!!")
        key = q_key_event.key()
        logging.info("Key = {}".format(key))

        if(Qt.ControlModifier == (int(q_key_event.modifiers()) & (Qt.ControlModifier))):
            if key == Qt.Key_Delete:
                logging.info("Delete key pressed while in the table. Clear all filters")
                self.clear_all_filters()
            elif key == Qt.Key_H:
                self.hide_rows_based_on_selected_cells()
            elif key == Qt.Key_O:
                self.show_rows_based_on_selected_cells()
            elif key == Qt.Key_Up: # Jump to previous match
                selected_indexes = self.get_selected_indexes()
                if(len(selected_indexes) == 1):
                    self.go_to_prev_match(selected_indexes[0])
            elif key == Qt.Key_Down: # Jump to next match
                selected_indexes = self.get_selected_indexes()
                if(len(selected_indexes) == 1):
                    self.go_to_next_match(selected_indexes[0])           
            elif key == Qt.Key_PageUp:
                selected_indexes = self.get_selected_indexes()
                if(len(selected_indexes) == 1):
                    prev_bookmark_index = self.table_model.getPrevBookmarkIndex(selected_indexes[0])
                    if(prev_bookmark_index is not None):
                        self.select_cell_by_index(prev_bookmark_index)
            elif key == Qt.Key_PageDown:
                selected_indexes = self.get_selected_indexes()
                if(len(selected_indexes) == 1):
                    next_bookmark_index = self.table_model.getNextBookmarkIndex(selected_indexes[0])
                    if(next_bookmark_index is not None):
                        self.select_cell_by_index(next_bookmark_index)
            elif key == Qt.Key_C:
                selected_indexes = self.get_selected_indexes()
                self.prepare_clipboard_text()
            elif key == Qt.Key_B:
                if(Qt.ShiftModifier == (int(q_key_event.modifiers()) & (Qt.ShiftModifier))):
                    self.table_model.clearAllBookmarks()
                else:
                    selected_indexes = self.get_selected_indexes()
                    self.table_model.toggleBookmarks(selected_indexes)
            elif key == Qt.Key_Left:
                self.select_search_match(is_forward=False)
            elif key == Qt.Key_Right:
                self.select_search_match(is_forward=True)
            elif key == Qt.Key_Home:
                self.select_cell_by_row_and_column(0, 0);
            elif key == Qt.Key_End:
                self.select_cell_by_row_and_column(self.table_model.rowCount(None) - 1, 0);               
        elif key == Qt.Key_F5:
            self.load_log_file(self.log_file_full_path)
        
        else:
            QTableView.keyPressEvent(self.user_interface.tblLogData, q_key_event)
        self.update_graph_markers()

    def update_graph_markers(self):
        selected_indexes = self.get_selected_indexes()
        if (len(selected_indexes) == 1):
            for marker in self.graph_marker_list:
                marker.setPos(selected_indexes[0].row())

    def prepare_clipboard_text(self):
        """
        Copy the cell content to the clipboard if a single cell is selected. Or
        Copy the whole rows if cells from multiple rows are selected.
        """
        selected_indexes = self.get_selected_indexes()
        if(len(selected_indexes) == 0):
            clipboard_text = ""
        elif(len(selected_indexes) == 1):
            clipboard_text = self.user_interface.tblLogData.currentIndex().data()
        else:
            unique_rows_set = set([index.row() for index in sorted(selected_indexes)])
            row_text_list = [str(row) + "," + ",".join([self.proxy_model.index(row, column, QModelIndex()).data() for column in range(self.proxy_model.columnCount())]) for row in sorted(unique_rows_set)]
            clipboard_text = "\n".join(row_text_list)
        self.clipboard.setText(clipboard_text)

    
    def get_index_by_row_and_column(self, row, column):
        """
        Get the table index value by the given row and column
        """
        index = self.table_model.createIndex(row, column)
        index = self.proxy_model.mapFromSource(index)
        return index
           
    def select_cell_by_row_and_column(self, row, column):
        """
        Select the cell identified by the given row and column and scroll the 
        table view to make that cell in the middle of the visible part of the
        table.
        """
        self.user_interface.tblLogData.clearSelection()
        index = self.get_index_by_row_and_column(row, column)
        self.user_interface.tblLogData.setCurrentIndex(index)  
        self.user_interface.tblLogData.scrollTo(index, hint = QAbstractItemView.PositionAtCenter)
        self.user_interface.tblLogData.setFocus()
        self.update_status_bar()
        
    def select_cell_by_index(self, index):        
        """
        Select a cell at the given index.
        """
        self.user_interface.tblLogData.clearSelection()
        index = self.proxy_model.mapFromSource(index)
        self.user_interface.tblLogData.setCurrentIndex(index)  
        self.user_interface.tblLogData.scrollTo(index, hint = QAbstractItemView.PositionAtCenter)
        self.user_interface.tblLogData.setFocus()
        self.update_status_bar()
        
    def go_to_prev_match(self, selected_cell):
        """
        Go to the prev cell that matches the currently selected cell in the 
        same column
        """
        matches_list = self.columns_dict[selected_cell.column()][selected_cell.data()]
        index = matches_list.index(selected_cell.row())
        if(index > 0):
            new_row = matches_list[index - 1]
            self.select_cell_by_row_and_column(new_row, selected_cell.column())
            
    def go_to_next_match(self, selected_cell):
        """
        Go to the prev cell that matches the currently selected cell in the 
        same column
        """
        matches_list = self.columns_dict[selected_cell.column()][selected_cell.data()]
        index = matches_list.index(selected_cell.row())
        if(index < (len(matches_list) - 1)):
            new_row = matches_list[index + 1]
            self.select_cell_by_row_and_column(new_row, selected_cell.column())
    
    
    def get_top_left_selected_row_index(self):
        """
        This function return the top-left selected index from the selected list.
        It's used for example to anchor the table view around the top-left 
        selected cell following any change in the visible cells due to filtering
        """
        top_left_index = None
        
        selected_indexes = self.get_selected_indexes()
        if(len(selected_indexes) > 0):
            selected_indexes = self.get_selected_indexes()
            
            top_left_index  = selected_indexes[0]
            row             = top_left_index.row()
            column          = top_left_index.column()
            for index in selected_indexes[1:]:
                if((index.row() < row) and (index.column() < column)):
                    row     = index.row()
                    column  = index.column()
                    top_left_index = index
        return top_left_index            
            
    def clear_all_filters(self):
        """
        Clears all the current filter and return the table to its initial view.
        """
        top_selected_index = self.get_top_left_selected_row_index()
        
        self.per_column_filter_out_set_list = [set() for column in range(len(self.table_data[0]))]
        self.per_column_filter_in_set_list = [set() for column in range(len(self.table_data[0]))]
        self.apply_filter(is_filtering_mode_out = True)
        
        if(top_selected_index != None):
            self.select_cell_by_index(top_selected_index)
      
        self.update_status_bar()   

        
    def hide_rows_based_on_selected_cells(self):
        """
        Hides the selected rows and any other rows with matching data.
        """
        selected_indexes = self.get_selected_indexes()
        for index in selected_indexes:
            column = index.column()
            self.per_column_filter_out_set_list[column].add(index.data())
        
        new_selected_row = None
        min_selected_row = selected_indexes[0].row()    
        max_selected_row = selected_indexes[-1].row()    
        if(min_selected_row != 0):
            new_selected_row = min_selected_row - 1
        elif(max_selected_row != self.table_model.columnCount(None)):
            new_selected_row = max_selected_row + 1
            
        self.apply_filter(is_filtering_mode_out=True)    
        
        self.select_cell_by_row_and_column(new_selected_row, selected_indexes[0].column())
        self.update_status_bar()   
            
    def show_rows_based_on_selected_cells(self):
        """
        Shows the selected rows and any other rows with matching data only.
        """
        
        selected_indexes = self.get_selected_indexes()
        self.per_column_filter_in_set_list = [set() for column in range(len(self.table_data[0]))]
        for index in selected_indexes:
            column = index.column()
            self.per_column_filter_in_set_list[column].add(index.data())
        self.apply_filter(is_filtering_mode_out=False)   
        self.update_status_bar()   

    def unhide_selected_rows_only_based_on_column(self, filter_column, filtered_out_string):
        """
        Unhides the selected rows and any other rows with matching data.
        
        The filtering works on one column only.
        """
        top_selected_index = self.get_top_left_selected_row_index()

        if(self.is_filtering_mode_out):
            self.per_column_filter_out_set_list[filter_column].remove(filtered_out_string)
        else:
            self.per_column_filter_in_set_list[filter_column].add(filtered_out_string)
            
        logging.debug("Unhiding: %s", filtered_out_string)
        self.apply_filter(self.is_filtering_mode_out)
        
        if(top_selected_index != None):
            self.select_cell_by_index(top_selected_index)
        
        self.update_status_bar()   
        
    def apply_filter(self, is_filtering_mode_out):    
        """
        Applies the filter based on the given mode. 
        """
        self.is_filtering_mode_out = is_filtering_mode_out
        if(is_filtering_mode_out):
            self.proxy_model.setFilterOutList(self.per_column_filter_out_set_list)
        else:
            self.proxy_model.setFilterInList(self.per_column_filter_in_set_list)
        
        # This is just to trigger the proxy model to apply the filter    
        self.proxy_model.setFilterKeyColumn(0)
    
    def dragEnterEvent(self, q_drag_enter_event):
        if(q_drag_enter_event.mimeData().hasFormat("text/uri-list")):
            q_drag_enter_event.acceptProposedAction();
    
    def dropEvent(self, q_drop_event):
        url_list = q_drop_event.mimeData().urls()
        if(len(url_list) == 0):
            return
        log_file_list = [url.toLocalFile() for url in url_list]
        self.log_file_full_path = log_file_list[0]
        self.load_log_file(self.log_file_full_path)
    
    def closeEvent(self, event):
        app = QApplication([])
#         app.closeAllWindows() 
        app.deleteLater()
        app.closeAllWindows()
Example #32
0
 def on_custom_context_menu_requested(self):
     menu = QMenu(self)
     for action in self.actions:
         menu.addAction(action)
     menu.popup(self.cursor().pos())
Example #33
0
class Tabs(QTabWidget):
    """TabWidget with a context-menu"""
    def __init__(self, parent, actions=None):
        QTabWidget.__init__(self, parent)
        tab_bar = TabsBase(self, parent)
        self.connect(tab_bar, SIGNAL('move_tab(int,int)'), self.move_tab)
        self.connect(tab_bar, SIGNAL('move_tab(long,int,int)'),
                     self.move_tab_from_another_tabwidget)
        self.setTabBar(tab_bar)
        self.menu = QMenu(self)
        if actions:
            add_actions(self.menu, actions)
        self.index_history = []
        self.connect(self, SIGNAL('currentChanged(int)'),
                     self.__current_changed)
        tabsc = QShortcut(QKeySequence("Ctrl+Tab"), parent, self.tab_navigate)
        tabsc.setContext(Qt.WidgetWithChildrenShortcut)

    def __current_changed(self, index):
        for i, ind in [(i, ind) for i, ind in enumerate(self.index_history)]:
            if ind > self.count() - 1:
                self.index_history.pop(i)
        while index in self.index_history:
            self.index_history.pop(self.index_history.index(index))
        self.index_history.append(index)

    def tab_navigate(self):
        """Ctrl+Tab"""
        if len(self.index_history) > 1:
            last = len(self.index_history) - 1
            index = self.index_history.pop(last)
            self.index_history.insert(0, index)
            self.setCurrentIndex(self.index_history[last])
        elif len(self.index_history) == 0 and self.count():
            self.index_history = [self.currentIndex()]

    def contextMenuEvent(self, event):
        """Override Qt method"""
        if self.menu:
            self.menu.popup(event.globalPos())

    def mousePressEvent(self, event):
        """Override Qt method"""
        if event.button() == Qt.MidButton:
            index = self.tabBar().tabAt(event.pos())
            if index >= 0:
                self.emit(SIGNAL("close_tab(int)"), index)
                event.accept()
                return
        QTabWidget.mousePressEvent(self, event)

    def keyPressEvent(self, event):
        """Override Qt method"""
        ctrl = event.modifiers() & Qt.ControlModifier
        key = event.key()
        handled = False
        if ctrl and self.count() > 0:
            index = self.currentIndex()
            if key == Qt.Key_PageUp and index > 0:
                self.setCurrentIndex(index - 1)
                handled = True
            elif key == Qt.Key_PageDown and index < self.count() - 1:
                self.setCurrentIndex(index + 1)
                handled = True
        if handled:
            event.accept()
        else:
            QTabWidget.keyPressEvent(self, event)

    def move_tab(self, index_from, index_to):
        """Move tab inside a tabwidget"""
        self.emit(SIGNAL('move_data(int,int)'), index_from, index_to)

        tip, text = self.tabToolTip(index_from), self.tabText(index_from)
        icon, widget = self.tabIcon(index_from), self.widget(index_from)
        current_widget = self.currentWidget()

        self.removeTab(index_from)
        self.insertTab(index_to, widget, icon, text)
        self.setTabToolTip(index_to, tip)

        self.setCurrentWidget(current_widget)

        self.emit(SIGNAL('move_tab_finished()'))

    def move_tab_from_another_tabwidget(self, tabwidget_from, index_from,
                                        index_to):
        """Move tab from a tabwidget to another"""
        self.emit(SIGNAL('move_tab(long,long,int,int)'), tabwidget_from,
                  id(self), index_from, index_to)
Example #34
0
class WatchPointView(QTreeView):
    " Watch expression viewer widget "

    def __init__(self, parent, wpointsModel):
        QTreeView.__init__(self, parent)

        self.__model = None
        self.setModel(wpointsModel)

        self.setItemsExpandable(False)
        self.setRootIsDecorated(False)
        self.setAlternatingRowColors(True)
        self.setUniformRowHeights(True)
        self.setSelectionMode(QAbstractItemView.SingleSelection)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setItemDelegate(NoOutlineHeightDelegate(4))

        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.__showContextMenu)
        self.doubleClicked.connect(self.__doubleClicked)

        self.__createPopupMenus()
        return

    def setModel(self, model):
        " Sets the watch expression model "
        self.__model = model

        self.sortingModel = QSortFilterProxyModel()
        self.sortingModel.setSourceModel(self.__model)
        QTreeView.setModel(self, self.sortingModel)

        header = self.header()
        header.setSortIndicator(0, Qt.AscendingOrder)
        header.setSortIndicatorShown(True)
        header.setClickable(True)

        self.setSortingEnabled(True)
        self.__layoutDisplay()
        return

    def __layoutDisplay(self):
        " Performs the layout operation "
        self.__resizeColumns()
        self.__resort()
        return

    def __resizeColumns(self):
        " Resizes the view when items get added, edited or deleted "
        self.header().resizeSections(QHeaderView.ResizeToContents)
        self.header().setStretchLastSection(True)
        return

    def __resort(self):
        " Resorts the tree "
        self.model().sort(self.header().sortIndicatorSection(),
                          self.header().sortIndicatorOrder())
        return

    def __toSourceIndex(self, index):
        " Converts an index to a source index "
        return self.sortingModel.mapToSource(index)

    def __fromSourceIndex(self, sindex):
        " Converts a source index to an index "
        return self.sortingModel.mapFromSource(sindex)

    def __setRowSelected(self, index, selected=True):
        " Selects a row "
        if not index.isValid():
            return

        if selected:
            flags = QItemSelectionModel.SelectionFlags(
                QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows)
        else:
            flags = QItemSelectionModel.SelectionFlags(
                QItemSelectionModel.Deselect | QItemSelectionModel.Rows)
        self.selectionModel().select(index, flags)
        return

    def __createPopupMenus(self):
        """
        Private method to generate the popup menus.
        """
        self.menu = QMenu()
        self.menu.addAction(self.trUtf8("Add"), self.__addWatchPoint)
        self.menu.addAction(self.trUtf8("Edit..."), self.__editWatchPoint)
        self.menu.addSeparator()
        self.menu.addAction(self.trUtf8("Enable"), self.__enableWatchPoint)
        self.menu.addAction(self.trUtf8("Enable all"),
                            self.__enableAllWatchPoints)
        self.menu.addSeparator()
        self.menu.addAction(self.trUtf8("Disable"), self.__disableWatchPoint)
        self.menu.addAction(self.trUtf8("Disable all"),
                            self.__disableAllWatchPoints)
        self.menu.addSeparator()
        self.menu.addAction(self.trUtf8("Delete"), self.__deleteWatchPoint)
        self.menu.addAction(self.trUtf8("Delete all"),
                            self.__deleteAllWatchPoints)

        self.backMenuActions = {}
        self.backMenu = QMenu()
        self.backMenu.addAction(self.trUtf8("Add"), self.__addWatchPoint)
        self.backMenuActions["EnableAll"] = \
            self.backMenu.addAction(self.trUtf8("Enable all"),
                self.__enableAllWatchPoints)
        self.backMenuActions["DisableAll"] = \
            self.backMenu.addAction(self.trUtf8("Disable all"),
                self.__disableAllWatchPoints)
        self.backMenuActions["DeleteAll"] = \
            self.backMenu.addAction(self.trUtf8("Delete all"),
                self.__deleteAllWatchPoints)
        self.backMenu.aboutToShow.connect(self.__showBackMenu)

        self.multiMenu = QMenu()
        self.multiMenu.addAction(self.trUtf8("Add"), self.__addWatchPoint)
        self.multiMenu.addSeparator()
        self.multiMenu.addAction(self.trUtf8("Enable selected"),
                                 self.__enableSelectedWatchPoints)
        self.multiMenu.addAction(self.trUtf8("Enable all"),
                                 self.__enableAllWatchPoints)
        self.multiMenu.addSeparator()
        self.multiMenu.addAction(self.trUtf8("Disable selected"),
                                 self.__disableSelectedWatchPoints)
        self.multiMenu.addAction(self.trUtf8("Disable all"),
                                 self.__disableAllWatchPoints)
        self.multiMenu.addSeparator()
        self.multiMenu.addAction(self.trUtf8("Delete selected"),
                                 self.__deleteSelectedWatchPoints)
        self.multiMenu.addAction(self.trUtf8("Delete all"),
                                 self.__deleteAllWatchPoints)
        return

    def __showContextMenu(self, coord):
        """
        Private slot to show the context menu.

        @param coord the position of the mouse pointer (QPoint)
        """
        cnt = self.__getSelectedItemsCount()
        if cnt <= 1:
            index = self.indexAt(coord)
            if index.isValid():
                cnt = 1
                self.__setRowSelected(index)
        coord = self.mapToGlobal(coord)
        if cnt > 1:
            self.multiMenu.popup(coord)
        elif cnt == 1:
            self.menu.popup(coord)
        else:
            self.backMenu.popup(coord)

    def __findDuplicates(self,
                         cond,
                         special,
                         showMessage=False,
                         index=QModelIndex()):
        " Checks if an entry already exists "
        cond = unicode(cond)
        special = unicode(special)
        idx = self.__model.getWatchPointIndex(cond, special)
        duplicate = idx.isValid(
        ) and idx.internalPointer() != index.internalPointer()
        #        if showMessage and duplicate:
        #            if not special:
        #                msg = """<p>A watch expression '<b>%1</b>'"""
        #                                  """ already exists.</p>""".arg(Utilities.html_encode(unicode(cond)))
        #            else:
        #                msg = self.trUtf8("""<p>A watch expression '<b>%1</b>'"""
        #                                  """ for the variable <b>%2</b> already exists.</p>""")\
        #                        .arg(special)\
        #                        .arg(Utilities.html_encode(unicode(cond)))
        #            KQMessageBox.warning(None,
        #                self.trUtf8("Watch expression already exists"),
        #                msg)

        return duplicate

    def __clearSelection(self):
        " Clears the selection "
        for index in self.selectedIndexes():
            self.__setRowSelected(index, False)
        return

    def __addWatchPoint(self):
        " Adds watch expression via a context menu entry "
        #        dlg = EditWatchpointDialog( ( "", False, True, 0, "" ), self )
        #        if dlg.exec_() == QDialog.Accepted:
        #            cond, temp, enabled, ignorecount, special = dlg.getData()
        #            if not self.__findDuplicates(cond, special, True):
        #                self.__model.addWatchPoint(cond, special, (temp, enabled, ignorecount))
        #                self.__resizeColumns()
        #                self.__resort()
        return

    def __doubleClicked(self, index):
        " Handles the double clicked signal "
        if index.isValid():
            self.__doEditWatchPoint(index)
        return

    def __editWatchPoint(self):
        " Handles the edit watch expression context menu entry "
        index = self.currentIndex()
        if index.isValid():
            self.__doEditWatchPoint(index)
        return

    def __doEditWatchPoint(self, index):
        " Edits a watch expression "
        sindex = self.__toSourceIndex(index)
        if sindex.isValid():
            wp = self.__model.getWatchPointByIndex(sindex)
            if not wp:
                return

            cond, special, temp, enabled, count = wp[:5]


#            dlg = EditWatchpointDialog(
#                (cond, temp, enabled, count, special), self)
#            if dlg.exec_() == QDialog.Accepted:
#                cond, temp, enabled, count, special = dlg.getData()
#                if not self.__findDuplicates(cond, special, True, sindex):
#                    self.__model.setWatchPointByIndex(sindex,
#                        unicode(cond), unicode(special), (temp, enabled, count))
#                    self.__resizeColumns()
#                    self.__resort()
        return

    def __setWpEnabled(self, index, enabled):
        " Sets the enabled status of a watch expression "
        sindex = self.__toSourceIndex(index)
        if sindex.isValid():
            self.__model.setWatchPointEnabledByIndex(sindex, enabled)
        return

    def __enableWatchPoint(self):
        " Handles the enable watch expression context menu entry "
        index = self.currentIndex()
        self.__setWpEnabled(index, True)
        self.__resizeColumns()
        self.__resort()
        return

    def __enableAllWatchPoints(self):
        " Handles the enable all watch expressions context menu entry "
        index = self.model().index(0, 0)
        while index.isValid():
            self.__setWpEnabled(index, True)
            index = self.indexBelow(index)
        self.__resizeColumns()
        self.__resort()
        return

    def __enableSelectedWatchPoints(self):
        " Handles the enable selected watch expressions context menu entry "
        for index in self.selectedIndexes():
            if index.column() == 0:
                self.__setWpEnabled(index, True)
        self.__resizeColumns()
        self.__resort()
        return

    def __disableWatchPoint(self):
        " Handles the disable watch expression context menu entry "
        index = self.currentIndex()
        self.__setWpEnabled(index, False)
        self.__resizeColumns()
        self.__resort()
        return

    def __disableAllWatchPoints(self):
        " Handles the disable all watch expressions context menu entry "
        index = self.model().index(0, 0)
        while index.isValid():
            self.__setWpEnabled(index, False)
            index = self.indexBelow(index)
        self.__resizeColumns()
        self.__resort()
        return

    def __disableSelectedWatchPoints(self):
        " Handles the disable selected watch expressions context menu entry "
        for index in self.selectedIndexes():
            if index.column() == 0:
                self.__setWpEnabled(index, False)
        self.__resizeColumns()
        self.__resort()
        return

    def __deleteWatchPoint(self):
        " Handles the delete watch expression context menu entry "
        index = self.currentIndex()
        sindex = self.__toSourceIndex(index)
        if sindex.isValid():
            self.__model.deleteWatchPointByIndex(sindex)
        return

    def __deleteAllWatchPoints(self):
        " Handles the delete all watch expressions context menu entry "
        self.__model.deleteAll()
        return

    def __deleteSelectedWatchPoints(self):
        " Handles the delete selected watch expressions context menu entry "
        idxList = []
        for index in self.selectedIndexes():
            sindex = self.__toSourceIndex(index)
            if sindex.isValid() and index.column() == 0:
                lastrow = index.row()
                idxList.append(sindex)
        self.__model.deleteWatchPoints(idxList)
        return

    def __showBackMenu(self):
        " Handles the aboutToShow signal of the background menu "
        if self.model().rowCount() == 0:
            self.backMenuActions["EnableAll"].setEnabled(False)
            self.backMenuActions["DisableAll"].setEnabled(False)
            self.backMenuActions["DeleteAll"].setEnabled(False)
        else:
            self.backMenuActions["EnableAll"].setEnabled(True)
            self.backMenuActions["DisableAll"].setEnabled(True)
            self.backMenuActions["DeleteAll"].setEnabled(True)
        return

    def __getSelectedItemsCount(self):
        " Provides the count of items selected "
        count = len(self.selectedIndexes()) / (self.__model.columnCount() - 1)
        # column count is 1 greater than selectable
        return count
Example #35
0
class myMainWindow(QMainWindow, Ui_MainWindow):
    askusersig = pyqtSignal(str, str, str, str, str, str) #connected to askUserOUT
    refreshmodelsig = pyqtSignal(str)
    update_bytestatssig = pyqtSignal(str)
    refreshconnectionssig = pyqtSignal()
    refreshrulessig = pyqtSignal()
    prevstats = ''
    model = None
    sourcemodel = None
    menu = None
    #index = None
    out_rules_num = 0

    def __init__(self):
        QMainWindow.__init__(self)
        self.setupUi(self)
        #title2 = '我的个人防火墙'
        #print title2
        #title = QString(u'我的个人防火墙')
        self.setWindowTitle(u'我的个人防火墙')
        #self.setWindowTitle(title)
        #self.setWindowIcon(QIcon(":/pics/pic.jpg"))
        self.tableView.setShowGrid(False)
        self.actionDisplay.triggered.connect(self.displayconnections)
        self.actionList_Rules.triggered.connect(self.listrules)
        self.actionAdd_Rules.triggered.connect(self.addrules)
        self.actionDisconnect.triggered.connect(self.disconnection)
        self.actionReconnect.triggered.connect(self.reconnection)
        self.actionMessage.triggered.connect(self.message)
        #self.menuRules.aboutToShow.connect(self.rulesMenuTriggered)
        #self.menuRules.actions()[0].triggered.connect(self.deleteMenuTriggered)
        #self.actionShow_active_only.triggered.connect(self.showActiveOnly)
        #self.actionShow_all.triggered.connect(self.showAll)
        self.actionExit.triggered.connect(self.realQuit)
        self.askusersig.connect(self.askUser)
        self.update_bytestatssig.connect(self.update_bytestats)
        self.refreshmodelsig.connect(self.refreshmodel)
        self.refreshconnectionssig.connect(self.refreshconnections)
        self.refreshrulessig.connect(self.refreshrules)
        #msgQueue.put('LIST')        

    def message(self):
        dialog = msgdialog
        dialog.show()

    def disconnection(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect( ('127.0.0.1', 9999) )
        sock.send("--disconnect")
        data = sock.recv(1024)
        print data
        sock.close()

    def reconnection(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect( ('127.0.0.1', 9999) )
        sock.send("--reconnect")
        data = sock.recv(1024)
        print data
        sock.close()

    def addrules(self):
        dialog = addruledialog
        dialog.show()

    def contextMenuEvent(self, event):
        current_layout_lock.acquire()
        if(self.sourcemodel.current_layout == "conn"):
            current_layout_lock.release()
            return
        current_layout_lock.release()
        #self.index = self.sourcemodel.indexAt(event.pos())
        self.menu = QMenu(self)
        delete_ruleAction = QAction(u"删除", self)
        delete_ruleAction.triggered.connect(self.deleterule)
        self.menu.addAction(delete_ruleAction)
        self.menu.popup(QtGui.QCursor.pos())

    def deleterule(self):
        #index = self.tableView.selectedIndexes()
        #print(index[0].row())
        row_num = (self.tableView.selectedIndexes())[0].row()
        if(row_num < self.out_rules_num):
            #print ("-d OUT " + str(row_num + 1))
            cmd_del = "-d OUT " + str(row_num + 1)
        else:
            #print ("-d IN " + str(row_num - self.out_rules_num + 1))
            cmd_del = "-d IN " + str(row_num - self.out_rules_num + 1)
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect(('127.0.0.1', 9999))
        sock.send(cmd_del)
        result = sock.recv(1024)
        print(result)
        sock.close()
        self.refreshrules()



    def listrules(self):
        self.sourcemodel.layout_change_to_rule_sig.emit()
        self.refreshrules()

    def refreshrules(self):
        #self.sourcemodel.layout_change_to_rule_sig.emit()
        current_layout_lock.acquire()
        if(self.sourcemodel.current_layout != "rule"):
            print ("refreshrules error")
            current_layout_lock.release()
            return
        self.sourcemodel.layoutAboutToBeChanged.emit()
        self.sourcemodel.removeRows(0, self.sourcemodel.rowCount())
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect(('127.0.0.1', 9999))
        sock.send("--list")
        ruleslist = ''
        while(True):
            data = sock.recv(1024)
            if not data:
                break
            ruleslist = ruleslist + data
        sock.close()
        #print (ruleslist)
        if ruleslist:
            self.out_rules_num = 0
            for ruleline in ruleslist[0:-1].split('\n'):
                #print ( 'line: ' + line)
                items = ruleline.split()
                print (items)
                if(items[0] == 'direction:OUT'):
                    self.out_rules_num += 1
                direction = QStandardItem((items[0].split(':'))[1])
                lport = QStandardItem((items[1].split(':'))[1])
                raddr = QStandardItem((items[3].split(':'))[1])
                rport = QStandardItem((items[5].split(':'))[1])
                proto = QStandardItem((items[6].split(':'))[1])
                target = QStandardItem((items[7].split(':'))[1])
                #print (direction + ':' + lport + ':' + raddr + ':' + rport + ':' + proto + ':' + target) 
                self.sourcemodel.appendRow( (direction, lport, raddr, rport, proto, target) )

        self.sourcemodel.layoutChanged.emit()
        current_layout_lock.release()

    def displayconnections(self):
        '''
        if(self.sourcemodel.current_layout == "conn"):
            self.refreshconnectionssig.emit()
        else:
            self.sourcemode.layout_change_to_conn_sig.emit()
            self.refreshconnections()
            '''
        self.sourcemodel.layout_change_to_conn_sig.emit()
        self.refreshconnections()
        


    def refreshconnections(self):
        current_layout_lock.acquire()
        if(self.sourcemodel.current_layout != "conn"):
            print ("refreshconnections error")
            current_layout_lock.release()
            return
        self.sourcemodel.layoutAboutToBeChanged.emit()
        self.sourcemodel.removeRows(0, self.sourcemodel.rowCount())
        for conn in psutil.net_connections("inet4"):
            if(conn.type == socket.SOCK_STREAM):
                proto = QStandardItem("tcp")
            else:
                proto = QStandardItem("udp")
            laddr = QStandardItem(conn.laddr[0])
            lport = QStandardItem(str(conn.laddr[1]))
            if(len(conn.raddr) == 0):
                continue
            raddr = QStandardItem(conn.raddr[0])
            rport = QStandardItem(str(conn.raddr[1]))
            status = QStandardItem(conn.status)
            pid = QStandardItem(str(conn.pid))
            if(conn.pid != None):
                p = psutil.Process(conn.pid)
                name = QStandardItem(p.name())
            else:
                name = QStandardItem("None")
            family = QStandardItem("ipv4")
            self.sourcemodel.appendRow( (family, proto, laddr, lport, raddr, rport, status, pid, name))
        self.sourcemodel.layoutChanged.emit()
        current_layout_lock.release()



    def showActiveOnly(self):
        self.model.toggle_mode_sig.emit('SHOW ACTIVE ONLY')
        self.actionShow_active_only.setEnabled(False)
        self.actionShow_all.setEnabled(True)
        self.actionShow_all.setChecked(False)
     
    def showAll(self):
        self.model.toggle_mode_sig.emit('SHOW ALL')        
        self.actionShow_active_only.setEnabled(True)
        self.actionShow_all.setEnabled(False)
        self.actionShow_active_only.setChecked(False)


    @pyqtSlot(str, str, str, str, str, str)
    def askUser(self, req_str_in, path_in, pid_in, addr_in, dport_in, sport_in):
        #print "In askUser"
        #Convert all incoming QString into normal python strings
        req_str = str(req_str_in)
        path = unicode(QString.fromUtf8(path_in))
        pid = str(pid_in)
        addr = str(addr_in)
        dport = str(dport_in)
        sport = str(sport_in)
        if (req_str == 'REQUEST_OUT'):
            dialog = dialogOut
            rport = sport
            lport = dport
        elif (req_str == 'REQUEST_IN'):
            dialog = dialogOut            
            rport = dport
            lport = sport

        name = string.rsplit(path,"/",1)
        dialog.path = path
        dialog.pid = pid
        dialog.label_name.setText(name[1])
        dialog.label_ip.setText(addr)
        dialog.label_domain.setText("Looking up DNS...")        
        fullpath = QTableWidgetItem(unicode(QString.fromUtf8(path)))
        dialog.tableWidget_details.setItem(0,1,fullpath)
        pid_item = QTableWidgetItem(pid)
        dialog.tableWidget_details.setItem(1,1,pid_item)
        remoteip = QTableWidgetItem(addr)
        dialog.tableWidget_details.setItem(2,1,remoteip)
        dns = QTableWidgetItem("Looking up DNS...")
        dialog.tableWidget_details.setItem(3,1,dns)
        rport_item = QTableWidgetItem(rport)
        dialog.tableWidget_details.setItem(4,1,rport_item)
        lport_item = QTableWidgetItem(lport)
        dialog.tableWidget_details.setItem(5,1,lport_item)
        QHostInfo.lookupHost(addr, dialog.dnsLookupFinished)
        #we don't want the user to accidentally trigger ALLOW
        dialog.pushButton_deny.setFocus()
        dialog.show()



    def rulesMenuTriggered(self):
        "If no rules are selected in the view, grey out the Delete... item"
        if (len(self.tableView.selectedIndexes()) == 0):
            self.menuRules.actions()[0].setEnabled(False)
        else:
            self.menuRules.actions()[0].setEnabled(True)


    def deleteMenuTriggered(self):
        "send delete request to backend"
        selected_indexes = self.tableView.selectedIndexes()
        bFound = False
        for index in selected_indexes:
            if index.column() != 3: continue
            path = unicode(index.data().toPyObject())
            bFound = True
            break
        if not bFound:
            #print 'Could not find the path to delete'
            return
        msgQueue.put('DELETE ' + b64encode(bytearray(path, encoding='utf-8')))
    

    def closeEvent(self, event):
        event.ignore()
        self.hide()


    def realQuit(self): 
        #print "see you later..."
        #msgQueue.put('UNREGISTER')
        time.sleep(1) #allow queue to be processed
        exit(1)

    @pyqtSlot(unicode)
    def refreshmodel(self, data_in):  
        "Fill the frontend with rules data"
        rawstr = unicode(QString.fromUtf8(data_in))

        export_list = []            
        rules = rawstr[len('RULES_LIST'):].split('CRLF')
        for one_rule in rules: 
            split_rule = one_rule.split()
            if len(split_rule) != 5: continue
            export_list.append(split_rule)
        export_list.append("EOF")
        ruleslist = export_list
        #empty the model, we're filling it anew, we can't use clear() cause it flushes headers too:
        modellock.acquire()
        self.sourcemodel.layoutAboutToBeChanged.emit()
        self.sourcemodel.removeRows(0, self.sourcemodel.rowCount())
    
        #if there's only one element, it's EOF; dont go through iterations,just leave the model empty
        if (len(ruleslist) == 1):
            self.sourcemodel.layoutChanged.emit()            
            modellock.release()
            return
        for item in ruleslist[0:-1]:#leave out the last EOF from iteration
            path_u = b64decode(item[0]).decode('utf-8')
            fullpath = QStandardItem(path_u)
            #item[4] contains nfmark
            fullpath.setData(item[4])
            if (item[1] == "0"):
                pid_string = "N/A"
            else: 
                pid_string = item[1]
            pid = QStandardItem(pid_string)
            perms = QStandardItem(item[2])
            #only the name of the executable after the last /
            m_list = string.rsplit(path_u,"/",1)
            m_name = m_list[1]
            name = QStandardItem(m_name)
            in_allow_traf = QStandardItem()
            out_allow_traf = QStandardItem()
            in_deny_traf = QStandardItem()
            out_deny_traf = QStandardItem()
            self.sourcemodel.appendRow( (name, pid, perms, fullpath,
                                 in_allow_traf, out_allow_traf, in_deny_traf, out_deny_traf) ) 
            #print "Received: %s" %(item[0])
        self.sourcemodel.layoutChanged.emit()                    
        modellock.release()
        self.update_bytestats()        


    #Update and remember the stats. The stats may be restored from 
    #a previous save when model refreshes
    @pyqtSlot(str)
    def update_bytestats(self, data_in = ''):
        data = str(data_in)
        items = []
        if (data):
            message = data.split('EOL')[-2] #discard the last empty one and take the one before it
            #take the last message with 5 elements as it is the most recent one
            items = message.split('CRLF')[:-1] #discard the last empty one
        if (items):
            self.prevstats = items
        else:
            items = self.prevstats
        #one item looks like '1212 3232 3243 4343 43434'
        modellock.acquire()
        self.sourcemodel.layoutAboutToBeChanged.emit()                    
        for one_item in items:
            fields = one_item.split()
            for j in range(self.sourcemodel.rowCount()):
                #4th element of each line has nfmark in its data field
                if (self.sourcemodel.item(j,3).data().toString() != fields[0]): continue
                #else
                self.sourcemodel.item(j,4).setText(fields[1])
                self.sourcemodel.item(j,5).setText(fields[2])
                self.sourcemodel.item(j,6).setText(fields[3])
                self.sourcemodel.item(j,7).setText(fields[4])
                break
        self.sourcemodel.layoutChanged.emit()                    
        modellock.release()   
Example #36
0
    def doMenu(self, pos):
        index = self.indexAt(pos)

        if not index.isValid():
            return

        item = self.itemAt(pos)
        menu = QMenu(self)
        action_Folder = QAction(Icons.newfolder,'New Folder', self)
        action_Folder.triggered.connect(lambda:self.newFolder(item))
        action_File = QAction(Icons.new_file,'New File', self)
        action_File.triggered.connect(lambda:self.newFile(item))
        action_Open = QAction('Open', self)
        action_Open.triggered.connect(lambda:self.openProject(item))
        action_Close = QAction('Close', self)
        action_Close.triggered.connect(lambda:self.closeProject(item))
        
        action_OpenFile = QAction(Icons.open,'Open', self)
        action_OpenFile.triggered.connect(lambda:self.openFile(item))
        action_RunFile = QAction(Icons.go,'Python Run', self)
        action_RunFile.triggered.connect(lambda:self.runFile(item))
        action_SendFile = QAction(Icons.file_obj,'Send to SDcard', self)
        action_SendFile.triggered.connect(lambda:self.sendFile(item))
        action_Copy = QAction(Icons.file_obj,'Copy', self)
        action_Copy.triggered.connect(lambda:self.copy(item))
        action_Paste = QAction(Icons.paste_edit,'Paste', self)
        action_Paste.triggered.connect(lambda:self.paste(item))
        if(self.clipboard == []):
            action_Paste.setEnabled(False)
            
        action_RefreshProject = QAction(Icons.refresh_tab,'Refresh', self)
        action_RefreshProject.triggered.connect(lambda:self.refreshProject(item))
        action_RemoveProject = QAction('Remove', self)
        action_RemoveProject.triggered.connect(lambda:self.removeProject(item))
        action_RenameProject = QAction('Rename...', self)
        action_RenameProject.triggered.connect(lambda:self.renameProject(item))
        action_RenameDir = QAction('Rename...', self)
        action_RenameDir.triggered.connect(lambda:self.renameDir(item))
        action_RenameFile = QAction('Rename...', self)
        action_RenameFile.triggered.connect(lambda:self.renameFile(item))
        action_DeleteFile = QAction(Icons.trash,'Delete', self)
        action_DeleteFile.triggered.connect(lambda:self.deleteFile(item))
        action_DeleteDir = QAction(Icons.trash,'Delete', self)
        action_DeleteDir.triggered.connect(lambda:self.deleteDir(item))
        action_DeleteProject = QAction(Icons.trash,'Delete', self)
        action_DeleteProject.triggered.connect(lambda:self.deleteProject(item))
        
        action_CreateProject = QAction('Create Android', self)
        action_CreateProject.triggered.connect(lambda:self.create(item))
        action_BuildProject = QAction('Build', self)
        action_BuildProject.triggered.connect(lambda:self.build(item))
        action_BuildRunProject = QAction('Build and Install', self)
        action_BuildRunProject.triggered.connect(lambda:self.buildRun(item))
        action_CleanProject = QAction('Clean', self)
        action_CleanProject.triggered.connect(lambda:self.clean(item))
        action_RunProject = QAction('Install', self)
        action_RunProject.triggered.connect(lambda:self.run(item))
        if(item.isProject()):
            if not(item.isClosed()):
                menu.addAction(action_Folder)
                menu.addAction(action_File)
                menu.addSeparator()
                menu.addAction(action_CreateProject)
                menu.addAction(action_BuildProject)
                menu.addAction(action_BuildRunProject)
                menu.addAction(action_RunProject)
                menu.addAction(action_CleanProject)
                menu.addSeparator()
                menu.addAction(action_RenameProject)
                menu.addAction(action_RemoveProject)
                menu.addAction(action_DeleteProject)
                menu.addSeparator()
                menu.addAction(action_RefreshProject)
                menu.addAction(action_Close)
            else:
                menu.addAction(action_Open)
        else:
            if(item.isDir()):
                menu.addAction(action_Folder)
                menu.addAction(action_File)
                menu.addSeparator()
                #menu.addAction(action_Copy)
                menu.addAction(action_Paste)
                menu.addAction(action_RenameDir)
                menu.addAction(action_DeleteDir)      
            else:
                menu1 = QMenu(self)
                menu1.setTitle("Run As")
                menu1.addAction(action_RunFile)
                menu.addMenu(menu1)
                menu.addAction(action_OpenFile)
                menu.addSeparator()
                menu.addAction(action_SendFile)
                menu.addSeparator()
                menu.addAction(action_Copy)
                
                menu.addAction(action_Paste)
                menu.addAction(action_RenameFile)
                menu.addAction(action_DeleteFile)
                
        menu.popup(QCursor.pos())
Example #37
0
class auto(QGraphicsPixmapItem):
    def __init__(self, *args):
        self.seleccionado = False
        self.velocity = random.randint(1, 10)
        QGraphicsPixmapItem.__init__(self, *args)
        self.setPixmap(
            QPixmap("sprites/" + str(random.randint(1, 45)) + ".png"))
        self.setTransformOriginPoint(self.boundingRect().width() / 2.0,
                                     self.boundingRect().height() / 2.0)
        self.setZValue(10)
        ##menu contextual
        self.menu = QMenu()
        self.Actions = []  #arreglo de acciones
        self.Actions.append(self.menu.addAction("Seguir"))
        self.Actions.append(self.menu.addAction("Editar"))
        self.Actions.append(self.menu.addAction("girar clockwise"))
        self.Actions.append(self.menu.addAction("girar anti-clockwise"))
        self.Actions.append(self.menu.addAction("Colisiones"))
        self.Actions.append(self.menu.addAction("Duplicar"))
        self.Actions.append(self.menu.addAction("Eliminar"))
        self.menu.triggered[QAction].connect(self.test)
        ##offset para el arrastre
        self.offset = QPointF(0, 0)
        ##poligono de vision
        poligono = QPolygonF()
        poligono.append(QPointF(-1, 10))
        poligono.append(QPointF(-1, 20))
        poligono.append(QPointF(-30, 40))
        poligono.append(QPointF(-40, 15))
        poligono.append(QPointF(-30, -10))
        self.vision = QGraphicsPolygonItem(poligono, self, self.scene())
        self.vision.setBrush(QColor(255, 255, 0, 100))
        self.vision.setPen(QColor(255, 255, 0))

    def info(self):
        return "Velocidad " + str(self.velocity) + " posicion " + str(
            self.pos())[20:] + "\n"

    def test(self, act):
        print act.text()
        if act.text() == "girar clockwise":
            self.setRotation(self.rotation() - 45)
        if act.text() == "girar anti-clockwise":
            self.setRotation(self.rotation() + 45)
        if act.text() == "Colisiones":
            print "colisiones con", self.collidingItems(
                1), self.vision.collidingItems(1)
        if act.text() == "Duplicar":
            self.scene().addItem(auto())
        if act.text() == "Eliminar":
            self.scene().removeItem(self)

    def contextMenuEvent(self, event):
        self.menu.popup(event.screenPos())

    def mousePressEvent(self, event):
        p = event.pos()
        self.offset = QPointF(p.x() * 1.0, p.y() * 1.0)
        self.seleccionado = not self.seleccionado

    def mouseMoveEvent(self, event):
        self.setPos(event.scenePos() - self.offset)

    def avanza(self):
        if self.velocity != 0:
            """print velocity
              print "current pos (%f,%f)"%(self.pos().x(),self.pos().y())
              print "angle %f "%(self.rotation())"""
            radians = self.rotation() * 0.0174532925
            """ print "angle rad %f "%(radians)"""
            nx = 1.0 * self.velocity * cos(radians)
            ny = 1.0 * self.velocity * sin(radians)
            """ print "avanzara a (%f,%f)"%(nx,ny) """
            self.setPos(self.pos().x() - nx, self.pos().y() - ny)
            """for i in self.collidingItems():
Example #38
0
class TagHelpViewer( QWidget ):
    """ The tag help viewer widget """

    def __init__( self, parent = None ):
        QWidget.__init__( self, parent )

        self.__isEmpty = True
        self.__copyAvailable = False
        self.__clearButton = None
        self.__textEdit = None
        self.__header = None
        self.__copyButton = None
        self.__selectAllButton = None
        self.__createLayout( parent )

        # create the context menu
        self.__menu = QMenu( self )
        self.__selectAllMenuItem = self.__menu.addAction(
                            PixmapCache().getIcon( 'selectall.png' ),
                            'Select All', self.__textEdit.selectAll )
        self.__copyMenuItem = self.__menu.addAction(
                            PixmapCache().getIcon( 'copytoclipboard.png' ),
                            'Copy', self.__textEdit.copy )
        self.__menu.addSeparator()
        self.__clearMenuItem = self.__menu.addAction(
                            PixmapCache().getIcon( 'trash.png' ),
                            'Clear', self.__clear )

        self.__textEdit.setContextMenuPolicy( Qt.CustomContextMenu )
        self.__textEdit.customContextMenuRequested.connect(
                                                self.__handleShowContextMenu )
        self.__textEdit.copyAvailable.connect( self.__onCopyAvailable )

        self.__updateToolbarButtons()
        return

    def __createLayout( self, parent ):
        " Helper to create the viewer layout "

        # __textEdit list area
        self.__textEdit = QPlainTextEdit( parent )
        self.__textEdit.setLineWrapMode( QPlainTextEdit.NoWrap )
        self.__textEdit.setFont( QFont( GlobalData().skin.baseMonoFontFace ) )
        self.__textEdit.setReadOnly( True )

        # Default font size is good enough for most of the systems.
        # 12.0 might be good only in case of the XServer on PC (Xming).
        # self.__textEdit.setFontPointSize( 12.0 )

        # Buttons
        self.__selectAllButton = QAction(
            PixmapCache().getIcon( 'selectall.png' ),
            'Select all', self )
        self.__selectAllButton.triggered.connect(self.__textEdit.selectAll )
        self.__copyButton = QAction(
            PixmapCache().getIcon( 'copytoclipboard.png' ),
            'Copy to clipboard', self )
        self.__copyButton.triggered.connect( self.__textEdit.copy )
        spacer = QWidget()
        spacer.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding )
        self.__clearButton = QAction(
            PixmapCache().getIcon( 'trash.png' ),
            'Clear all', self )
        self.__clearButton.triggered.connect( self.__clear )

        # Toolbar
        toolbar = QToolBar()
        toolbar.setOrientation( Qt.Vertical )
        toolbar.setMovable( False )
        toolbar.setAllowedAreas( Qt.LeftToolBarArea )
        toolbar.setIconSize( QSize( 16, 16 ) )
        toolbar.setFixedWidth( 28 )
        toolbar.setContentsMargins( 0, 0, 0, 0 )
        toolbar.addAction( self.__selectAllButton )
        toolbar.addAction( self.__copyButton )
        toolbar.addWidget( spacer )
        toolbar.addAction( self.__clearButton )

        self.__header = QLabel( "Signature: none" )
        self.__header.setFrameStyle( QFrame.StyledPanel )
        self.__header.setSizePolicy( QSizePolicy.Ignored, QSizePolicy.Fixed )
        self.__header.setAutoFillBackground( True )
        headerPalette = self.__header.palette()
        headerBackground = headerPalette.color( QPalette.Background )
        headerBackground.setRgb( min( headerBackground.red() + 30, 255 ),
                                 min( headerBackground.green() + 30, 255 ),
                                 min( headerBackground.blue() + 30, 255 ) )
        headerPalette.setColor( QPalette.Background, headerBackground )
        self.__header.setPalette( headerPalette )
        verticalLayout = QVBoxLayout()
        verticalLayout.setContentsMargins( 2, 2, 2, 2 )
        verticalLayout.setSpacing( 2 )
        verticalLayout.addWidget( self.__header )
        verticalLayout.addWidget( self.__textEdit )

        # layout
        layout = QHBoxLayout()
        layout.setContentsMargins( 0, 0, 0, 0 )
        layout.setSpacing( 0 )
        layout.addWidget( toolbar )
        layout.addLayout( verticalLayout )

        self.setLayout( layout )
        return

    def __handleShowContextMenu( self, coord ):
        """ Show the context menu """

        self.__selectAllMenuItem.setEnabled( not self.__isEmpty )
        self.__copyMenuItem.setEnabled( self.__copyAvailable )
        self.__clearMenuItem.setEnabled( not self.__isEmpty )

        self.__menu.popup( QCursor.pos() )
        return

    def __calltipDisplayable( self, calltip ):
        " True if calltip is displayable "
        if calltip is None:
            return False
        if calltip.strip() == "":
            return False
        return True

    def __docstringDisplayable( self, docstring ):
        " True if docstring is displayable "
        if docstring is None:
            return False
        if isinstance( docstring, dict ):
            if docstring[ "docstring" ].strip() == "":
                return False
            return True
        if docstring.strip() == "":
            return False
        return True

    def display( self, calltip, docstring ):
        " Displays the given help information "

        calltipDisplayable = self.__calltipDisplayable( calltip )
        docstringDisplayable = self.__docstringDisplayable( docstring )
        self.__isEmpty = True
        if calltipDisplayable or docstringDisplayable:
            self.__isEmpty = False

        if calltipDisplayable:
            if '\n' in calltip:
                calltip = calltip.split( '\n' )[ 0 ]
            self.__header.setText( "Signature: " + calltip.strip() )
        else:
            self.__header.setText( "Signature: n/a" )

        self.__textEdit.clear()
        if docstringDisplayable:
            if isinstance( docstring, dict ):
                docstring = docstring[ "docstring" ]
            self.__textEdit.insertPlainText( docstring )

        self.__updateToolbarButtons()
        QApplication.processEvents()
        return

    def __updateToolbarButtons( self ):
        " Contextually updates toolbar buttons "

        self.__selectAllButton.setEnabled( not self.__isEmpty )
        self.__copyButton.setEnabled( self.__copyAvailable )
        self.__clearButton.setEnabled( not self.__isEmpty )
        return

    def __clear( self ):
        " Triggers when the clear function is selected "
        self.__isEmpty = True
        self.__copyAvailable = False
        self.__header.setText( "Signature: none" )
        self.__textEdit.clear()
        self.__updateToolbarButtons()
        return

    def __onCopyAvailable( self, isAvailable ):
        " Triggers on the copyAvailable signal "
        self.__copyAvailable = isAvailable
        self.__updateToolbarButtons()
        return
Example #39
0
class DirView(QTreeView):
    """Base file/directory tree view"""
    def __init__(self, parent=None):
        super(DirView, self).__init__(parent)
        self.name_filters = None
        self.parent_widget = parent
        self.valid_types = None
        self.show_all = None
        self.menu = None
        self.common_actions = None
        self.__expanded_state = None
        self._to_be_loaded = None
        self.fsmodel = None
        self.setup_fs_model()
        self._scrollbar_positions = None

    #---- Model
    def setup_fs_model(self):
        """Setup filesystem model"""
        filters = QDir.AllDirs | QDir.Files | QDir.Drives | QDir.NoDotAndDotDot
        self.fsmodel = QFileSystemModel(self)
        self.fsmodel.setFilter(filters)
        self.fsmodel.setNameFilterDisables(False)

    def install_model(self):
        """Install filesystem model"""
        self.setModel(self.fsmodel)

    def setup_view(self):
        """Setup view"""
        self.install_model()
        self.connect(self.fsmodel, SIGNAL('directoryLoaded(QString)'),
                     lambda: self.resizeColumnToContents(0))
        self.setAnimated(False)
        self.setSortingEnabled(True)
        self.sortByColumn(0, Qt.AscendingOrder)

    def set_name_filters(self, name_filters):
        """Set name filters"""
        self.name_filters = name_filters
        self.fsmodel.setNameFilters(name_filters)

    def set_show_all(self, state):
        """Toggle 'show all files' state"""
        if state:
            self.fsmodel.setNameFilters([])
        else:
            self.fsmodel.setNameFilters(self.name_filters)

    def get_filename(self, index):
        """Return filename associated with *index*"""
        if index:
            return osp.normpath(unicode(self.fsmodel.filePath(index)))

    def get_index(self, filename):
        """Return index associated with filename"""
        return self.fsmodel.index(filename)

    def get_selected_filenames(self):
        """Return selected filenames"""
        if self.selectionMode() == self.ExtendedSelection:
            return [self.get_filename(idx) for idx in self.selectedIndexes()]
        else:
            return [self.get_filename(self.currentIndex())]

    def get_dirname(self, index):
        """Return dirname associated with *index*"""
        fname = self.get_filename(index)
        if fname:
            if osp.isdir(fname):
                return fname
            else:
                return osp.dirname(fname)

    #---- Tree view widget
    def setup(self,
              name_filters=['*.py', '*.pyw'],
              valid_types=('.py', '.pyw'),
              show_all=False):
        """Setup tree widget"""
        self.setup_view()

        self.set_name_filters(name_filters)
        self.valid_types = valid_types
        self.show_all = show_all

        # Setup context menu
        self.menu = QMenu(self)
        self.common_actions = self.setup_common_actions()

    #---- Context menu
    def setup_common_actions(self):
        """Setup context menu common actions"""
        # Filters
        filters_action = create_action(self,
                                       _("Edit filename filters..."),
                                       None,
                                       get_icon('filter.png'),
                                       triggered=self.edit_filter)
        # Show all files
        all_action = create_action(self,
                                   _("Show all files"),
                                   toggled=self.toggle_all)
        all_action.setChecked(self.show_all)
        self.toggle_all(self.show_all)

        return [filters_action, all_action]

    def edit_filter(self):
        """Edit name filters"""
        filters, valid = QInputDialog.getText(self, _('Edit filename filters'),
                                              _('Name filters:'),
                                              QLineEdit.Normal,
                                              ", ".join(self.name_filters))
        if valid:
            filters = [f.strip() for f in unicode(filters).split(',')]
            self.parent_widget.sig_option_changed.emit('name_filters', filters)
            self.set_name_filters(filters)

    def toggle_all(self, checked):
        """Toggle all files mode"""
        self.parent_widget.sig_option_changed.emit('show_all', checked)
        self.show_all = checked
        self.set_show_all(checked)

    def create_file_new_actions(self, fnames):
        """Return actions for submenu 'New...'"""
        if not fnames:
            return []
        new_file_act = create_action(
            self,
            _("File..."),
            icon='filenew.png',
            triggered=lambda: self.new_file(fnames[-1]))
        new_module_act = create_action(
            self,
            _("Module..."),
            icon='py.png',
            triggered=lambda: self.new_module(fnames[-1]))
        new_folder_act = create_action(
            self,
            _("Folder..."),
            icon='folder_new.png',
            triggered=lambda: self.new_folder(fnames[-1]))
        new_package_act = create_action(
            self,
            _("Package..."),
            icon=get_icon('package_collapsed.png'),
            triggered=lambda: self.new_package(fnames[-1]))
        return [
            new_file_act, new_folder_act, None, new_module_act, new_package_act
        ]

    def create_file_import_actions(self, fnames):
        """Return actions for submenu 'Import...'"""
        return []

    def create_file_manage_actions(self, fnames):
        """Return file management actions"""
        only_files = all([osp.isfile(_fn) for _fn in fnames])
        only_modules = all([
            osp.splitext(_fn)[1] in ('.py', '.pyw', '.ipy') for _fn in fnames
        ])
        only_valid = all(
            [osp.splitext(_fn)[1] in self.valid_types for _fn in fnames])
        run_action = create_action(self,
                                   _("Run"),
                                   icon="run_small.png",
                                   triggered=self.run)
        edit_action = create_action(self,
                                    _("Edit"),
                                    icon="edit.png",
                                    triggered=self.clicked)
        move_action = create_action(self,
                                    _("Move..."),
                                    icon="move.png",
                                    triggered=self.move)
        delete_action = create_action(self,
                                      _("Delete..."),
                                      icon="delete.png",
                                      triggered=self.delete)
        rename_action = create_action(self,
                                      _("Rename..."),
                                      icon="rename.png",
                                      triggered=self.rename)
        open_action = create_action(self, _("Open"), triggered=self.open)

        actions = []
        if only_modules:
            actions.append(run_action)
        if only_valid and only_files:
            actions.append(edit_action)
        else:
            actions.append(open_action)
        actions += [delete_action, rename_action]
        basedir = fixpath(osp.dirname(fnames[0]))
        if all([fixpath(osp.dirname(_fn)) == basedir for _fn in fnames]):
            actions.append(move_action)
        actions += [None]

        # VCS support is quite limited for now, so we are enabling the VCS
        # related actions only when a single file/folder is selected:
        dirname = fnames[0] if osp.isdir(fnames[0]) else osp.dirname(fnames[0])
        if len(fnames) == 1 and vcs.is_vcs_repository(dirname):
            vcs_ci = create_action(self,
                                   _("Commit"),
                                   icon="vcs_commit.png",
                                   triggered=lambda fnames=[dirname]: self.
                                   vcs_command(fnames, tool='commit'))
            vcs_log = create_action(self,
                                    _("Browse repository"),
                                    icon="vcs_browse.png",
                                    triggered=lambda fnames=[dirname]: self.
                                    vcs_command(fnames, tool='browse'))
            actions += [None, vcs_ci, vcs_log]

        return actions

    def create_folder_manage_actions(self, fnames):
        """Return folder management actions"""
        actions = []
        if os.name == 'nt':
            _title = _("Open command prompt here")
        else:
            _title = _("Open terminal here")
        action = create_action(
            self,
            _title,
            icon="cmdprompt.png",
            triggered=lambda fnames=fnames: self.open_terminal(fnames))
        actions.append(action)
        _title = _("Open Python interpreter here")
        action = create_action(
            self,
            _title,
            icon="python.png",
            triggered=lambda fnames=fnames: self.open_interpreter(fnames))
        actions.append(action)
        return actions

    def create_context_menu_actions(self):
        """Create context menu actions"""
        actions = []
        fnames = self.get_selected_filenames()
        new_actions = self.create_file_new_actions(fnames)
        if len(new_actions) > 1:
            # Creating a submenu only if there is more than one entry
            new_act_menu = QMenu(_('New'), self)
            add_actions(new_act_menu, new_actions)
            actions.append(new_act_menu)
        else:
            actions += new_actions
        import_actions = self.create_file_import_actions(fnames)
        if len(import_actions) > 1:
            # Creating a submenu only if there is more than one entry
            import_act_menu = QMenu(_('Import'), self)
            add_actions(import_act_menu, import_actions)
            actions.append(import_act_menu)
        else:
            actions += import_actions
        if actions:
            actions.append(None)
        if fnames:
            actions += self.create_file_manage_actions(fnames)
        if actions:
            actions.append(None)
        if fnames and all([osp.isdir(_fn) for _fn in fnames]):
            actions += self.create_folder_manage_actions(fnames)
        if actions:
            actions.append(None)
        actions += self.common_actions
        return actions

    def update_menu(self):
        """Update context menu"""
        self.menu.clear()
        add_actions(self.menu, self.create_context_menu_actions())

    #---- Events
    def viewportEvent(self, event):
        """Reimplement Qt method"""

        # Prevent Qt from crashing or showing warnings like:
        # "QSortFilterProxyModel: index from wrong model passed to
        # mapFromSource", probably due to the fact that the file system model
        # is being built. See Issue 1250.
        #
        # This workaround was inspired by the following KDE bug:
        # https://bugs.kde.org/show_bug.cgi?id=172198
        #
        # Apparently, this is a bug from Qt itself.
        self.executeDelayedItemsLayout()

        return QTreeView.viewportEvent(self, event)

    def contextMenuEvent(self, event):
        """Override Qt method"""
        self.update_menu()
        self.menu.popup(event.globalPos())

    def keyPressEvent(self, event):
        """Reimplement Qt method"""
        if event.key() in (Qt.Key_Enter, Qt.Key_Return):
            self.clicked()
        elif event.key() == Qt.Key_F2:
            self.rename()
        elif event.key() == Qt.Key_Delete:
            self.delete()
        else:
            QTreeView.keyPressEvent(self, event)

    def mouseDoubleClickEvent(self, event):
        """Reimplement Qt method"""
        QTreeView.mouseDoubleClickEvent(self, event)
        self.clicked()

    def clicked(self):
        """Selected item was double-clicked or enter/return was pressed"""
        fnames = self.get_selected_filenames()
        for fname in fnames:
            if osp.isdir(fname):
                self.directory_clicked(fname)
            else:
                self.open([fname])

    def directory_clicked(self, dirname):
        """Directory was just clicked"""
        pass

    #---- Drag
    def dragEnterEvent(self, event):
        """Drag and Drop - Enter event"""
        event.setAccepted(event.mimeData().hasFormat("text/plain"))

    def dragMoveEvent(self, event):
        """Drag and Drop - Move event"""
        if (event.mimeData().hasFormat("text/plain")):
            event.setDropAction(Qt.MoveAction)
            event.accept()
        else:
            event.ignore()

    def startDrag(self, dropActions):
        """Reimplement Qt Method - handle drag event"""
        data = QMimeData()
        data.setUrls([QUrl(fname) for fname in self.get_selected_filenames()])
        drag = QDrag(self)
        drag.setMimeData(data)
        drag.exec_()

    #---- File/Directory actions
    def open(self, fnames=None):
        """Open files with the appropriate application"""
        if fnames is None:
            fnames = self.get_selected_filenames()
        for fname in fnames:
            ext = osp.splitext(fname)[1]
            if osp.isfile(fname) and ext in self.valid_types:
                self.parent_widget.sig_open_file.emit(fname)
            else:
                self.open_outside_spyder([fname])

    def open_outside_spyder(self, fnames):
        """Open file outside Spyder with the appropriate application
        If this does not work, opening unknown file in Spyder, as text file"""
        for path in sorted(fnames):
            path = file_uri(path)
            ok = programs.start_file(path)
            if not ok:
                self.parent_widget.emit(SIGNAL("edit(QString)"), path)

    def open_terminal(self, fnames):
        """Open terminal"""
        for path in sorted(fnames):
            self.parent_widget.emit(SIGNAL("open_terminal(QString)"), path)

    def open_interpreter(self, fnames):
        """Open interpreter"""
        for path in sorted(fnames):
            self.parent_widget.emit(SIGNAL("open_interpreter(QString)"), path)

    def run(self, fnames=None):
        """Run Python scripts"""
        if fnames is None:
            fnames = self.get_selected_filenames()
        for fname in fnames:
            self.parent_widget.emit(SIGNAL("run(QString)"), fname)

    def remove_tree(self, dirname):
        """Remove whole directory tree
        Reimplemented in project explorer widget"""
        shutil.rmtree(dirname, onerror=misc.onerror)

    def delete_file(self, fname, multiple, yes_to_all):
        """Delete file"""
        if multiple:
            buttons = QMessageBox.Yes|QMessageBox.YesAll| \
                      QMessageBox.No|QMessageBox.Cancel
        else:
            buttons = QMessageBox.Yes | QMessageBox.No
        if yes_to_all is None:
            answer = QMessageBox.warning(
                self, _("Delete"),
                _("Do you really want "
                  "to delete <b>%s</b>?") % osp.basename(fname), buttons)
            if answer == QMessageBox.No:
                return yes_to_all
            elif answer == QMessageBox.Cancel:
                return False
            elif answer == QMessageBox.YesAll:
                yes_to_all = True
        try:
            if osp.isfile(fname):
                misc.remove_file(fname)
                self.parent_widget.emit(SIGNAL("removed(QString)"), fname)
            else:
                self.remove_tree(fname)
                self.parent_widget.emit(SIGNAL("removed_tree(QString)"), fname)
            return yes_to_all
        except EnvironmentError, error:
            action_str = _('delete')
            QMessageBox.critical(
                self, _("Project Explorer"),
                _("<b>Unable to %s <i>%s</i></b>"
                  "<br><br>Error message:<br>%s") %
                (action_str, fname, unicode(error)))
        return False
Example #40
0
class VisionneurImagePourEKD(QScrollArea):
	''' Classe pour l'affichage des images (avec des barres de
	défilement)'''
	def __init__(self, img=None):
		QScrollArea.__init__(self)

		# Déclaration du drapeau: a-t-on chargé un *.gif
		if img and os.path.splitext(img)[1]!=".gif":
			self.gif = 1
		else:
			self.gif = 0
		
		# Facteur de redimensionnement de l'image à afficher par rapport à la taille réelle de l'image
		self.factor = 1
		
		# Variables de paramètres
		self.modeTransformation=Qt.SmoothTransformation
		#self.modeTransformation=Qt.FastTransformation
		
		# widget qui contiendra l'image
		self.imageLabel = QLabel()
		self.imageLabel.setAlignment(Qt.AlignCenter)
		
		self.setBackgroundRole(QPalette.Dark)
		self.setWidget(self.imageLabel)
		# Indispensable pour ne pas avoir d'images tronquées, lors du chargement de nvll img
		self.setWidgetResizable(True)
		
		# Position du curseur dans le QScrollArea au moment du clic de la souris
		self.positionPresseeSourisIni = QPoint()
		# Position du point haut-gauche du QScrollArea par rapport au QPixMap entier au
		# moment du clic de la souris (par la suite appelée "position de la barre de défilement")
        	self.positionBarrePresseeSourisIni = QPoint()
		
		# Création du menu contextuel
		self.menuZoom=QMenu("Zoom")
		
		# Entrée zoom taille réelle
		self.menuTailleReelle=self.menuZoom.addAction(_(u'&Taille Réelle'))
		self.menuTailleReelle.setIcon(QIcon("Icones" + os.sep + "taillereelle.png"))
		self.connect(self.menuTailleReelle, SIGNAL("triggered()"), self.setTailleReelle)
		
		# Entrée zoom taille fenetre
		self.menuTailleFenetre=self.menuZoom.addAction(_(u'&Adapter à la fenêtre'))
		self.menuTailleFenetre.setIcon(QIcon("Icones" + os.sep + "fenetre.png"))
		self.connect(self.menuTailleFenetre, SIGNAL("triggered()"), self.setTailleFenetre)
	
		# Entrée zoom +
		self.menuZoomPlus=self.menuZoom.addAction(_(u'&Zoom Avant'))
		self.menuZoomPlus.setIcon(QIcon("Icones" + os.sep + "zoomplus.png"))
		self.connect(self.menuZoomPlus, SIGNAL("triggered()"), self.zoomAvant)
		
		# Entrée zoom - 
		self.menuZoomMoins=self.menuZoom.addAction(_(u'&Zoom Arrière'))
		self.menuZoomMoins.setIcon(QIcon("Icones" + os.sep + "zoommoins.png"))
		self.connect(self.menuZoomMoins, SIGNAL("triggered()"), self.zoomArriere)
		
		# Entrée mettre en pause/démarrer l'animation du gif
		self.menuStartPauseGif=self.menuZoom.addAction(_(u"Mettre en pause/démarrer l'animation"))
		self.menuStartPauseGif.setIcon(QIcon("Icones" + os.sep + "player_end.png"))
		self.connect(self.menuStartPauseGif, SIGNAL("triggered()"), self.startPauseGif)
			
		# Entrée mettre en pause/démarrer l'animation du gif
		self.menuStopGif=self.menuZoom.addAction(_(u"Arrêter l'animation"))
		self.menuStopGif.setIcon(QIcon("Icones" + os.sep + "player_stop.png"))
		self.connect(self.menuStopGif, SIGNAL("triggered()"), self.stopGif)
		
		# On cache les 2 menus de *.gif si on ne traite pas ce format
		if not self.gif:
			self.menuStartPauseGif.setVisible(False)
			self.menuStopGif.setVisible(False)
		
		# Si une image est en paramètre de classe, on l'affiche directement
		# sinon on pourra toujours l'afficher plus tard en appelant la
		# méthode setImage(), le moment venu
		if img:
			self.setImage(img)
			self.setToolTip(img)
		else:
			# image par défaut
			self.setImage("Icones" + os.sep + "avant-image.png")
			self.setToolTip(_(u"image d'accueil"))
			self.setTailleReelle()
	
	def mousePressEvent(self, event):
		"Menu contextuel et enregistrement de données préparant le déplacement de l'image par pincement"
		
		# Menu contextuel
		if event.button() == Qt.RightButton: 
			self.menuZoom.popup(event.globalPos())
		
		# On enregistre la position du curseur et de la barre de défilement au moment du clic
		elif event.button() == Qt.LeftButton:
			self.positionPresseeSourisIni = QPoint(event.pos())
			self.positionBarrePresseeSourisIni.setX(self.horizontalScrollBar().value())
			self.positionBarrePresseeSourisIni.setY(self.verticalScrollBar().value())
			if PYQT_VERSION_STR >= "4.1.0": 
				# curseur main fermée
				self.setCursor(Qt.ClosedHandCursor)
			else: self.setCursor(Qt.SizeAllCursor)
			event.accept()
	
	def mouseMoveEvent(self, event):
		"Déplacement de l'image dans le QScrollArea quand la souris est pressée"
		
		if self.positionPresseeSourisIni.isNull():
			event.ignore()
			return
		
		# Nouvelles positions de la barre de défilement (selon x et y)
		self.horizontalScrollBar().setValue(self.positionBarrePresseeSourisIni.x() + (self.positionPresseeSourisIni.x() - event.pos().x()))
		self.verticalScrollBar().setValue(self.positionBarrePresseeSourisIni.y() + (self.positionPresseeSourisIni.y() - event.pos().y()))
		self.horizontalScrollBar().update()
		self.verticalScrollBar().update()
		event.accept()
	
	def mouseReleaseEvent(self, event):
		"Réaffichage du curseur classique de la souris"
		self.setCursor(Qt.ArrowCursor)
		event.accept()
	
	def setScaleMode(self, mode):
		"Choix du mode de redimensionnement"
		# Mise à jour du paramètre
		self.modeTransformation=mode
	
	def setTailleFenetre(self):
		"Affichage taille fenetre"
		
		# Gestion de la taille
		#- Si l'image rentre
		##- Si l'image est trop grande
		# On retaille l'image en gardant le ratio entre 
		# le min (si l'image ne rentre pas dans le cadre), le max (sinon) de :
		#         * La largeur de la fenetre
		#         * La largeur de l'image
		#         * La hauteur de la fenetre
		#         * La hauteur de l'image
		if (self.preview.height() < self.height()) and (self.preview.width() < self.width()):
			width=max(self.preview.width(), self.width())
			height=max(self.preview.height(), self.height())
		else :
			width=min(self.preview.width(), self.width())
			height=min(self.preview.height(), self.height())

		if self.gif:
			self.redimGif(width - 5, height - 5)
		else:
			resultat = self.preview.get_preview().scaled(width - 5, height - 5, Qt.KeepAspectRatio, self.modeTransformation)
			debug(u"Preview : %s, taille : %d, %d" % (self.preview.get_imageName(), self.preview.width(), self.preview.height()))
			self.factor = min(float(self.height())/self.preview.height(), float(self.width())/self.preview.width())
		
		#-- On met l'image et on redimensionne le Label pour les images simples
		if not self.gif:
			self.imageLabel.setPixmap(resultat)


			
	
	def setTailleReelle(self):
		"Fonction d'affichage en taille réelle"
		self.preview.origin()

		width, height = self.preview.width(), self.preview.height()

		# On redimensionne le label à la taille de l'image
		if self.gif:
			self.redimGif(width, height)
		else:
			self.imageLabel.setPixmap(self.preview.get_preview())
		self.factor = 1
	
	def zoomAvant(self):
		"Fonction de zoom avant 25%"
		
		# On redimensionne l'image à 125% de la taille actuelle
		factor = 5/4. * self.factor

		width = int(self.preview.width() * factor)
		height = int(self.preview.height() * factor)

		if self.gif:
			self.redimGif(width, height)
		else:
			image = self.preview.get_preview().scaled(width, height, Qt.KeepAspectRatio)
			self.imageLabel.setPixmap(image)
		self.factor = factor
	
	def zoomArriere(self):
		"Fonction de zoom arrière 25%"
		
		# On redimensionne l'image à 75% de la taille actuelle
		factor = 3/4. * self.factor

		width = int(self.preview.width() * factor)
		height = int(self.preview.height() * factor)

		if self.gif:
			self.redimGif(width, height)
		else:
			image = self.preview.get_preview().scaled(width, height, Qt.KeepAspectRatio)
			self.imageLabel.setPixmap(image)
		self.factor = factor
	
	def startPauseGif(self):
		"Démarrer/mettre en pause l'animation de l'image gif"
		if self.movie.state() == QMovie.NotRunning:
			self.movie.start()
		else:
			self.movie.setPaused(self.movie.state() != QMovie.Paused)
	
	def stopGif(self):
		"Arrêter l'animation de l'image gif"
		if self.movie.state() != QMovie.NotRunning:
			self.movie.stop()
	
	def redimGif(self, width, height):
		"""Changer la taille d'affichage du gif en prenant soin d'arrêter et de
		reprendre l'animation si nécessaire.
		Il y a un petit bogue d'affichage sur la redimension (il disparait en changeant
		d'onglet ou de cadre et en revenant.
		"""
		etatInitial = self.movie.state()
		if etatInitial == QMovie.Running:
			self.movie.stop()
		self.movie.setScaledSize(QSize(width, height))
		if etatInitial == QMovie.Running:
			self.movie.start()
		else:
			# On redémarre le gif sinon l'image n'est pas actualisée et reste à la même taille
			self.movie.start()
			self.movie.stop()
	
	def isGif(self):
		"Indique si l'image affichée est un gif. Le test est effectué sur l'extension du fichier"
		return self.gif
	
	def setImage(self, img=None, fauxChemin=None, anim=False):
		"""Fonction de mise en place de l'image.
		Le faux chemin est utile pour dissocier le chemin que verra l'utilisateur
		du chemin de l'image affichée. Ils sont différents uniquement lorsqu'une image
		composite est affichée (cadres masque alpha 3D et image composite).
		L'argument "anim" dit si une image gif doit être animée.
		"""
		
		if not img:
			img = "Icones" + os.sep + "avant-image.png"
			self.setToolTip(_(u"image d'accueil"))
			self.setTailleReelle()
			return
		elif fauxChemin:
			self.setToolTip(fauxChemin)
		else:
			self.setToolTip(img)
		
		# Chargement du gif le cas échéant
		if isinstance(img, str) or isinstance(img, unicode):
			# En général
			extension = os.path.splitext(img)[1]
		elif isinstance(img, QString):
			# Pour selectWidget.py principalement
			extension = "." + QFileInfo(img).suffix()
		if extension == ".gif":
			self.menuStartPauseGif.setVisible(True)
			self.menuStopGif.setVisible(True)
			self.gif = 1
			self.movie = QMovie(img)
			# On démarre le gif de toute façon sinon l'image n'est pas visible
			self.movie.start()
			if not anim:
				self.movie.stop()
			self.imageLabel.setMovie(self.movie)
		else:
			# Pour des images non-gif, on cache les menus d'animation
			self.menuStartPauseGif.setVisible(False)
			self.menuStopGif.setVisible(False)
			self.gif = 0
		

		# Visiblement sous windows la taille du QScrollArea renvoie 0,
		# on passe par l'Objet à l'intérieur pour obtenir la taille de l'image à créer
		self.preview = EkdPreview(img, self.width(), 0, 10, False, True, True) #(chemin, largeur, qualité, cache?, keepRatio?, magnify? )

		# Par défault on charge en taille fenetre
		self.setTailleFenetre()
class RecentProjectsViewer( QWidget ):
    " Recent projects viewer implementation "

    def __init__( self, parent = None ):
        QWidget.__init__( self, parent )

        self.__projectContextItem = None
        self.__fileContextItem = None

        self.upper = self.__createRecentFilesLayout()
        self.lower = self.__createRecentProjectsLayout()
        self.__createProjectPopupMenu()
        self.__createFilePopupMenu()

        layout = QVBoxLayout()
        layout.setContentsMargins( 1, 1, 1, 1 )
        splitter = QSplitter( Qt.Vertical )
        splitter.addWidget( self.upper )
        splitter.addWidget( self.lower )
        splitter.setCollapsible( 0, False )
        splitter.setCollapsible( 1, False )

        layout.addWidget( splitter )
        self.setLayout( layout )

        self.__populateProjects()
        self.__populateFiles()
        self.__updateProjectToolbarButtons()
        self.__updateFileToolbarButtons()

        # Debugging mode support
        self.__debugMode = False
        parent.debugModeChanged.connect( self.__onDebugMode )
        return

    def setTooltips( self, switchOn ):
        " Switches the tooltips mode "
        for index in xrange( 0, self.recentFilesView.topLevelItemCount() ):
            self.recentFilesView.topLevelItem( index ).updateIconAndTooltip()
        for index in xrange( 0, self.projectsView.topLevelItemCount() ):
            self.projectsView.topLevelItem( index ).updateTooltip()
        return

    def __createFilePopupMenu( self ):
        " create the recent files popup menu "
        self.__fileMenu = QMenu( self.recentFilesView )
        self.__openMenuItem = self.__fileMenu.addAction( \
                                PixmapCache().getIcon( 'openitem.png' ),
                                'Open', self.__openFile )
        self.__copyPathFileMenuItem = self.__fileMenu.addAction( \
                        PixmapCache().getIcon( 'copytoclipboard.png' ),
                        'Copy path to clipboard', self.__filePathToClipboard )
        self.__fileMenu.addSeparator()
        self.__delFileMenuItem = self.__fileMenu.addAction( \
                                PixmapCache().getIcon( 'trash.png' ),
                                'Delete from recent',
                                self.__deleteFile )
        self.recentFilesView.setContextMenuPolicy( Qt.CustomContextMenu )
        self.connect( self.recentFilesView,
                      SIGNAL( "customContextMenuRequested(const QPoint &)" ),
                      self.__handleShowFileContextMenu )

        self.connect( GlobalData().project, SIGNAL( 'recentFilesChanged' ),
                      self.__populateFiles )
        return


    def __createProjectPopupMenu( self ):
        " Creates the recent project popup menu "
        self.__projectMenu = QMenu( self.projectsView )
        self.__prjLoadMenuItem = self.__projectMenu.addAction( \
                                PixmapCache().getIcon( 'load.png' ),
                                'Load',
                                self.__loadProject )
        self.__projectMenu.addSeparator()
        self.__propsMenuItem = self.__projectMenu.addAction( \
                                PixmapCache().getIcon( 'smalli.png' ),
                                'Properties',
                                self.__viewProperties )
        self.__prjCopyPathMenuItem = self.__projectMenu.addAction( \
                                PixmapCache().getIcon( 'copytoclipboard.png' ),
                                'Copy path to clipboard',
                                self.__prjPathToClipboard )
        self.__projectMenu.addSeparator()
        self.__delPrjMenuItem = self.__projectMenu.addAction( \
                                PixmapCache().getIcon( 'trash.png' ),
                                'Delete from recent',
                                self.__deleteProject )
        self.projectsView.setContextMenuPolicy( Qt.CustomContextMenu )
        self.connect( self.projectsView,
                      SIGNAL( "customContextMenuRequested(const QPoint &)" ),
                      self.__handleShowPrjContextMenu )

        self.connect( Settings().iInstance, SIGNAL( 'recentListChanged' ),
                      self.__populateProjects )
        GlobalData().project.projectChanged.connect( self.__projectChanged )
        return

    def __createRecentFilesLayout( self ):
        " Creates the upper part - recent files "
        headerFrame = QFrame()
        headerFrame.setFrameStyle( QFrame.StyledPanel )
        headerFrame.setAutoFillBackground( True )
        headerPalette = headerFrame.palette()
        headerBackground = headerPalette.color( QPalette.Background )
        headerBackground.setRgb( min( headerBackground.red() + 30, 255 ),
                                 min( headerBackground.green() + 30, 255 ),
                                 min( headerBackground.blue() + 30, 255 ) )
        headerPalette.setColor( QPalette.Background, headerBackground )
        headerFrame.setPalette( headerPalette )
        headerFrame.setFixedHeight( 24 )

        recentFilesLabel = QLabel()
        recentFilesLabel.setText( "Recent files" )

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins( 3, 0, 0, 0 )
        headerLayout.addWidget( recentFilesLabel )
        headerFrame.setLayout( headerLayout )

        self.recentFilesView = QTreeWidget()
        self.recentFilesView.setAlternatingRowColors( True )
        self.recentFilesView.setRootIsDecorated( False )
        self.recentFilesView.setItemsExpandable( False )
        self.recentFilesView.setSortingEnabled( True )
        self.recentFilesView.setItemDelegate( NoOutlineHeightDelegate( 4 ) )
        self.recentFilesView.setUniformRowHeights( True )

        self.__filesHeaderItem = QTreeWidgetItem( [ "", "File",
                                                    "Absolute path" ] )
        self.recentFilesView.setHeaderItem( self.__filesHeaderItem )
        self.recentFilesView.header().setSortIndicator( 1, Qt.AscendingOrder )

        self.connect( self.recentFilesView,
                      SIGNAL( "itemSelectionChanged()" ),
                      self.__fileSelectionChanged )
        self.connect( self.recentFilesView,
                      SIGNAL( "itemActivated(QTreeWidgetItem *, int)" ),
                      self.__fileActivated )

        # Toolbar part - buttons
        self.openFileButton = QAction( PixmapCache().getIcon( 'openitem.png' ),
                                       'Open the highlighted file', self )
        self.connect( self.openFileButton, SIGNAL( "triggered()" ),
                      self.__openFile )
        self.copyFilePathButton = QAction( \
                        PixmapCache().getIcon( 'copytoclipboard.png' ),
                        'Copy path to clipboard', self )
        self.connect( self.copyFilePathButton, SIGNAL( "triggered()" ),
                      self.__filePathToClipboard )
        spacer = QWidget()
        spacer.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding )
        self.trashFileButton = QAction( PixmapCache().getIcon( 'delitem.png' ),
                                        'Remove selected (not from the disk)',
                                        self )
        self.connect( self.trashFileButton, SIGNAL( "triggered()" ),
                      self.__deleteFile )

        self.upperToolbar = QToolBar()
        self.upperToolbar.setMovable( False )
        self.upperToolbar.setAllowedAreas( Qt.TopToolBarArea )
        self.upperToolbar.setIconSize( QSize( 16, 16 ) )
        self.upperToolbar.setFixedHeight( 28 )
        self.upperToolbar.setContentsMargins( 0, 0, 0, 0 )
        self.upperToolbar.addAction( self.openFileButton )
        self.upperToolbar.addAction( self.copyFilePathButton )
        self.upperToolbar.addWidget( spacer )
        self.upperToolbar.addAction( self.trashFileButton )

        recentFilesLayout = QVBoxLayout()
        recentFilesLayout.setContentsMargins( 0, 0, 0, 0 )
        recentFilesLayout.setSpacing( 0 )
        recentFilesLayout.addWidget( headerFrame )
        recentFilesLayout.addWidget( self.upperToolbar )
        recentFilesLayout.addWidget( self.recentFilesView )

        upperContainer = QWidget()
        upperContainer.setContentsMargins( 0, 0, 0, 0 )
        upperContainer.setLayout( recentFilesLayout )
        return upperContainer

    def getRecentFilesToolbar( self ):
        " Provides a reference to the recent files toolbar "
        return self.upperToolbar

    def __createRecentProjectsLayout( self ):
        " Creates the bottom layout "
        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle( QFrame.StyledPanel )
        self.headerFrame.setAutoFillBackground( True )
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color( QPalette.Background )
        headerBackground.setRgb( min( headerBackground.red() + 30, 255 ),
                                 min( headerBackground.green() + 30, 255 ),
                                 min( headerBackground.blue() + 30, 255 ) )
        headerPalette.setColor( QPalette.Background, headerBackground )
        self.headerFrame.setPalette( headerPalette )
        self.headerFrame.setFixedHeight( 24 )

        recentProjectsLabel = QLabel()
        recentProjectsLabel.setText( "Recent projects" )

        expandingSpacer = QSpacerItem( 10, 10, QSizePolicy.Expanding )

        self.__showHideButton = QToolButton()
        self.__showHideButton.setAutoRaise( True )
        self.__showHideButton.setIcon( PixmapCache().getIcon( 'less.png' ) )
        self.__showHideButton.setFixedSize( 20, 20 )
        self.__showHideButton.setToolTip( "Hide recent projects list" )
        self.__showHideButton.setFocusPolicy( Qt.NoFocus )
        self.connect( self.__showHideButton, SIGNAL( 'clicked()' ),
                      self.__onShowHide )

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins( 3, 0, 0, 0 )
        headerLayout.addWidget( recentProjectsLabel )
        headerLayout.addSpacerItem( expandingSpacer )
        headerLayout.addWidget( self.__showHideButton )
        self.headerFrame.setLayout( headerLayout )

        # Toolbar part - buttons
        self.loadButton = QAction( PixmapCache().getIcon( 'load.png' ),
                                   'Load the highlighted project', self )
        self.connect( self.loadButton, SIGNAL( "triggered()" ),
                      self.__loadProject )
        self.propertiesButton = QAction( PixmapCache().getIcon( 'smalli.png' ),
                                         'Show the highlighted project ' \
                                         'properties', self )
        self.connect( self.propertiesButton, SIGNAL( "triggered()" ),
                      self.__viewProperties )
        self.copyPrjPathButton = QAction( \
                        PixmapCache().getIcon( 'copytoclipboard.png' ),
                        'Copy path to clipboard', self )
        self.connect( self.copyPrjPathButton, SIGNAL( "triggered()" ),
                      self.__prjPathToClipboard )
        spacer = QWidget()
        spacer.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding )
        self.trashButton = QAction( PixmapCache().getIcon( 'delitem.png' ),
                                    'Remove selected (not from the disk)',
                                    self )
        self.connect( self.trashButton, SIGNAL( "triggered()" ),
                      self.__deleteProject )

        self.lowerToolbar = QToolBar()
        self.lowerToolbar.setMovable( False )
        self.lowerToolbar.setAllowedAreas( Qt.TopToolBarArea )
        self.lowerToolbar.setIconSize( QSize( 16, 16 ) )
        self.lowerToolbar.setFixedHeight( 28 )
        self.lowerToolbar.setContentsMargins( 0, 0, 0, 0 )
        self.lowerToolbar.addAction( self.loadButton )
        self.lowerToolbar.addAction( self.propertiesButton )
        self.lowerToolbar.addAction( self.copyPrjPathButton )
        self.lowerToolbar.addWidget( spacer )
        self.lowerToolbar.addAction( self.trashButton )

        self.projectsView = QTreeWidget()
        self.projectsView.setAlternatingRowColors( True )
        self.projectsView.setRootIsDecorated( False )
        self.projectsView.setItemsExpandable( False )
        self.projectsView.setSortingEnabled( True )
        self.projectsView.setItemDelegate( NoOutlineHeightDelegate( 4 ) )
        self.projectsView.setUniformRowHeights( True )

        self.__projectsHeaderItem = QTreeWidgetItem( [ "", "Project",
                                                       "Absolute path" ] )
        self.projectsView.setHeaderItem( self.__projectsHeaderItem )

        self.projectsView.header().setSortIndicator( 1, Qt.AscendingOrder )
        self.connect( self.projectsView,
                      SIGNAL( "itemActivated(QTreeWidgetItem *, int)" ),
                      self.__projectActivated )
        self.connect( self.projectsView,
                      SIGNAL( "itemSelectionChanged()" ),
                      self.__projectSelectionChanged )

        recentProjectsLayout = QVBoxLayout()
        recentProjectsLayout.setContentsMargins( 0, 0, 0, 0 )
        recentProjectsLayout.setSpacing( 0 )
        recentProjectsLayout.addWidget( self.headerFrame )
        recentProjectsLayout.addWidget( self.lowerToolbar )
        recentProjectsLayout.addWidget( self.projectsView )

        lowerContainer = QWidget()
        lowerContainer.setContentsMargins( 0, 0, 0, 0 )
        lowerContainer.setLayout( recentProjectsLayout )
        return lowerContainer

    def getRecentProjectsToolbar( self ):
        " Provides a reference to the projects toolbar "
        return self.lowerToolbar

    def __projectSelectionChanged( self ):
        " Handles the projects changed selection "
        selected = list( self.projectsView.selectedItems() )

        if selected:
            self.__projectContextItem = selected[ 0 ]
        else:
            self.__projectContextItem = None

        self.__updateProjectToolbarButtons()
        return

    def __fileSelectionChanged( self ):
        " Handles the files changed selection "
        selected = list( self.recentFilesView.selectedItems() )

        if selected:
            self.__fileContextItem = selected[ 0 ]
        else:
            self.__fileContextItem = None
        self.__updateFileToolbarButtons()
        return

    def __updateProjectToolbarButtons( self ):
        " Updates the toolbar buttons depending on the __projectContextItem "
        if self.__projectContextItem is None:
            self.loadButton.setEnabled( False )
            self.propertiesButton.setEnabled( False )
            self.copyPrjPathButton.setEnabled( False )
            self.trashButton.setEnabled( False )
        else:
            enabled = self.__projectContextItem.isValid()
            isCurrentProject = self.__projectContextItem.isCurrent()

            self.propertiesButton.setEnabled( enabled )
            self.copyPrjPathButton.setEnabled( True )
            self.loadButton.setEnabled( enabled and
                                        not isCurrentProject and
                                        not self.__debugMode )
            self.trashButton.setEnabled( not isCurrentProject )
        return

    def __updateFileToolbarButtons( self ):
        " Updates the toolbar buttons depending on the __fileContextItem "
        enabled = self.__fileContextItem is not None
        self.openFileButton.setEnabled( enabled )
        self.copyFilePathButton.setEnabled( enabled )
        self.trashFileButton.setEnabled( enabled )
        return

    def __handleShowPrjContextMenu( self, coord ):
        " Show the project item context menu "
        self.__projectContextItem = self.projectsView.itemAt( coord )
        if self.__projectContextItem is None:
            return

        enabled = self.__projectContextItem.isValid()
        isCurrentProject = self.__projectContextItem.isCurrent()

        self.__propsMenuItem.setEnabled( enabled )
        self.__delPrjMenuItem.setEnabled( not isCurrentProject )
#        fName = self.__projectContextItem.getFilename()
        self.__prjLoadMenuItem.setEnabled( enabled and \
                                           not isCurrentProject and \
                                           not self.__debugMode )

        self.__projectMenu.popup( QCursor.pos() )
        return

    def __sortProjects( self ):
        " Sort the project items "
        self.projectsView.sortItems( \
                self.projectsView.sortColumn(),
                self.projectsView.header().sortIndicatorOrder() )
        return

    def __sortFiles( self ):
        " Sort the file items "
        self.recentFilesView.sortItems( \
                self.recentFilesView.sortColumn(),
                self.recentFilesView.header().sortIndicatorOrder() )
        return

    def __resizeProjectColumns( self ):
        """ Resize the projects list columns """
        self.projectsView.header().setStretchLastSection( True )
        self.projectsView.header().resizeSections( \
                                    QHeaderView.ResizeToContents )
        self.projectsView.header().resizeSection( 0, 22 )
        self.projectsView.header().setResizeMode( 0, QHeaderView.Fixed )
        return

    def __resizeFileColumns( self ):
        " Resize the files list columns "
        self.recentFilesView.header().setStretchLastSection( True )
        self.recentFilesView.header().resizeSections( \
                                    QHeaderView.ResizeToContents )
        self.recentFilesView.header().resizeSection( 0, 22 )
        self.recentFilesView.header().setResizeMode( 0, QHeaderView.Fixed )
        return

    def __projectActivated( self, item, column ):
        " Handles the double click (or Enter) on the item "
        self.__projectContextItem = item
        self.__loadProject()
        return

    def __fileActivated( self, item, column ):
        " Handles the double click (or Enter) on a file item "
        self.__fileContextItem = item
        self.__openFile()
        return

    def __viewProperties( self ):
        " Handles the 'view properties' context menu item "
        if self.__projectContextItem is None:
            return
        if not self.__projectContextItem.isValid():
            return

        if self.__projectContextItem.isCurrent():
            # This is the current project - it can be edited
            project = GlobalData().project
            dialog = ProjectPropertiesDialog( project )
            if dialog.exec_() == QDialog.Accepted:
                importDirs = []
                for index in xrange( dialog.importDirList.count() ):
                    importDirs.append( dialog.importDirList.item( index ).text() )

                scriptName = dialog.scriptEdit.text().strip()
                relativePath = relpath( scriptName, project.getProjectDir() )
                if not relativePath.startswith( '..' ):
                    scriptName = relativePath

                project.updateProperties(
                    scriptName, importDirs,
                    dialog.creationDateEdit.text().strip(),
                    dialog.authorEdit.text().strip(),
                    dialog.licenseEdit.text().strip(),
                    dialog.copyrightEdit.text().strip(),
                    dialog.versionEdit.text().strip(),
                    dialog.emailEdit.text().strip(),
                    dialog.descriptionEdit.toPlainText().strip() )
        else:
            # This is not the current project - it can be viewed
            fName = self.__projectContextItem.getFilename()
            dialog = ProjectPropertiesDialog( fName )
            dialog.exec_()
        return

    def __deleteProject( self ):
        " Handles the 'delete from recent' context menu item "
        if self.__projectContextItem is None:
            return

        # Removal from the visible list is done via a signal which comes back
        # from settings
        fName = self.__projectContextItem.getFilename()
        Settings().deleteRecentProject( fName )
        return

    def __loadProject( self ):
        " handles 'Load' context menu item "
        if self.__projectContextItem is None:
            return
        if not self.__projectContextItem.isValid():
            return
        if self.__debugMode:
            return

        projectFileName = self.__projectContextItem.getFilename()

        if self.__projectContextItem.isCurrent():
            GlobalData().mainWindow.openFile( projectFileName, -1 )
            return  # This is the current project, open for text editing

        QApplication.processEvents()
        QApplication.setOverrideCursor( QCursor( Qt.WaitCursor ) )
        if os.path.exists( projectFileName ):
            mainWin = GlobalData().mainWindow
            editorsManager = mainWin.editorsManagerWidget.editorsManager
            if editorsManager.closeRequest():
                prj = GlobalData().project
                prj.setTabsStatus( editorsManager.getTabsStatus() )
                editorsManager.closeAll()
                prj.loadProject( projectFileName )
                mainWin.activateProjectTab()
        else:
            logging.error( "The project " + \
                           os.path.basename( projectFileName ) + \
                           " disappeared from the file system." )
            self.__populateProjects()
        QApplication.restoreOverrideCursor()
        return

    def __populateProjects( self ):
        " Populates the recent projects "
        self.projectsView.clear()
        for item in Settings().recentProjects:
            self.projectsView.addTopLevelItem( RecentProjectViewItem( item ) )

        self.__sortProjects()
        self.__resizeProjectColumns()
        self.__updateProjectToolbarButtons()
        return

    def __populateFiles( self ):
        " Populates the recent files "
        self.recentFilesView.clear()
        for path in GlobalData().project.recentFiles:
            self.recentFilesView.addTopLevelItem( RecentFileViewItem( path ) )

        self.__sortFiles()
        self.__resizeFileColumns()
        self.__updateFileToolbarButtons()
        return

    def __projectChanged( self, what ):
        " Triggered when the current project is changed "
        if what == CodimensionProject.CompleteProject:
            self.__populateProjects()
            self.__populateFiles()
            return

        if what == CodimensionProject.Properties:
            # Update the corresponding tooltip
            items = self.projectsView.findItems( GlobalData().project.fileName,
                                                 Qt.MatchExactly, 2 )
            if len( items ) != 1:
                logging.error( "Unexpected number of matched projects: " + \
                               str( len( items ) ) )
                return

            items[ 0 ].updateTooltip()
            return

    def __openFile( self ):
        " Handles 'open' file menu item "
        self.__fileContextItem.updateIconAndTooltip()
        fName = self.__fileContextItem.getFilename()

        if not self.__fileContextItem.isValid():
            logging.warning( "Cannot open " + fName )
            return

        fileType = detectFileType( fName )
        if fileType == PixmapFileType:
            GlobalData().mainWindow.openPixmapFile( fName )
            return

        GlobalData().mainWindow.openFile( fName, -1 )
        return

    def __deleteFile( self ):
        " Handles 'delete from recent' file menu item "
        self.removeRecentFile( self.__fileContextItem.getFilename() )
        return

    def __handleShowFileContextMenu( self, coord ):
        " File context menu "
        self.__fileContextItem = self.recentFilesView.itemAt( coord )
        if self.__fileContextItem is not None:
            self.__fileMenu.popup( QCursor.pos() )
        return

    def __filePathToClipboard( self ):
        " Copies the file item path to the clipboard "
        if self.__fileContextItem is not None:
            QApplication.clipboard().setText( \
                    self.__fileContextItem.getFilename() )
        return

    def __prjPathToClipboard( self ):
        " Copies the project item path to the clipboard "
        if self.__projectContextItem is not None:
            QApplication.clipboard().setText( \
                    self.__projectContextItem.getFilename() )
        return

    def onFileUpdated( self, fileName, uuid ):
        " Triggered when the file is updated: python or project "
        realPath = os.path.realpath( fileName )

        count = self.recentFilesView.topLevelItemCount()
        for index in xrange( 0, count ):
            item = self.recentFilesView.topLevelItem( index )

            itemRealPath = os.path.realpath( item.getFilename() )
            if realPath == itemRealPath:
                item.updateIconAndTooltip()
                break

        for index in xrange( 0, self.projectsView.topLevelItemCount() ):
            item = self.projectsView.topLevelItem( index )

            itemRealPath = os.path.realpath( item.getFilename() )
            if realPath == itemRealPath:
                item.updateTooltip()
                break
        return

    def __onShowHide( self ):
        " Triggered when show/hide button is clicked "
        if self.projectsView.isVisible():
            self.projectsView.setVisible( False )
            self.lowerToolbar.setVisible( False )
            self.__showHideButton.setIcon( PixmapCache().getIcon( 'more.png' ) )
            self.__showHideButton.setToolTip( "Show recent projects list" )

            self.__minH = self.lower.minimumHeight()
            self.__maxH = self.lower.maximumHeight()

            self.lower.setMinimumHeight( self.headerFrame.height() )
            self.lower.setMaximumHeight( self.headerFrame.height() )
        else:
            self.projectsView.setVisible( True )
            self.lowerToolbar.setVisible( True )
            self.__showHideButton.setIcon( PixmapCache().getIcon( 'less.png' ) )
            self.__showHideButton.setToolTip( "Hide recent projects list" )

            self.lower.setMinimumHeight( self.__minH )
            self.lower.setMaximumHeight( self.__maxH )
        return

    def __onDebugMode( self, newState ):
        " Triggered when debug mode has changed "
        self.__debugMode = newState

        # Disable the load project button
        self.__updateProjectToolbarButtons()
        return

    def removeRecentFile( self, fName ):
        " Removes a single file from the recent files list "
        GlobalData().project.removeRecentFile( fName )

        for index in xrange( self.recentFilesView.topLevelItemCount() ):
            candidate = self.recentFilesView.topLevelItem( index )
            if candidate.getFilename() == fName:
                self.recentFilesView.takeTopLevelItem( index )
                return
        return
 def on_neoUnitList_customContextMenuRequested(self, pos):
     if not self.neoUnitList.selectedIndexes():
         return
     context_menu = QMenu(self)
     context_menu.addActions(self._context_actions(self.neoUnitList))
     context_menu.popup(self.neoUnitList.mapToGlobal(pos))
Example #43
0
class FileDialog(QDialog, Ui_FileDialog):
    """
  FileDialog class
  """

    #############################################################################
    def __init__(self, parent=None):
        """
    initialize the widget
    """
        QDialog.__init__(self, parent)
        Ui_FileDialog.__init__(self)
        self.setupUi(self)
        #flags = 0
        #flags = Qt.Window | Qt.WindowMinimizeButtonHint;
        #self.setWindowFlags( flags )
        self.hideTckFilter()
        self.__controler = ControlerFileDialog(self, parent.getControler())
        self.connect(self.closeButton, SIGNAL("clicked()"),
                     self.__controler.close)
        self.connect(self.saveButton, SIGNAL("clicked()"),
                     self.__controler.save)
        self.connect(self.advancedSave, SIGNAL("clicked()"),
                     self.__controler.advancedSave)
        self.connect(self.nextButton, SIGNAL("clicked()"),
                     self.__controler.next)

        self.__model = {}
        self.__path = None
        self.__fileExtension = None
        self.__popUp = QMenu(self.tableView)

        self.__jobAction = QAction(self.tr("Job Info"), self.tableView)
        self.connect(self.__jobAction, SIGNAL("triggered()"),
                     self.__controler.jobinfo)
        self.__popUp.addAction(self.__jobAction)

        self.__ancesstorsAction = QAction(self.tr("Get Anccestors"),
                                          self.tableView)
        self.connect(self.__ancesstorsAction, SIGNAL("triggered()"),
                     self.__controler.getancesstots)
        self.__popUp.addAction(self.__ancesstorsAction)

        self.__loginfoAction = QAction(self.tr("Logginig informations"),
                                       self.tableView)
        self.connect(self.__loginfoAction, SIGNAL("triggered()"),
                     self.__controler.loggininginfo)
        self.__popUp.addAction(self.__loginfoAction)

        self.__copyAction = QAction(self.tr("Copy data"), self.tableView)
        self.connect(self.__copyAction, SIGNAL("triggered()"),
                     self.__controler.copy)
        self.__popUp.addAction(self.__copyAction)

        self.tableView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.connect(self.tableView,
                     SIGNAL('customContextMenuRequested(QPoint)'),
                     self.popUpMenu)

        self.__advancedSave = AdvancedSave(self)
        self.__advancedSave.setFocus()

        self.__controler.addChild('AdvancedSave',
                                  self.__advancedSave.getControler())

        self.__historyDialog = HistoryDialog(self)
        self.__controler.addChild('HistoryDialog',
                                  self.__historyDialog.getControler())

        self.connect(self.tckcombo, SIGNAL('currentIndexChanged(QString)'),
                     self.getControler().tckChanged)
        self.__proxy = QSortFilterProxyModel()

        self.connect(self.tckButton, SIGNAL("clicked()"),
                     self.__controler.tckButtonPressed)
        self.connect(self.tckcloseButton, SIGNAL("clicked()"),
                     self.__controler.hideFilterWidget)

        self.filterWidget.setupControler(self)
        self.__controler.addChild('TckFilterWidget',
                                  self.filterWidget.getControler())

    #############################################################################
    def closeEvent(self, event):
        """handles the close action"""
        gLogger.debug(event)
        self.getControler().close()

    #############################################################################
    def getControler(self):
        """returns the controller"""
        return self.__controler

    #############################################################################
    def setModel(self, model):
        """sets the model"""
        self.__model = model

    def updateModel(self, model):
        """updates the model in case of change"""
        self.__model.update(model)

    #############################################################################
    def getModel(self):
        """returns the model"""
        return self.__model

    #############################################################################
    def setPath(self, path):
        """sets the path"""
        self.__path = path

    #############################################################################
    def getPath(self):
        """returns the path"""
        return self.__path

    #############################################################################
    def showNumberOfEvents(self, number):
        """shows the number of events"""
        self.lineEdit_2.setText(str(number))

    #############################################################################
    def showNumberOfFiles(self, number):
        """shows the number of files"""
        self.lineEdit.setText(str(number))

    #############################################################################
    def showEventInputStat(self, number):
        """shows the number of processed input events"""
        self.alleventinputstat.setText(str(number))

    #############################################################################
    def showFilesSize(self, number):
        """shows the size of the files"""
        self.lineEdit_5.setText(str(number) + '  GB')

    #############################################################################
    def showSelectedNumberOfEvents(self, number):
        """shows the selected number of events"""
        self.lineEdit_4.setText(str(number))

    #############################################################################
    def showSelectedEventInputStat(self, number):
        """shows the selected processed input events"""
        self.eventInputstat.setText(str(number))

    #############################################################################
    def showSelectedNumberOfFiles(self, number):
        """shoes the selected number of files"""
        self.lineEdit_3.setText(str(number))

    #############################################################################
    def showSelectedFileSize(self, number):
        """shows the selected file size"""
        self.lineEdit_6.setText(str(number) + '  GB')

    #############################################################################
    def showTotalLuminosity(self, number):
        """shows the total luminosity"""
        self.alltotalluminosity.setText(str(number))

    #############################################################################
    def showSelectedTotalLuminosity(self, number):
        """selected total luminosity"""
        self.totalluminosity.setText(str(number))

    #############################################################################
    def showLuminosity(self, number):
        """luminosity"""
        self.allluminosity.setText(str(number))

    #############################################################################
    def showSelectedLuminosity(self, number):
        """selected luminosity"""
        self.luminosity.setText(str(number))

    #############################################################################
    def showError(self, message):
        """shows the message as an ERROR"""
        QMessageBox.critical(self, "ERROR", message, QMessageBox.Ok)

    #############################################################################
    def showData(self, data):
        """shows the files in the table widget"""
        self.waitCursor()

        tabledata = []

        header = [
            'FileName', 'EventStat', 'FileSize', 'CreationDate', 'JobStart',
            'JobEnd', 'WorkerNode', 'RunNumber', 'FillNumber', 'FullStat',
            'DataqualityFlag', 'EventInputStat', 'TotalLuminosity',
            'Luminosity', 'InstLuminosity', 'TCK'
        ]
        data.update(self.__model)
        keys = data.keys()
        keys.sort()
        for item in keys:
            lfn = data[item]
            i = []
            for info in header:
                value = lfn[info]
                if value == None:
                    value = ''
                i += [value]
            tabledata += [i]

        if len(tabledata) > 0:
            self.filltable(header, tabledata)
        self.arrowCursor()
        return True

    #############################################################################
    def filltable(self, header, tabledata):
        """ fill the table widget"""
        # set the table model

        tm = TableModel(tabledata, header, self)

        self.__proxy.setSourceModel(tm)

        self.tableView.setModel(self.__proxy)
        self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection)

        self.tableView.setAlternatingRowColors(True)

        sm = self.tableView.selectionModel()
        self.connect(
            sm, SIGNAL("selectionChanged(QItemSelection, QItemSelection)"),
            self.__controler.selection)

        # set the minimum size
        self.setMinimumSize(400, 300)

        # hide grid
        self.tableView.setShowGrid(True)

        # set the font
        #font = QFont("Courier New", 12)
        #self.tableView.setFont(font)

        # hide vertical header
        vh = self.tableView.verticalHeader()
        vh.setVisible(True)

        # set horizontal header properties
        hh = self.tableView.horizontalHeader()
        hh.setStretchLastSection(True)

        # set column width to fit contents
        self.tableView.resizeColumnsToContents()
        self.tableView.setSortingEnabled(True)

        # set row height
        nrows = len(tabledata)
        for row in xrange(nrows):
            self.tableView.setRowHeight(row, 18)

        self.__proxy.sort(0, Qt.AscendingOrder)
        # enable sorting
        # this doesn't work
        #tv.setSortingEnabled(True)

    #############################################################################
    def saveAs(self, filename=''):
        """saves the selected files"""
        saveDialog = QFileDialog(
            self, 'Feicim Save file(s) dialog', QDir.currentPath(),
            'Python option(*.py);;Option file (*.opts);;Text file (*.txt);;CSV (*.csv)'
        )
        saveDialog.setAcceptMode(QFileDialog.AcceptSave)

        saveDialog.selectFile(filename)
        #self.connect(saveDialog, SIGNAL("filterSelected(const QString &)"),self.filter )
        ##saveDialog.setDirectory (QDir.currentPath())
        #filters = ['Option file (*.opts)' ,'Pool xml file (*.xml)','*.txt']
        #filters = ['Option file (*.opts)','*.py','*.txt']
        #saveDialog.setFilter(';;'.join(filters))
        #saveDialog.setFilter('Option file (*.opts);;Text file (*.txt);;Python option')
        #saveDialog.setFileMode(QFileDialog.AnyFile)
        #saveDialog.setViewMode(QFileDialog.Detail)

        ext = ''
        if saveDialog.exec_():
            filename = str(saveDialog.selectedFiles()[0])
            ext = saveDialog.selectedFilter()
            if 'Text file (*.txt)' in ext:
                if not filename.endswith('.txt'):
                    filename += '.txt'
            elif 'Option file (*.opts)' in ext:
                if not filename.endswith('.opts'):
                    filename += '.opts'
            elif 'Python option(*.py)' in ext:
                if not filename.endswith('.py'):
                    filename += '.py'
            elif 'CSV (*.csv)' in ext:
                if not filename.endswith('.csv'):
                    filename += '.csv'
            try:
                open(filename)
            except IOError:
                pass
            else:
                response = QMessageBox.warning(self, "File dialog",
                                               "File exists, overwrite?",
                                               QMessageBox.Ok, QMessageBox.No)
                if response == QMessageBox.No:
                    filename = ''
        if filename == '':
            return '', ''

        return filename, ext

    #############################################################################
    def popUpMenu(self):
        """shows the popup menu"""
        self.__popUp.popup(QCursor.pos())

    #############################################################################
    def showSelection(self, in_dict):
        """ shows the Bookkeeping query, the selected dataset"""

        if in_dict.has_key('ConfigName'):
            self.configname.setText(in_dict["ConfigName"])

        if in_dict.has_key('ConfigVersion'):
            self.configversion.setText(in_dict["ConfigVersion"])

        if in_dict.has_key('ConditionDescription'):
            self.simulation.setText(in_dict["ConditionDescription"])

        if in_dict.has_key('ProcessingPass'):
            self.processing.setText(in_dict["ProcessingPass"])

        if in_dict.has_key('EventTypeId'):
            self.eventtype.setText(in_dict["EventTypeId"])

        if in_dict.has_key('Production'):
            self.production.setText('')

        if in_dict.has_key('FileType'):
            self.filetype.setText(in_dict["FileType"])

        self.progrnameandversion.setText('')

    #############################################################################
    def clearTable(self):
        """clear the elements from the table"""
        #self.tableView().clear()
        self.__model = {}

    #############################################################################
    def fillTckFilter(self, data):
        """fills the tck combo box"""
        tcks = data + ['All']

        self.tckcombo.clear()
        j = 0
        for i in tcks:
            self.tckcombo.addItem(i, QVariant(i))
            if i == 'All':
                self.tckcombo.setCurrentIndex(j)
            j += 1
        #self.tckcombo.view().setSelectionMode(QAbstractItemView.MultiSelection)

    #############################################################################
    def applyFilter(self, data):
        """performs filter over the files"""
        if data == 'All':
            gLogger.debug('applyFilter-ALL')
            self.__proxy.clear()
            self.__proxy.invalidateFilter()
            filterCondition = "^\\S+$"
            gLogger.debug('Filter condition:' + filterCondition)
            self.__proxy.setFilterKeyColumn(15)
            self.__proxy.setFilterRegExp(filterCondition)
            for row in xrange(self.__proxy.rowCount()):
                self.tableView.setRowHeight(row, 18)
        else:
            gLogger.debug('applyFilter-Selected')
            self.__proxy.setFilterKeyColumn(15)
            filterCondition = '%s' % (data)
            gLogger.debug('Filter condition:' + filterCondition)
            self.__proxy.setFilterRegExp(filterCondition)
            for row in xrange(self.__proxy.rowCount()):
                self.tableView.setRowHeight(row, 18)

    def applyListFilter(self, data):
        """specific filter"""
        gLogger.debug('applyListFilter')
        filterCondition = '\\b'
        cond = '('
        for i in data:
            cond += i
            cond += '|'
        cond = cond[:-1]
        filterCondition += cond + ')\\b'
        gLogger.debug('Filter condition:' + filterCondition)
        self.__proxy.setFilterKeyColumn(15)
        self.__proxy.setFilterRegExp(filterCondition)
        for row in xrange(self.__proxy.rowCount()):
            self.tableView.setRowHeight(row, 18)

    #############################################################################
    def showTckFilter(self):
        """shows the tcks"""
        self.tckButton.hide()
        self.tckcloseButton.show()
        self.tckcombo.hide()
        self.filterWidget.show()

    #############################################################################
    def hideTckFilter(self):
        """hides the tcks"""
        self.tckButton.show()
        self.tckcloseButton.hide()
        self.tckcombo.show()
        self.filterWidget.hide()

    #############################################################################
    def getLFNs(self):
        """returns the lfns"""
        lfns = []
        for row in xrange(self.__proxy.rowCount()):
            index = self.__proxy.index(
                row, 0)  # this add the files to my selected list
            lfns += [str(self.__proxy.data(index).toString())]
        return lfns

    #############################################################################
    def waitCursor(self):
        """shows the wait cursor"""
        self.setCursor(Qt.WaitCursor)

    #############################################################################
    def arrowCursor(self):
        """shows the normal cursor"""
        self.setCursor(Qt.ArrowCursor)
Example #44
0
class Player(QWidget):
    def __init__(self,app):
        super(Player,self).__init__()
        self.mpd   = app.mpd
        self.ih    = app.imagehelper
        self.timer = None
        self.initGUI()
        self.initState()
        
    def initGUI(self):
        self.setWindowTitle(QApplication.applicationName())
        self.fmt = QFontMetrics(QFont())
        layout = QVBoxLayout()
        
        toplayout = QHBoxLayout()
        currentLayout = QGridLayout()
        currentLayout.setContentsMargins(0,20,0,20)
        currentLayout.setHorizontalSpacing(100)
        currentLayout.setVerticalSpacing(20)
        # current song information
        currentLayout.addWidget(QLabel("<b>Artist</b>"),1,0)
        self.artist = QLabel()
        currentLayout.addWidget(self.artist,1,1)
        currentLayout.addWidget(QLabel("<b>Title</b>"),2,0)
        self.title  = QLabel()
        currentLayout.addWidget(self.title,2,1)
        currentLayout.addWidget(QLabel("<b>Albumartist</b>"),3,0)
        self.albumartist = QLabel()
        currentLayout.addWidget(self.albumartist,3,1)
        currentLayout.addWidget(QLabel("<b>Album</b>"),4,0)
        self.album  = QLabel()
        currentLayout.addWidget(self.album,4,1)
        # playlist and song position
        self.playlistposition = QLabel()
        currentLayout.addWidget(self.playlistposition,5,0)
        poslayout = QHBoxLayout()
        poslayout.setSpacing(10)
        self.time = QLabel("00:00")
        poslayout.addWidget(self.time)
        self.position = QSlider(Qt.Horizontal)
        self.position.setTracking(False)
        self.position.setSingleStep(10)
        self.position.sliderReleased.connect( self.seek)
        self.position.sliderMoved.connect(
            lambda x: self.time.setText(self.mpd.timeString(x)))
        poslayout.addWidget(self.position)
        self.length = QLabel("00:00")
        poslayout.addWidget(self.length)
        currentLayout.addLayout(poslayout,5,1)
        toplayout.addLayout(currentLayout)
        layout.addLayout(toplayout)
        layout.addStretch(1)
        
        self.settingsWidget = QMenu()
        self.consumeBtn = self.settingsWidget.addAction("Consume")
        self.consumeBtn.setCheckable(True)
        self.consumeBtn.triggered.connect( lambda x: self.mpd.consume(int(x)))
        self.singleBtn  = self.settingsWidget.addAction("Single")
        self.singleBtn.setCheckable(True)
        self.singleBtn.triggered.connect( lambda x: self.mpd.single(int(x)))
        
        toolLayout = QHBoxLayout()
        self.settingsBtn = QToolButton()
        self.settingsBtn.setFixedSize(64,64)
        self.settingsBtn.setIcon( self.ih.settingsButton)
        self.settingsBtn.clicked.connect(self.showAdditionalControls)
        toolLayout.addWidget(self.settingsBtn)

        
        toolWidget = QStackedWidget()
        transpWidget = QWidget()
        transpLayout = QHBoxLayout()
        self.prevBtn = self.createButton(
            self.ih.prevButton, self.ih.prevButtonPressed)
        self.prevBtn.clicked.connect( lambda x: self.mpd.previous())
        transpLayout.addWidget(self.prevBtn)
        self.playBtn = self.createCheckButton(
            self.ih.playButton, self.ih.pauseButton)
        self.playBtn.clicked.connect( self.playPressed)
        transpLayout.addWidget(self.playBtn)
        self.stopBtn = self.createButton(
            self.ih.stopButton, self.ih.stopButtonPressed)
        self.stopBtn.clicked.connect( lambda x: self.mpd.stop())
        transpLayout.addWidget(self.stopBtn)
        self.nextBtn = self.createButton(
            self.ih.nextButton, self.ih.nextButtonPressed)
        self.nextBtn.clicked.connect( lambda x: self.mpd.next())
        transpLayout.addWidget(self.nextBtn)
        self.shuffleBtn = self.createCheckButton(
            self.ih.shuffleButton, self.ih.shuffleButtonPressed)
        self.shuffleBtn.toggled.connect(
            lambda x: self.mpd.random(1) if x else self.mpd.random(0))
        transpLayout.addWidget(self.shuffleBtn)
        self.repeatBtn = self.createCheckButton(
            self.ih.repeatButton, self.ih.repeatButtonPressed)
        self.repeatBtn.toggled.connect(
            lambda x: self.mpd.repeat(1) if x else self.mpd.repeat(0))
        transpLayout.addWidget(self.repeatBtn)
        transpLayout.addSpacing(64)
        transpWidget.setLayout(transpLayout)
        toolWidget.addWidget( transpWidget)
        
        self.volume = QSlider(Qt.Horizontal)
        self.volume.valueChanged.connect(self.mpd.setvol)
        toolWidget.addWidget(self.volume)
        
        toolLayout.addWidget(toolWidget)
        self.volumeBtn = QToolButton()
        self.volumeBtn.setFixedSize(64,64)
        self.volumeBtn.setCheckable(True)
        self.volumeBtn.setIcon( self.ih.volumeButton)
        self.volumeBtn.toggled.connect(
            lambda x: toolWidget.setCurrentIndex(x))
        toolLayout.addWidget(self.volumeBtn)
        layout.addLayout(toolLayout)
        self.setLayout(layout)

    def showAdditionalControls(self):
        pos = self.settingsBtn.pos()
        pos.setY( pos.y()-self.settingsWidget.sizeHint().height())
        self.settingsWidget.popup( self.mapToGlobal(pos))

    def createCheckButton(self, offIcon, onIcon):
        i = QIcon()
        i.addPixmap( offIcon.pixmap(64), QIcon.Normal, QIcon.Off)
        i.addPixmap(  onIcon.pixmap(64), QIcon.Normal, QIcon.On)
        b = QToolButton()
        b.setFixedSize(64,64)
        b.setCheckable(True)
        b.setIcon(i)
        b.setStyleSheet("* { background: transparent }")
        return b

    def createButton(self, normal, pressed):
        b = QToolButton()
        b.setFixedSize(64,64)
        b.setIcon(normal)
        b.setStyleSheet("* { background: transparent }")
        b.pressed.connect( lambda: b.setIcon(pressed))
        b.released.connect( lambda: b.setIcon(normal))
        return b
    
    def playPressed(self,state):
        if   self.state == 'stop': self.mpd.play()
        else: self.mpd.pause(int(not state))
        
    def initState(self):
        self.songid  = -1
        self.state = 'stop'
        self.artist.setText("Unknown Artist")
        self.title.setText("Unknown Title")
        self.albumartist.setText("Unknown Artist")
        self.album.setText("Unknown Album")
        self.position.setRange(0,0)
        self.position.setValue(0)
        self.position.setEnabled(False)
        self.length.setText("00:00")
        self.playlistposition.setText("0/0")
        self.setStopState()
        
    def setStopState(self):
        self.playBtn.setChecked(False)
        self.time.setText("00:00")
        self.position.setValue(0)
        self.volume.setEnabled(False)

    def updateStatus(self):
        status = self.mpd.status()
        self.repeatBtn.setChecked(int(status['repeat']))
        self.shuffleBtn.setChecked(int(status['random']))
        self.consumeBtn.setChecked(int(status['consume']))
        self.singleBtn.setChecked(int(status['single']))
        if not status.has_key('songid') and self.songid != -1:
            self.initState()
            return
        stateChanged = False
        state = status['state']
        if state != self.state:
            stateChanged = True
        self.state = state
        volume = int(status['volume'])
        if self.state == 'play' or self.state == 'pause':
            self.playBtn.setChecked(True if self.state == 'play' else False)
            songid = int(status['songid'])
            if songid != self.songid:
                self.songid = songid
                self.updateCurrentSong()
            playlistlength = int(status['playlistlength'])
            song = int(status.get('song',-1))
            self.playlistposition.setText("%d/%d" % (song+1,playlistlength))
            playlistlength = int(status['playlistlength'])
            elapsed = float(status['elapsed'])
            if not self.position.isSliderDown():
                timeString = self.mpd.timeString(round(elapsed))
                self.time.setFixedSize(
                    (len(timeString)+1)*self.fmt.averageCharWidth(),
                    self.fmt.height())
                self.time.setText(timeString)
                if self.position.maximum() > 0:
                    self.position.setSliderPosition(round(elapsed))
            if stateChanged:
                self.volume.setEnabled(True)
            if not self.volume.isSliderDown():
                self.volume.setValue(volume)
            #nextsong = int(status['nextsong'])
        else:
            if self.songid == -1: return
            self.setStopState()
            
    def updateCurrentSong(self):
        currentsong = self.mpd.unifySongInfo(self.mpd.currentsong())
        self.artist.setText(      currentsong['artist'])
        self.title.setText(       currentsong['title'])
        self.albumartist.setText( currentsong['albumartist'])
        self.album.setText(       currentsong['album'])
        self.length.setText(      currentsong['length'])
        self.position.setRange(0,currentsong['time'])
        self.position.setEnabled(True if self.position.maximum() > 0 else False)
        self.position.setValue(0)
        self.time.setText("00:00")
        self.volume.setEnabled(True)

    def seek(self):
        secs = self.position.sliderPosition()
        if self.songid == -1: return
        self.mpd.seekid(self.songid, secs)
       
    def hideEvent(self, ev):
        if self.timer:
            self.killTimer( self.timer)
            self.timer = None
        super(Player,self).hideEvent(ev)

    def showEvent(self,ev):
        if not self.timer:
            self.updateStatus()
            self.timer = self.startTimer(1000)
        super(Player,self).showEvent(ev)

    def timerEvent(self,ev):
        try:
            self.updateStatus()
        except ConnectionError, e:
            self.hide()
            QMaemo5InformationBox.information(
                self, "Connection Error: %s" % str(e),
                QMaemo5InformationBox.DefaultTimeout)
        except socket.error, e:
            QMaemo5InformationBox.information(
                self, "Connection Error: %s" % e[1],
                QMaemo5InformationBox.DefaultTimeout)
            self.hide()
Example #45
0
class ShellBaseWidget(ConsoleBaseWidget):
    """
    Shell base widget
    """
    INITHISTORY = None
    SEPARATOR = None

    def __init__(self, parent, history_filename, debug=False, profile=False):
        """
        parent : specifies the parent widget
        """
        ConsoleBaseWidget.__init__(self, parent)

        # Prompt position: tuple (line, index)
        self.current_prompt_pos = None
        self.new_input_line = True

        # History
        self.histidx = None
        self.hist_wholeline = False
        assert isinstance(history_filename, (str, unicode))
        self.history_filename = history_filename
        self.history = self.load_history()

        # Session
        self.historylog_filename = CONF.get('main', 'historylog_filename',
                                            get_conf_path('history.log'))

        # Context menu
        self.menu = None
        self.setup_context_menu()

        # Debug mode
        self.debug = debug

        # Simple profiling test
        self.profile = profile

        # write/flush
        self.__buffer = []
        self.__timestamp = 0.0

        # Give focus to widget
        self.setFocus()

    def setup(self):
        """Reimplement ConsoleBaseWidget method"""
        ConsoleBaseWidget.setup(self)
        self.set_caret(color=Qt.darkGray, width=2)
        self.remove_margins()  # Suppressing Scintilla margins

    def toggle_wrap_mode(self, enable):
        """Reimplement ConsoleBaseWidget method: 'word' -> 'character'"""
        self.set_wrap_mode('character' if enable else None)

    def set_font(self, font):
        """Set shell styles font"""
        self.set_pythonshell_font(font)

    #------ Context menu
    def setup_context_menu(self):
        """Setup shell context menu"""
        self.menu = QMenu(self)
        self.cut_action = create_action(self,
                                        translate("ShellBaseWidget", "Cut"),
                                        shortcut=keybinding('Cut'),
                                        icon=get_icon('editcut.png'),
                                        triggered=self.cut)
        self.copy_action = create_action(self,
                                         translate("ShellBaseWidget", "Copy"),
                                         shortcut=keybinding('Copy'),
                                         icon=get_icon('editcopy.png'),
                                         triggered=self.copy)
        paste_action = create_action(self,
                                     translate("ShellBaseWidget", "Paste"),
                                     shortcut=keybinding('Paste'),
                                     icon=get_icon('editpaste.png'),
                                     triggered=self.paste)
        save_action = create_action(self,
                                    translate("ShellBaseWidget",
                                              "Save history log..."),
                                    icon=get_icon('filesave.png'),
                                    tip=translate(
                                        "ShellBaseWidget",
                                        "Save current history log (i.e. all "
                                        "inputs and outputs) in a text file"),
                                    triggered=self.save_historylog)
        add_actions(self.menu, (self.cut_action, self.copy_action,
                                paste_action, None, save_action))

    def contextMenuEvent(self, event):
        """Reimplement Qt method"""
        state = self.hasSelectedText()
        self.copy_action.setEnabled(state)
        self.cut_action.setEnabled(state)
        self.menu.popup(event.globalPos())
        event.accept()

    #------ Input buffer
    def get_current_line_to_cursor(self):
        return self.get_text(self.current_prompt_pos, 'cursor')

    def get_current_line_from_cursor(self):
        return self.get_text('cursor', 'eof')

    def _select_input(self):
        """Select current line (without selecting console prompt)"""
        line, index = self.get_position('eof')
        if self.current_prompt_pos is None:
            pline, pindex = line, index
        else:
            pline, pindex = self.current_prompt_pos
        self.setSelection(pline, pindex, line, index)

    def clear_line(self):
        """Clear current line (without clearing console prompt)"""
        if self.current_prompt_pos is not None:
            self.remove_text(self.current_prompt_pos, 'eof')

    def clear_terminal(self):
        """
        Clear terminal window
        Child classes reimplement this method to write prompt
        """
        self.clear()

    # The buffer being edited
    def _set_input_buffer(self, text):
        """Set input buffer"""
        if self.current_prompt_pos is not None:
            self.replace_text(self.current_prompt_pos, 'eol', text)
        else:
            self.insert(text)
        self.set_cursor_position('eof')

    def _get_input_buffer(self):
        """Return input buffer"""
        input_buffer = ''
        if self.current_prompt_pos is not None:
            input_buffer = self.get_text(self.current_prompt_pos, 'eol')
            input_buffer = input_buffer.replace(os.linesep, '\n')
        return input_buffer

    input_buffer = pyqtProperty("QString", _get_input_buffer,
                                _set_input_buffer)

    #------ Prompt
    def new_prompt(self, prompt):
        """
        Print a new prompt and save its (line, index) position
        """
        self.write(prompt, prompt=True)
        # now we update our cursor giving end of prompt
        self.current_prompt_pos = self.get_position('cursor')
        self.ensureCursorVisible()
        self.new_input_line = False

    def check_selection(self):
        """
        Check if selected text is r/w,
        otherwise remove read-only parts of selection
        """
        if self.current_prompt_pos is None:
            self.set_cursor_position('eof')
        else:
            self.truncate_selection(self.current_prompt_pos)

    #------ Copy / Keyboard interrupt
    def copy(self):
        """Copy text to clipboard... or keyboard interrupt"""
        if self.hasSelectedText():
            text = unicode(self.selectedText()).replace(u"\u2029", os.linesep)
            QApplication.clipboard().setText(text)
        else:
            self.emit(SIGNAL("keyboard_interrupt()"))

    def cut(self):
        """Cut text"""
        self.check_selection()
        if self.hasSelectedText():
            ConsoleBaseWidget.cut(self)

    def delete(self):
        """Remove selected text"""
        self.check_selection()
        if self.hasSelectedText():
            ConsoleBaseWidget.removeSelectedText(self)

    def save_historylog(self):
        """Save current history log (all text in console)"""
        title = translate("ShellBaseWidget", "Save history log")
        self.emit(SIGNAL('redirect_stdio(bool)'), False)
        filename = QFileDialog.getSaveFileName(self, title,
                                               self.historylog_filename,
                                               "History logs (*.log)")
        self.emit(SIGNAL('redirect_stdio(bool)'), True)
        if filename:
            filename = osp.normpath(unicode(filename))
            try:
                encoding.write(unicode(self.text()), filename)
                self.historylog_filename = filename
                CONF.set('main', 'historylog_filename', filename)
            except EnvironmentError, error:
                QMessageBox.critical(self, title,
                                translate("ShellBaseWidget",
                                          "<b>Unable to save file '%1'</b>"
                                          "<br><br>Error message:<br>%2") \
                                .arg(osp.basename(filename)).arg(str(error)))
class CompareTwoScansWidget(QWizardPage, ListWidgetDeleting):
    VIEW_MASK_ADDED = 1
    VIEW_MASK_MODIFIED = 2
    VIEW_MASK_REMOVED = 4
    VIEW_MASK_UNCHANGED = 8
    VIEW_MASK_ALL_CHECKED = 16
    VIEW_MASK_ALL = 31
    VIEW_MASK_ONLY_CHECKED = 32
    VIEW_MASK_ONLY_UNCHECKED = 64

    def __init__(self):
        super(QWizardPage, self).__init__()
        super(ListWidgetDeleting, self).__init__()

        self.ui = compare_two_scans.Ui_compare_two_scans()
        self.ui.setupUi(self)

        self.actionShowInFinder = QAction(
            "Show in Finder" if Platform.isMac else "Show in Explorer", self)
        self.actionShowInFinder.triggered.connect(self.__onShowInFinder)
        self.actionCheckSelected = QAction("Check all Selected", self)
        self.actionCheckSelected.triggered.connect(
            lambda: self.__onCheckSelectionViaContextMenu(Qt.Checked))
        self.actionUnCheckSelected = QAction("Uncheck all Selected", self)
        self.actionUnCheckSelected.triggered.connect(
            lambda: self.__onCheckSelectionViaContextMenu(Qt.Unchecked))

        self.menu = QMenu()
        self.menu.addAction(self.actionShowInFinder)
        self.menu.addSeparator()
        self.menu.addAction(self.actionCheckSelected)
        self.menu.addAction(self.actionUnCheckSelected)

        self.ui.checkBoxAdded.stateChanged.connect(
            self.__onStateFilteringChanged)
        self.ui.checkBoxChanged.stateChanged.connect(
            self.__onStateFilteringChanged)
        self.ui.checkBoxNotChanged.stateChanged.connect(
            self.__onStateFilteringChanged)
        self.ui.checkBoxRemoved.stateChanged.connect(
            self.__onStateFilteringChanged)
        self.ui.comboFiltering.currentIndexChanged.connect(
            self.__onStateFilteringChanged)

        # I added this because I was concerned that it took too many clicks on the checkbox to change its state
        #self.ui.tableView.setAttribute(Qt.WA_MacNoClickThrough, True)
        self.setTitle("Comparison and Package Preparation")

        self.ui.searchLineEdit.textChanged.connect(self.__onFilterTextChanged)
        self.ui.buttonRescan.clicked.connect(self.__onRescanClicked)

        # the current document name being shown
        self.document = None
        # the current path that is used to show a subset of the items in this document, this path is modified by
        # the user clicked in the 'tree widget' view.  The path is then added to an SQL expression filter that
        # is used to restrict the items shown in the table view.
        self.filter_abs_path = ''
        # the current filter text is stored here (so it can be re-applied), this text is a copy of whatever is
        # being typed into the search filter QLineEdit instance
        self.filter_text = ''
        # the current filter mask
        self.filter_mask = CompareTwoScansWidget.VIEW_MASK_ALL

        self.ui.treeView.customContextMenuRequested.connect(
            self.__onCustomContextMenu)

    def initializePage(self):
        name_of_file = self.wizard().documentName()
        self.__refreshResultsUsingDocument(
            PersistentScanningState(
                DocumentStorage.documentFullPath(name_of_file)))

        self.wizard().removePage(WizardPage.CREATE_NEW)
        self.wizard().removePage(WizardPage.FIRST_SCAN_PROGRESS)
        self.wizard().removePage(WizardPage.SECOND_SCAN_PROGRESS)
        self.wizard().removePage(WizardPage.SCANNING_COMPLETE_INSTALL_NOW)

        self.wizard().reinsertCreateScanPage()

    def __onCustomContextMenu(self, pos):
        indexes = self.ui.treeView.selectionModel().selectedRows()
        self.actionShowInFinder.setEnabled(len(indexes) == 1)
        self.menu.popup(self.ui.treeView.mapToGlobal(pos))

    def __onShowInFinder(self, action):
        indexes = self.ui.treeView.selectionModel().selectedRows()
        if len(indexes):
            first_index = indexes[0]
            ms = self.model.mergeScanForIndex(first_index)
            if ms is not None:
                showInFinder(ms.abs_path)

    def __onCheckSelectionViaContextMenu(self, check_state):
        """
		This is called when the right-click contextual menu fires a check or uncheck selection event - we just modify
		the checked state of the selected rows
		"""
        indexes = self.ui.treeView.selectedIndexes()
        for idx in indexes:
            # find the object, and change its checked state
            ms = self.model.mergeScanForIndex(idx)
            if ms is not None and ms.checked != check_state:
                self.model.setCheckedStateForMergeScan(ms, check_state)

    def __onStateFilteringChanged(self, new_state):
        """
		This filtering method is called when one of the state-type radio buttons is clicked.  The idea is to restrict the rows
		to those that match either the added/modified/deleted flags.
		"""
        new_mask = 0

        if self.ui.checkBoxAdded.checkState() == Qt.Checked:
            new_mask += CompareTwoScansWidget.VIEW_MASK_ADDED
        if self.ui.checkBoxChanged.checkState() == Qt.Checked:
            new_mask += CompareTwoScansWidget.VIEW_MASK_MODIFIED
        if self.ui.checkBoxRemoved.checkState() == Qt.Checked:
            new_mask += CompareTwoScansWidget.VIEW_MASK_REMOVED
        if self.ui.checkBoxNotChanged.checkState() == Qt.Checked:
            new_mask += CompareTwoScansWidget.VIEW_MASK_UNCHANGED

        if self.ui.comboFiltering.currentIndex() == 1:
            new_mask += CompareTwoScansWidget.VIEW_MASK_ONLY_CHECKED
        if self.ui.comboFiltering.currentIndex() == 2:
            new_mask += CompareTwoScansWidget.VIEW_MASK_ONLY_UNCHECKED

        self.filter_mask = new_mask
        self.__resetFilterCondition()

    def __rescanFinished(self):
        self.rescan_dlg.accept()
        self.rescan_dlg = None

    def __onRescanClicked(self):
        if not hasattr(self, 'document'):
            return

        # run a scan again in the background, throw up a dialog (modal) to keep track
        self.rescan_dlg = QDialog(self.wizard())
        self.rescan_dlg.setWindowFlags(Qt.Sheet)

        progress_widget = ScanningProgressWidget(False, parent=self.rescan_dlg)

        filename = self.document.filename

        scan_paths = [p.abs_path for p in self.document.pathsBeingScanned()]
        progress_widget.beginScan(filename,
                                  scan_paths,
                                  callableWhenDone=self.__rescanFinished)

        self.rescan_dlg.open()

    def __onFilterTextChanged(self, new_text):
        self.filter_text = new_text
        self.__resetFilterCondition()

    def __addToFlagsSet(self, flags_set, flag_value):
        if len(flags_set) > 0:
            flags_set += ", "
        flags_set += str(flag_value)
        return flags_set

    def __resetFilterCondition(self):
        if not hasattr(self, 'model'):
            return

        # build the entire condition, it is drive by the filter_abs_path (which may be null/zero len) and the filter_text

        flags_set = ""

        if self.filter_mask & CompareTwoScansWidget.VIEW_MASK_ADDED:
            flags_set = self.__addToFlagsSet(
                flags_set, PersistentScanningState.ITEM_ADDED)

        if self.filter_mask & CompareTwoScansWidget.VIEW_MASK_MODIFIED:
            flags_set = self.__addToFlagsSet(
                flags_set, PersistentScanningState.ITEM_MODIFIED)

        if self.filter_mask & CompareTwoScansWidget.VIEW_MASK_REMOVED:
            flags_set = self.__addToFlagsSet(
                flags_set, PersistentScanningState.ITEM_DELETED)

        if self.filter_mask & CompareTwoScansWidget.VIEW_MASK_UNCHANGED:
            flags_set = self.__addToFlagsSet(
                flags_set, PersistentScanningState.ITEM_UNCHANGED)

        filter = "is_dir = 'false' AND flags IN ({}) ".format(flags_set)
        #filter = " flags IN ({}) ".format(flags_set)

        if self.filter_mask & CompareTwoScansWidget.VIEW_MASK_ONLY_UNCHECKED:
            filter += "AND checked = {}".format(Qt.Unchecked)
        elif self.filter_mask & CompareTwoScansWidget.VIEW_MASK_ONLY_CHECKED:
            filter += "AND checked = {}".format(Qt.Checked)

        if len(self.filter_abs_path) > 0:
            filter += " AND abs_path LIKE '{}{}%'".format(
                self.filter_abs_path.encode("utf-8"), os.path.sep)

        if len(self.filter_text) > 0:
            filter += " AND (abs_path LIKE '%{}%' OR path_info LIKE '%{}%')".format(
                self.filter_text, self.filter_text)

        logger.debug("re-filtering text expression to: {0}".format(filter))
        #self.model.setFilter(filter)

    def __refreshResultsUsingDocument(self, doc):
        self.document = doc
        #self.document.databaseChanged.connect(self.__resetFilterCondition)

        mapper = MergeScanMapper(doc)
        self.model = MergeScanTreeModel(doc, mapper, doc.roots(), self)
        self.ui.treeView.setModel(self.model)

        #self.model.checkStateChanged.connect(self.__onCheckSelectionHasChanged)

        registryMapper = MergedRegistryMapper(doc)
        self.registryModel = mergedRegistryTreeModel(doc, registryMapper,
                                                     HIVES, self)
        self.ui.regView.setModel(self.registryModel)

        header = self.ui.treeView.header()
        header.setResizeMode(MergeScanTreeModel.COL_CHECKED,
                             QHeaderView.ResizeToContents)
        header.setResizeMode(MergeScanTreeModel.COL_PERMISSIONS,
                             QHeaderView.ResizeToContents)

        #		# adjust column 0 in the table header
        #		header = self.ui.treeView.header()
        #		header.setSortIndicator(QueryModel.COL_ABSPATH, Qt.AscendingOrder)
        #		model.setSort(PersistentScanningState.DBCOL_MERGE_ABS_PATH, Qt.AscendingOrder)
        #
        #		header.setResizeMode(QueryModel.COL_CHECKED, QHeaderView.Fixed)
        #		header.setResizeMode(QueryModel.COL_ICON, QHeaderView.Fixed)
        #		header.setResizeMode(QueryModel.COL_ABSPATH, QHeaderView.ResizeToContents)
        #		header.resizeSection(QueryModel.COL_CHECKED, 45)
        #		header.resizeSection(QueryModel.COL_ICON, 45)

        self.ui.treeView.setAttribute(Qt.WA_MacShowFocusRect, False)

        # clear existing search string
        self.ui.searchLineEdit.setText("")
        self.__resetFilterCondition()
Example #47
0
class ProfileTableViewer( QWidget ):
    " Profiling results table viewer "

    escapePressed = pyqtSignal()

    def __init__( self, scriptName, params, reportTime,
                        dataFile, stats, parent = None ):
        QWidget.__init__( self, parent )

        self.__table = ProfilerTreeWidget( self )
        self.__table.escapePressed.connect( self.__onEsc )

        self.__script = scriptName
        self.__stats = stats
        project = GlobalData().project
        if project.isLoaded():
            self.__projectPrefix = os.path.dirname( project.fileName )
        else:
            self.__projectPrefix = os.path.dirname( scriptName )
        if not self.__projectPrefix.endswith( os.path.sep ):
            self.__projectPrefix += os.path.sep

        self.__table.setAlternatingRowColors( True )
        self.__table.setRootIsDecorated( False )
        self.__table.setItemsExpandable( False )
        self.__table.setSortingEnabled( True )
        self.__table.setItemDelegate( NoOutlineHeightDelegate( 4 ) )
        self.__table.setUniformRowHeights( True )
        self.__table.setSelectionMode( QAbstractItemView.SingleSelection )
        self.__table.setSelectionBehavior( QAbstractItemView.SelectRows )

        headerLabels = [ "", "Calls", "Total time", "Per call",
                         "Cum. time", "Per call", "File name:line",
                         "Function", "Callers", "Callees" ]
        self.__table.setHeaderLabels( headerLabels )

        headerItem = self.__table.headerItem()
        headerItem.setToolTip( 0, "Indication if it is an outside function" )
        headerItem.setToolTip( 1, "Actual number of calls/primitive calls "
                                  "(not induced via recursion)" )
        headerItem.setToolTip( 2, "Total time spent in function "
                                  "(excluding time made in calls "
                                  "to sub-functions)" )
        headerItem.setToolTip( 3, "Total time divided by number "
                                  "of actual calls" )
        headerItem.setToolTip( 4, "Total time spent in function and all "
                                  "subfunctions (from invocation till exit)" )
        headerItem.setToolTip( 5, "Cumulative time divided by number "
                                  "of primitive calls" )
        headerItem.setToolTip( 6, "Function location" )
        headerItem.setToolTip( 7, "Function name" )
        headerItem.setToolTip( 8, "Function callers" )
        headerItem.setToolTip( 9, "Function callees" )

        self.__table.itemActivated.connect( self.__activated )

        totalCalls = self.__stats.total_calls
        totalPrimitiveCalls = self.__stats.prim_calls  # The calls were not induced via recursion
        totalTime = self.__stats.total_tt

        txt = "<b>Script:</b> " + self.__script + " " + params.arguments + "<br>" \
              "<b>Run at:</b> " + reportTime + "<br>" + \
              str( totalCalls ) + " function calls (" + \
              str( totalPrimitiveCalls ) + " primitive calls) in " + \
              FLOAT_FORMAT % totalTime + " CPU seconds"
        summary = QLabel( txt )
        summary.setToolTip( txt )
        summary.setSizePolicy( QSizePolicy.Ignored, QSizePolicy.Fixed )
        summary.setFrameStyle( QFrame.StyledPanel )
        summary.setAutoFillBackground( True )
        summaryPalette = summary.palette()
        summaryBackground = summaryPalette.color( QPalette.Background )
        summaryBackground.setRgb( min( summaryBackground.red() + 30, 255 ),
                                  min( summaryBackground.green() + 30, 255 ),
                                  min( summaryBackground.blue() + 30, 255 ) )
        summaryPalette.setColor( QPalette.Background, summaryBackground )
        summary.setPalette( summaryPalette )

        vLayout = QVBoxLayout()
        vLayout.setContentsMargins( 0, 0, 0, 0 )
        vLayout.setSpacing( 0 )
        vLayout.addWidget( summary )
        vLayout.addWidget( self.__table )

        self.setLayout( vLayout )
        self.__createContextMenu()

        self.__populate( totalTime )
        return

    def __onEsc( self ):
        " Triggered when Esc is pressed "
        self.escapePressed.emit()
        return

    def __createContextMenu( self ):
        " Creates context menu for the table raws "
        self.__contextMenu = QMenu( self )
        self.__callersMenu = QMenu( "Callers", self )
        self.__outsideCallersMenu = QMenu( "Outside callers", self )
        self.__calleesMenu = QMenu( "Callees", self )
        self.__outsideCalleesMenu = QMenu( "Outside callees", self )
        self.__contextMenu.addMenu( self.__callersMenu )
        self.__contextMenu.addMenu( self.__outsideCallersMenu )
        self.__contextMenu.addSeparator()
        self.__contextMenu.addMenu( self.__calleesMenu )
        self.__contextMenu.addMenu( self.__outsideCalleesMenu )
        self.__contextMenu.addSeparator()
        self.__disasmAct = self.__contextMenu.addAction(
                                    PixmapCache().getIcon( 'disasmmenu.png' ),
                                    "Disassemble", self.__onDisassemble )

        self.__callersMenu.triggered.connect( self.__onCallContextMenu )
        self.__outsideCallersMenu.triggered.connect( self.__onCallContextMenu )
        self.__calleesMenu.triggered.connect( self.__onCallContextMenu )
        self.__outsideCalleesMenu.triggered.connect( self.__onCallContextMenu )

        self.__table.setContextMenuPolicy( Qt.CustomContextMenu )
        self.__table.customContextMenuRequested.connect( self.__showContextMenu )
        return

    def __showContextMenu( self, point ):
        " Context menu "
        self.__callersMenu.clear()
        self.__outsideCallersMenu.clear()
        self.__calleesMenu.clear()
        self.__outsideCalleesMenu.clear()

        # Detect what the item was clicked
        item = self.__table.itemAt( point )

        funcName = item.getFunctionName()
        self.__disasmAct.setEnabled( item.getFileName() != "" and \
                                     not funcName.startswith( "<" ) )

        # Build the context menu
        if item.callersCount() == 0:
            self.__callersMenu.setEnabled( False )
            self.__outsideCallersMenu.setEnabled( False )
        else:
            callers = self.__stats.stats[ item.getFuncIDs() ][ 4 ]
            callersList = callers.keys()
            callersList.sort()
            for callerFunc in callersList:
                menuText = self.__getCallLine( callerFunc, callers[ callerFunc ] )
                if self.__isOutsideItem( callerFunc[ 0 ] ):
                    act = self.__outsideCallersMenu.addAction( menuText )
                else:
                    act = self.__callersMenu.addAction( menuText )
                funcFileName, funcLine, funcName = self.__getLocationAndName( callerFunc )
                act.setData( QVariant( funcFileName + ":" + \
                                       str( funcLine ) + ":" + \
                                       funcName ) )
            self.__callersMenu.setEnabled( not self.__callersMenu.isEmpty() )
            self.__outsideCallersMenu.setEnabled( not self.__outsideCallersMenu.isEmpty() )

        if item.calleesCount() == 0:
            self.__calleesMenu.setEnabled( False )
            self.__outsideCalleesMenu.setEnabled( False )
        else:
            callees = self.__stats.all_callees[ item.getFuncIDs() ]
            calleesList = callees.keys()
            calleesList.sort()
            for calleeFunc in calleesList:
                menuText = self.__getCallLine( calleeFunc, callees[ calleeFunc ] )
                if self.__isOutsideItem( calleeFunc[ 0 ] ):
                    act = self.__outsideCalleesMenu.addAction( menuText )
                else:
                    act = self.__calleesMenu.addAction( menuText )
                funcFileName, funcLine, funcName = self.__getLocationAndName( calleeFunc )
                act.setData( QVariant( funcFileName + ":" + \
                                       str( funcLine ) + ":" + \
                                       funcName ) )
            self.__calleesMenu.setEnabled( not self.__calleesMenu.isEmpty() )
            self.__outsideCalleesMenu.setEnabled( not self.__outsideCalleesMenu.isEmpty() )

        self.__contextMenu.popup( QCursor.pos() )
        return

    def __onDisassemble( self ):
        " On disassemble something "
        item = self.__table.selectedItems()[ 0 ]
        GlobalData().mainWindow.showDisassembler( item.getFileName(),
                                                  item.getFunctionName() )
        return

    def __resize( self ):
        " Resizes columns to the content "
        self.__table.header().resizeSections( QHeaderView.ResizeToContents )
        self.__table.header().setStretchLastSection( True )
        self.__table.header().resizeSection( OUTSIDE_COL_INDEX, 28 )
        self.__table.header().setResizeMode( OUTSIDE_COL_INDEX,
                                             QHeaderView.Fixed )
        return

    def setFocus( self ):
        " Set focus to the proper widget "
        self.__table.setFocus()
        return

    def __isOutsideItem( self, fileName ):
        " Detects if the record should be shown as an outside one "
        return not fileName.startswith( self.__projectPrefix )

    def __activated( self, item, column ):
        " Triggered when the item is activated "

        try:
            line = item.getLineNumber()
            fileName = item.getFileName()
            if line == 0 or not os.path.isabs( fileName ):
                return
            GlobalData().mainWindow.openFile( fileName, line )
        except:
            logging.error( "Could not jump to function location" )
        return

    @staticmethod
    def __getFuncShortLocation( funcFileName, funcLine ):
        " Provides unified shortened function location "
        if funcFileName == "":
            return ""
        return os.path.basename( funcFileName ) + ":" + str( funcLine )

    def __getCallLine( self, func, props ):
        " Provides the formatted call line "
        funcFileName, funcLine, funcName = self.__getLocationAndName( func )
        if isinstance( props, tuple ):
            actualCalls, primitiveCalls, totalTime, cumulativeTime = props
            if primitiveCalls != actualCalls:
                callsString = str( actualCalls ) + "/" + str( primitiveCalls )
            else:
                callsString = str( actualCalls )

            return callsString + "\t" + FLOAT_FORMAT % totalTime + "\t" + \
                   FLOAT_FORMAT % cumulativeTime + "\t" + \
                   self.__getFuncShortLocation( funcFileName, funcLine ) + \
                   "(" + funcName + ")"

        # I've never seen this branch working so it is just in case.
        # There was something like this in the pstats module
        return self.__getFuncShortLocation( funcFileName, funcLine ) + \
               "(" + funcName + ")"

    @staticmethod
    def __getLocationAndName( func ):
        " Provides standardized function file name, line and its name "
        if func[ : 2 ] == ( '~', 0 ):
            # special case for built-in functions
            name = func[ 2 ]
            if name.startswith( '<' ) and name.endswith( '>' ):
                return "", 0, "{%s}" % name[ 1 : -1 ]
            return "", 0, name
        return func[ 0 ], func[ 1 ], func[ 2 ]

    def __createItem( self, func, totalCPUTime,
                            primitiveCalls, actualCalls, totalTime,
                            cumulativeTime, timePerCall, cumulativeTimePerCall,
                            callers ):
        " Creates an item to display "
        values = []
        values.append( "" )
        if primitiveCalls == actualCalls:
            values.append( str( actualCalls ) )
        else:
            values.append( str( actualCalls ) + "/" + str( primitiveCalls ) )

        if totalCPUTime == 0.0:
            values.append( FLOAT_FORMAT % totalTime )
        else:
            values.append( FLOAT_FORMAT % totalTime + " \t(%3.2f%%)" % (totalTime / totalCPUTime * 100) )
        values.append( FLOAT_FORMAT % timePerCall )
        values.append( FLOAT_FORMAT % cumulativeTime )
        values.append( FLOAT_FORMAT % cumulativeTimePerCall )

        # Location and name will be filled in the item constructor
        values.append( "" )
        values.append( "" )

        # Callers
        callersCount = len( callers )
        values.append( str( callersCount ) )

        # Callees
        if func in self.__stats.all_callees:
            calleesCount = len( self.__stats.all_callees[ func ] )
        else:
            calleesCount = 0
        values.append( str( calleesCount ) )

        item = ProfilingTableItem( values, self.__isOutsideItem( func[ 0 ] ),
                                   func )

        if callersCount != 0:
            tooltip = ""
            callersList = callers.keys()
            callersList.sort()
            for callerFunc in callersList[ : MAX_CALLS_IN_TOOLTIP ]:
                if tooltip != "":
                    tooltip += "\n"
                tooltip += self.__getCallLine( callerFunc, callers[ callerFunc ] )
            if callersCount > MAX_CALLS_IN_TOOLTIP:
                tooltip += "\n. . ."
            item.setToolTip( 8, tooltip )

        if calleesCount != 0:
            callees = self.__stats.all_callees[ func ]
            tooltip = ""
            calleesList = callees.keys()
            calleesList.sort()
            for calleeFunc in calleesList[ : MAX_CALLS_IN_TOOLTIP ]:
                if tooltip != "":
                    tooltip += "\n"
                tooltip += self.__getCallLine( calleeFunc, callees[ calleeFunc ] )
            if calleesCount > MAX_CALLS_IN_TOOLTIP:
                tooltip += "\n. . ."
            item.setToolTip( 9, tooltip )

        self.__table.addTopLevelItem( item )
        return

    def __populate( self, totalCPUTime ):
        " Populates the data "

        for func, ( primitiveCalls, actualCalls, totalTime,
                    cumulativeTime, callers ) in self.__stats.stats.items():

            # Calc time per call
            if actualCalls == 0:
                timePerCall = 0.0
            else:
                timePerCall = totalTime / actualCalls

            # Calc time per cummulative call
            if primitiveCalls == 0:
                cumulativeTimePerCall = 0.0
            else:
                cumulativeTimePerCall = cumulativeTime / primitiveCalls

            self.__createItem( func, totalCPUTime,
                               primitiveCalls, actualCalls, totalTime,
                               cumulativeTime, timePerCall, cumulativeTimePerCall,
                               callers )
        self.__resize()
        self.__table.header().setSortIndicator( 2, Qt.DescendingOrder )
        self.__table.sortItems( 2,
                                self.__table.header().sortIndicatorOrder() )
        return

    def togglePath( self, state ):
        " Switches between showing full paths or file names in locations "
        for index in xrange( 0, self.__table.topLevelItemCount() ):
            self.__table.topLevelItem( index ).updateLocation( state )
        self.__resize()
        return

    def __onCallContextMenu( self, act ):
        " Triggered when a context menu action is requested "
        name = str( act.data().toString() )
        for index in xrange( 0, self.__table.topLevelItemCount() ):
            item = self.__table.topLevelItem( index )
            if item.match( name ):
                self.__table.clearSelection()
                self.__table.scrollToItem( item )
                self.__table.setCurrentItem( item )
        return

    def onSaveAs( self, fileName ):
        " Saves the table to a file in CSV format "
        try:
            f = open( fileName, "wt" )
            headerItem = self.__table.headerItem()
            outsideIndex = -1
            for index in xrange( 0, headerItem.columnCount() ):
                title = str( headerItem.text( index ) )
                if title == "":
                    outsideIndex = index
                    title = "Outside"
                if index != 0:
                    f.write( ',' + title )
                else:
                    f.write( title )

            for index in xrange( 0, self.__table.topLevelItemCount() ):
                item = self.__table.topLevelItem( index )
                f.write( "\n" )
                for column in xrange( 0, item.columnCount() ):
                    if column != 0:
                        f.write( ',' )
                    if column == outsideIndex:
                        if item.isOutside():
                            f.write( "Y" )
                        else:
                            f.write( "N" )
                    else:
                        text = str( item.text( column ) )
                        f.write( text.replace( '\t', '' ) )
            f.close()
        except Exception, ex:
            logging.error( ex )
        return
Example #48
0
class IgnoredExceptionsViewer(QWidget):
    " Implements the client exceptions viewer for a debugger "

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.__createPopupMenu()
        self.__createLayout()
        self.__ignored = []
        self.__currentItem = None

        GlobalData().project.projectChanged.connect(self.__onProjectChanged)

        if Settings().showIgnoredExcViewer == False:
            self.__onShowHide(True)
        return

    def __createPopupMenu(self):
        " Creates the popup menu "
        self.__excptMenu = QMenu()
        self.__removeMenuItem = self.__excptMenu.addAction(
            PixmapCache().getIcon('ignexcptdel.png'),
            "Remove from ignore list", self.__onRemoveFromIgnore)
        return

    def __createLayout(self):
        " Creates the widget layout "

        verticalLayout = QVBoxLayout(self)
        verticalLayout.setContentsMargins(0, 0, 0, 0)
        verticalLayout.setSpacing(0)

        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle(QFrame.StyledPanel)
        self.headerFrame.setAutoFillBackground(True)
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color(QPalette.Background)
        headerBackground.setRgb(min(headerBackground.red() + 30, 255),
                                min(headerBackground.green() + 30, 255),
                                min(headerBackground.blue() + 30, 255))
        headerPalette.setColor(QPalette.Background, headerBackground)
        self.headerFrame.setPalette(headerPalette)
        self.headerFrame.setFixedHeight(24)

        self.__excptLabel = QLabel("Ignored exception types")

        expandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding)
        fixedSpacer = QSpacerItem(3, 3)

        self.__showHideButton = QToolButton()
        self.__showHideButton.setAutoRaise(True)
        self.__showHideButton.setIcon(PixmapCache().getIcon('less.png'))
        self.__showHideButton.setFixedSize(20, 20)
        self.__showHideButton.setToolTip("Hide ignored exceptions list")
        self.__showHideButton.setFocusPolicy(Qt.NoFocus)
        self.__showHideButton.clicked.connect(self.__onShowHide)

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins(1, 1, 1, 1)
        headerLayout.addSpacerItem(fixedSpacer)
        headerLayout.addWidget(self.__excptLabel)
        headerLayout.addSpacerItem(expandingSpacer)
        headerLayout.addWidget(self.__showHideButton)
        self.headerFrame.setLayout(headerLayout)

        self.exceptionsList = QTreeWidget(self)
        self.exceptionsList.setSortingEnabled(False)
        self.exceptionsList.setAlternatingRowColors(True)
        self.exceptionsList.setRootIsDecorated(False)
        self.exceptionsList.setItemsExpandable(True)
        self.exceptionsList.setUniformRowHeights(True)
        self.exceptionsList.setSelectionMode(QAbstractItemView.SingleSelection)
        self.exceptionsList.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.exceptionsList.setItemDelegate(NoOutlineHeightDelegate(4))
        self.exceptionsList.setContextMenuPolicy(Qt.CustomContextMenu)

        self.exceptionsList.customContextMenuRequested.connect(
            self.__showContextMenu)
        self.exceptionsList.itemSelectionChanged.connect(
            self.__onSelectionChanged)
        self.exceptionsList.setHeaderLabels(["Exception type"])

        self.__excTypeEdit = QLineEdit()
        self.__excTypeEdit.setFixedHeight(26)
        self.__excTypeEdit.textChanged.connect(self.__onNewFilterChanged)
        self.__excTypeEdit.returnPressed.connect(self.__onAddExceptionFilter)
        self.__addButton = QPushButton("Add")
        # self.__addButton.setFocusPolicy( Qt.NoFocus )
        self.__addButton.setEnabled(False)
        self.__addButton.clicked.connect(self.__onAddExceptionFilter)

        expandingSpacer2 = QWidget()
        expandingSpacer2.setSizePolicy(QSizePolicy.Expanding,
                                       QSizePolicy.Expanding)

        self.__removeButton = QAction(PixmapCache().getIcon('delitem.png'),
                                      "Remove selected exception type", self)
        self.__removeButton.triggered.connect(self.__onRemoveFromIgnore)
        self.__removeButton.setEnabled(False)

        fixedSpacer1 = QWidget()
        fixedSpacer1.setFixedWidth(5)

        self.__removeAllButton = QAction(
            PixmapCache().getIcon('ignexcptdelall.png'),
            "Remove all the exception types", self)
        self.__removeAllButton.triggered.connect(self.__onRemoveAllFromIgnore)
        self.__removeAllButton.setEnabled(False)

        self.toolbar = QToolBar()
        self.toolbar.setOrientation(Qt.Horizontal)
        self.toolbar.setMovable(False)
        self.toolbar.setAllowedAreas(Qt.TopToolBarArea)
        self.toolbar.setIconSize(QSize(16, 16))
        self.toolbar.setFixedHeight(28)
        self.toolbar.setContentsMargins(0, 0, 0, 0)
        self.toolbar.addWidget(expandingSpacer2)
        self.toolbar.addAction(self.__removeButton)
        self.toolbar.addWidget(fixedSpacer1)
        self.toolbar.addAction(self.__removeAllButton)

        addLayout = QHBoxLayout()
        addLayout.setContentsMargins(1, 1, 1, 1)
        addLayout.setSpacing(1)
        addLayout.addWidget(self.__excTypeEdit)
        addLayout.addWidget(self.__addButton)

        verticalLayout.addWidget(self.headerFrame)
        verticalLayout.addWidget(self.toolbar)
        verticalLayout.addWidget(self.exceptionsList)
        verticalLayout.addLayout(addLayout)
        return

    def clear(self):
        " Clears the content "
        self.exceptionsList.clear()
        self.__excTypeEdit.clear()
        self.__addButton.setEnabled(False)
        self.__ignored = []
        self.__currentItem = None
        self.__updateTitle()
        return

    def __onShowHide(self, startup=False):
        " Triggered when show/hide button is clicked "
        if startup or self.exceptionsList.isVisible():
            self.exceptionsList.setVisible(False)
            self.__excTypeEdit.setVisible(False)
            self.__addButton.setVisible(False)
            self.__removeButton.setVisible(False)
            self.__removeAllButton.setVisible(False)
            self.__showHideButton.setIcon(PixmapCache().getIcon('more.png'))
            self.__showHideButton.setToolTip("Show ignored exceptions list")

            self.__minH = self.minimumHeight()
            self.__maxH = self.maximumHeight()

            self.setMinimumHeight(self.headerFrame.height())
            self.setMaximumHeight(self.headerFrame.height())

            Settings().showIgnoredExcViewer = False
        else:
            self.exceptionsList.setVisible(True)
            self.__excTypeEdit.setVisible(True)
            self.__addButton.setVisible(True)
            self.__removeButton.setVisible(True)
            self.__removeAllButton.setVisible(True)
            self.__showHideButton.setIcon(PixmapCache().getIcon('less.png'))
            self.__showHideButton.setToolTip("Hide ignored exceptions list")

            self.setMinimumHeight(self.__minH)
            self.setMaximumHeight(self.__maxH)

            Settings().showIgnoredExcViewer = True
        return

    def __onSelectionChanged(self):
        " Triggered when the current item is changed "
        selected = list(self.exceptionsList.selectedItems())
        if selected:
            self.__currentItem = selected[0]
            self.__removeButton.setEnabled(True)
        else:
            self.__currentItem = None
            self.__removeButton.setEnabled(False)
        return

    def __showContextMenu(self, coord):
        " Shows the frames list context menu "
        contextItem = self.exceptionsList.itemAt(coord)
        if contextItem is not None:
            self.__currentItem = contextItem
            self.__excptMenu.popup(QCursor.pos())
        return

    def __updateTitle(self):
        " Updates the section title "
        count = self.exceptionsList.topLevelItemCount()
        if count == 0:
            self.__excptLabel.setText("Ignored exception types")
        else:
            self.__excptLabel.setText("Ignored exception types (total: " +
                                      str(count) + ")")
        self.__removeAllButton.setEnabled(count != 0)
        return

    def __onProjectChanged(self, what):
        " Triggered when a project is changed "
        if what != CodimensionProject.CompleteProject:
            return

        self.clear()
        project = GlobalData().project
        if project.isLoaded():
            self.__ignored = list(project.ignoredExcpt)
        else:
            self.__ignored = list(Settings().ignoredExceptions)

        for exceptionType in self.__ignored:
            item = QTreeWidgetItem(self.exceptionsList)
            item.setText(0, exceptionType)
        self.__updateTitle()
        return

    def __onNewFilterChanged(self, text):
        " Triggered when the text is changed "
        text = str(text).strip()
        if text == "":
            self.__addButton.setEnabled(False)
            return
        if " " in text:
            self.__addButton.setEnabled(False)
            return

        if text in self.__ignored:
            self.__addButton.setEnabled(False)
            return

        self.__addButton.setEnabled(True)
        return

    def __onAddExceptionFilter(self):
        " Adds an item into the ignored exceptions list "
        text = self.__excTypeEdit.text().strip()
        self.addExceptionFilter(text)

    def addExceptionFilter(self, excType):
        " Adds a new item into the ignored exceptions list "
        if excType == "":
            return
        if " " in excType:
            return
        if excType in self.__ignored:
            return

        item = QTreeWidgetItem(self.exceptionsList)
        item.setText(0, excType)

        project = GlobalData().project
        if project.isLoaded():
            project.addExceptionFilter(excType)
        else:
            Settings().addExceptionFilter(excType)
        self.__ignored.append(excType)
        self.__updateTitle()
        return

    def __onRemoveFromIgnore(self):
        " Removes an item from the ignored exception types list "
        if self.__currentItem is None:
            return

        text = self.__currentItem.text(0)

        # Find the item index and remove it
        index = 0
        while True:
            if self.exceptionsList.topLevelItem(index).text(0) == text:
                self.exceptionsList.takeTopLevelItem(index)
                break
            index += 1

        project = GlobalData().project
        if project.isLoaded():
            project.deleteExceptionFilter(text)
        else:
            Settings().deleteExceptionFilter(text)
        self.__ignored.remove(text)
        self.__updateTitle()
        return

    def __onRemoveAllFromIgnore(self):
        " Triggered when all the ignored exceptions should be deleted "
        self.clear()

        project = GlobalData().project
        if project.isLoaded():
            project.setExceptionFilters([])
        else:
            Settings().setExceptionFilters([])
        return

    def isIgnored(self, exceptionType):
        " Returns True if this exception type should be ignored "
        return exceptionType in self.__ignored
class KerberusSystray(QWidget):

    def __init__(self):
        QWidget.__init__(self)
        icono = 'kerby-activo.ico'
        pixmap = QPixmap(icono)
        ##setear el nombre de la ventana
        self.setWindowTitle('Kerberus Control Parental')
        #colocar el icono cargado a la ventana
        self.setWindowIcon(QIcon(pixmap))
        ##creamos objeto Style para hacer uso de los iconos de Qt
	self.style = self.style()
        self.filtradoHabilitado = True

        if not os.path.isfile('dontShowMessage'):
            self.mostrarMensaje = True
            self.noMostrarMasMensaje()
        else:
            self.mostrarMensaje = False

        #Menu
        self.menu = QMenu('Kerberus')

        #accion deshabilitar filtrado
        self.deshabilitarFiltradoAction = self.menu.addAction(
                            self.style.standardIcon(QStyle.SP_DialogNoButton),
                            'Deshabilitar Filtrado'
                            )
        #accion habilitar filtrado
        self.habilitarFiltradoAction = self.menu.addAction(
                            self.style.standardIcon(QStyle.SP_DialogYesButton),
                            'Habilitar Filtrado'
                            )
        self.habilitarFiltradoAction.setVisible(False)
        #cambiar password
        self.cambiarPasswordAction = self.menu.addAction(
                self.style.standardIcon(QStyle.SP_BrowserReload),
                'Cambiar password de administrador'
                )
        #accion salir
        self.exitAction = self.menu.addAction(
                self.style.standardIcon(QStyle.SP_TitleBarCloseButton),
                'Salir')

        #SIGNAL->SLOT
        QObject.connect(
                self.exitAction,
                SIGNAL("triggered()"),
                lambda: sys.exit()
                )
        QObject.connect(
                self.menu, SIGNAL("clicked()"),
                lambda: self.menu.popup(QCursor.pos())
                )
        QObject.connect(
                self.deshabilitarFiltradoAction,
                SIGNAL("triggered()"),
                self.deshabilitarFiltradoWindow
                )
        QObject.connect(
                self.habilitarFiltradoAction,
                SIGNAL("triggered()"),
                self.habilitarFiltradoWindow
                )
        QObject.connect(
                self.cambiarPasswordAction,
                SIGNAL("triggered()"),
                self.cambiarPasswordWindow
                )

        #SystemTray
        #self.tray = QSystemTrayIcon(QIcon(pixmap), self)
        self.tray = QSystemTrayIcon(self.style.standardIcon(QStyle.SP_DialogYesButton), self)
        self.tray.setToolTip('Kerberus Control Parental - Activado')
        self.tray.setContextMenu(self.menu)
        self.tray.setVisible(True)



        QObject.connect(
                self.tray,
                SIGNAL("messageClicked()"),
                self.noMostrarMasMensaje
                )

        if self.mostrarMensaje:
            self.tray.showMessage(
                    u'Kerberus Control Parental',
                    u'Filtro de Protección para menores de edad Activado',
                    2000
                    )

    #def closeEvent(self, event):
        #event.ignore()
        #self.hide()

    def noMostrarMasMensaje(self):
        try:
            open('dontShowMessage','a').close()
        except IOError:
            print 'No se pudo crear el archivo dontShowMessage'

    def deshabilitarFiltradoWindow(self):
        webbrowser.open(
                'http://inicio.kerberus.com.ar/!DeshabilitarFiltrado!',
                new=2
                )
        self.habilitarFiltradoAction.setVisible(True)
        self.deshabilitarFiltradoAction.setVisible(False)
        self.tray.setIcon(self.style.standardIcon(QStyle.SP_DialogNoButton))
        self.tray.setToolTip('Kerberus Control Parental')

    def habilitarFiltradoWindow(self):
        webbrowser.open(
                'http://inicio.kerberus.com.ar/!HabilitarFiltrado!',
                new=2
                )
        self.habilitarFiltradoAction.setVisible(False)
        self.deshabilitarFiltradoAction.setVisible(True)
        self.tray.setIcon(self.style.standardIcon(QStyle.SP_DialogYesButton))
        self.tray.setToolTip('Kerberus Control Parental - Activado')

    def cambiarPasswordWindow(self):
        webbrowser.open(
                'http://inicio.kerberus.com.ar/!CambiarPassword!',
                new=2
                )
Example #50
0
class StepsTableView(QTableView):
    """
    Steps table view
    """
    DataChanged = pyqtSignal() 
    def __init__(self, parent, helper):
        """
        Description table view constructor
        """
        QTableView.__init__(self, parent)
        self.helper = helper
        self.createWidgets()
        self.createConnections()
        self.createActions()

    def createWidgets (self):
        """
        Create qt widgets
        """
        self.proxyModel = QSortFilterProxyModel(self)
        self.proxyModel.setDynamicSortFilter(True)

        self.model = DescriptionTableModel(self)
        self.setModel(self.proxyModel)
        self.proxyModel.setSourceModel(self.model)

        self.setFrameShape(QFrame.StyledPanel)
        self.setShowGrid(True)

        self.setSelectionMode(QAbstractItemView.SingleSelection)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.verticalHeader().setVisible(False)
        self.horizontalHeader().setHighlightSections(False)
        self.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
        self.horizontalHeader().setStretchLastSection(True)

        self.setItemDelegateForColumn( COL_SUMMARY_STEP, StepSummaryDelegate(self) )

        self.setColumnWidth(COL_ID_STEP, 45)

    def createConnections (self):
        """
        Create qt connections
        """
        self.customContextMenuRequested.connect(self.onPopupMenu)
        self.clicked.connect( self.onAbstractItemClicked)  

    def createActions (self):
        """
        Qt actions
        """
        self.addAction = QtHelper.createAction(self, self.tr("&Add"), self.addStep, icon = QIcon(":/step-add.png"),
                                                    tip = self.tr('Add a new step') )
        self.delAction = QtHelper.createAction(self, self.tr("&Delete"), self.deleteAction, icon = QIcon(":/step-del.png"),
                                                    tip = self.tr('Delete the selected step'))
        self.delAllAction = QtHelper.createAction(self, self.tr("&Delete All"), self.clearItems, icon = QIcon(":/test-parameter-clear.png"),
                                                    tip = self.tr('Delete all steps'))
        
        # set default actions
        self.delAction.setEnabled(False)
        self.delAllAction.setEnabled(False)
        
    def onAbstractItemClicked(self):
        """
        Called on item clicked
        """
        indexes = self.selectedIndexes()
        if not indexes:
            self.delAction.setEnabled(False)
        else:
            self.delAction.setEnabled(True)
            
    def onPopupMenu(self, pos):
        """
        Display menu on right click

        @param pos: 
        @type pos:
        """
        self.menu = QMenu(self)
        index = self.currentIndex()
        indexes = self.selectedIndexes()
        if not indexes:
            self.delAction.setEnabled(False)
        
            self.menu.addAction( self.addAction )
            self.menu.addSeparator()
        else:
            self.delAction.setEnabled(True)
            
            self.menu.addAction( self.addAction )
            self.menu.addSeparator()
        self.menu.popup( self.mapToGlobal(pos) )

    def getHelpFramework(self):
        """
        Get help from framework
        """
        self.helper = Helper.instance()
        val = self.helper.helpFramework(moduleName='TestExecutor', className='TestCase', functionName='addStep')
        if val is None:
            val = {}
            val['obj'] = {}
        else:
            desc = val['desc'].strip()
            desc_splitted = desc.splitlines()
            
            val['return-value'] = False
            params = []
            param = {}
            for line in desc_splitted:
                line = line.strip() 
                if line.startswith('@param '):
                    paramName = line.split(':', 1)[0].split('@param ')[1].strip()
                    param['name'] = paramName
                elif line.startswith('@type '):
                    paramType = line.split(':', 1)[1].strip()
                    param['type'] = paramType
                    params.append( param )
                    param = {}
                elif line.startswith('@return'):
                    val['return-value'] = True
                else:   
                    pass

            val['obj'] = params
        return val

    def addStep(self):
        """
        Add step
        """
        helpFramework = self.getHelpFramework()
        stepDialog = StepDialog(helpFramework) #, stepId=stepId)
        if stepDialog.exec_() == QDialog.Accepted:
            stepParams = stepDialog.getValues()
            self.insertItem(stepParams=stepParams)
                                       
    def insertItem(self, stepParams):
        """
        Insert item
        """
        indexes = self.selectedIndexes()
        if not len(indexes):
            row = self.model.rowCount()
        else:
            index = self.currentIndex()
            row = index.row()
        data = self.model.getData()

        # add data to model
        stepParams['id'] = "%s" % (len(data) + 1)
        data.insert(row + 1, stepParams)

        if sys.version_info > (3,): 
            self.model.beginResetModel()
            self.model.endResetModel()
        else:
            self.reset()
            
        self.delAllAction.setEnabled(True)
        
        self.setData()

    def deleteAction(self):
        """
        Delete action
        """
        indexes = self.selectedIndexes()
        if not indexes:
            return

        # map proxy indexes to source
        sourceIndexes = []
        for proxyIndex in indexes:
            if not proxyIndex.isValid():
                return
            else:
                sourceIndexes.append( self.proxyModel.mapToSource( proxyIndex ) )
        
        if sourceIndexes:
            answer = QMessageBox.question(self,  self.tr("Remove"),  
                                            self.tr("Do you want to remove the selection?"), 
                                            QMessageBox.Yes | QMessageBox.No)
            if answer == QMessageBox.Yes:
                self.removeValues(sourceIndexes)

    def removeValues(self, indexes):
        """
        Remove values from data

        @param indexes: 
        @type indexes:
        """
        if not indexes:
            return
        
        # data from model
        datas = self.model.getData()

        # remove duplicate index
        cleanIndexes = {}
        for index in indexes:
            if index.row() not in cleanIndexes:
                cleanIndexes[index.row()] = index

        for cleanIndex in list(cleanIndexes.keys()): # for python3 support
            datas.pop(cleanIndex)

        if sys.version_info > (3,): 
            self.model.beginResetModel()
            self.model.endResetModel()
        else:
            self.reset()
            
        self.setData( signal = True )

    def setSteps(self, steps):
        """
        Set steps
        """
        self.model.setDataModel( steps )
        self.setData( signal = False )
        
    def clearItems(self):
        """
        Clear all items
        """
        reply = QMessageBox.question(self, self.tr("Clear all steps"), 
                                        self.tr("Are you sure ?"),
                                        QMessageBox.Yes | QMessageBox.No )
        if reply == QMessageBox.Yes:
            data = self.model.getData()
            try:
                for i in xrange(len(data)):
                    data.pop()
            except Exception as e:
                pass

            if sys.version_info > (3,): 
                self.model.beginResetModel()
                self.model.endResetModel()
            else:
                self.reset()
                
            self.setData()
            
            self.delAllAction.setEnabled(False)
            self.delAction.setEnabled(False)
            
    def clear (self):
        """
        clear contents
        """
        self.model.setDataModel( [] )

    def setData(self, signal = True):
        """
        Set table data

        @param signal: 
        @type signal: boolean
        """
        if signal: self.DataChanged.emit()
Example #51
0
class ClientExceptionsViewer( QWidget ):
    " Implements the client exceptions viewer for a debugger "

    def __init__( self, parent, ignoredExceptionsViewer ):
        QWidget.__init__( self, parent )

        self.__ignoredExceptionsViewer = ignoredExceptionsViewer
        self.__currentItem = None

        self.__createPopupMenu()
        self.__createLayout()

        GlobalData().project.projectChanged.connect( self.__onProjectChanged )
        return

    def setFocus( self ):
        " Sets the widget focus "
        self.exceptionsList.setFocus()
        return

    def __createPopupMenu( self ):
        " Creates the popup menu "
        self.__excptMenu = QMenu()
        self.__addToIgnoreMenuItem = self.__excptMenu.addAction(
                    "Add to ignore list", self.__onAddToIgnore )
        self.__jumpToCodeMenuItem = self.__excptMenu.addAction(
                    "Jump to code", self.__onJumpToCode )
        return

    def __createLayout( self ):
        " Creates the widget layout "

        verticalLayout = QVBoxLayout( self )
        verticalLayout.setContentsMargins( 0, 0, 0, 0 )
        verticalLayout.setSpacing( 0 )

        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle( QFrame.StyledPanel )
        self.headerFrame.setAutoFillBackground( True )
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color( QPalette.Background )
        headerBackground.setRgb( min( headerBackground.red() + 30, 255 ),
                                 min( headerBackground.green() + 30, 255 ),
                                 min( headerBackground.blue() + 30, 255 ) )
        headerPalette.setColor( QPalette.Background, headerBackground )
        self.headerFrame.setPalette( headerPalette )
        self.headerFrame.setFixedHeight( 24 )

        self.__excptLabel = QLabel( "Exceptions" )

        fixedSpacer = QSpacerItem( 3, 3 )

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins( 0, 0, 0, 0 )
        headerLayout.addSpacerItem( fixedSpacer )
        headerLayout.addWidget( self.__excptLabel )
        self.headerFrame.setLayout( headerLayout )

        self.exceptionsList = QTreeWidget( self )
        self.exceptionsList.setSortingEnabled( False )
        self.exceptionsList.setAlternatingRowColors( True )
        self.exceptionsList.setRootIsDecorated( True )
        self.exceptionsList.setItemsExpandable( True )
        self.exceptionsList.setUniformRowHeights( True )
        self.exceptionsList.setSelectionMode( QAbstractItemView.SingleSelection )
        self.exceptionsList.setSelectionBehavior( QAbstractItemView.SelectRows )
        self.exceptionsList.setItemDelegate( NoOutlineHeightDelegate( 4 ) )
        self.exceptionsList.setContextMenuPolicy( Qt.CustomContextMenu )

        self.__addToIgnoreButton = QAction(
            PixmapCache().getIcon( 'add.png' ),
            "Add exception to the list of ignored", self )
        self.__addToIgnoreButton.triggered.connect( self.__onAddToIgnore )
        self.__addToIgnoreButton.setEnabled( False )


        expandingSpacer = QWidget()
        expandingSpacer.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding )

        self.__jumpToCodeButton = QAction(
            PixmapCache().getIcon( 'gotoline.png' ),
            "Jump to the code", self )
        self.__jumpToCodeButton.triggered.connect( self.__onJumpToCode )
        self.__jumpToCodeButton.setEnabled( False )

        self.__delAllButton = QAction(
            PixmapCache().getIcon( 'trash.png' ),
            "Delete all the client exceptions", self )
        self.__delAllButton.triggered.connect( self.__onDelAll )
        self.__delAllButton.setEnabled( False )

        self.toolbar = QToolBar()
        self.toolbar.setOrientation( Qt.Horizontal )
        self.toolbar.setMovable( False )
        self.toolbar.setAllowedAreas( Qt.TopToolBarArea )
        self.toolbar.setIconSize( QSize( 16, 16 ) )
        self.toolbar.setFixedHeight( 28 )
        self.toolbar.setContentsMargins( 0, 0, 0, 0 )
        self.toolbar.addAction( self.__addToIgnoreButton )
        self.toolbar.addAction( self.__jumpToCodeButton )
        self.toolbar.addWidget( expandingSpacer )
        self.toolbar.addAction( self.__delAllButton )

        self.exceptionsList.itemDoubleClicked.connect(
                                            self.__onExceptionDoubleClicked )
        self.exceptionsList.customContextMenuRequested.connect(
                                            self.__showContextMenu )
        self.exceptionsList.itemSelectionChanged.connect(
                                            self.__onSelectionChanged )


        self.exceptionsList.setHeaderLabels( [ "Exception" ] )

        verticalLayout.addWidget( self.headerFrame )
        verticalLayout.addWidget( self.toolbar )
        verticalLayout.addWidget( self.exceptionsList )
        return

    def clear( self ):
        " Clears the content "
        self.exceptionsList.clear()
        self.__updateExceptionsLabel()
        self.__addToIgnoreButton.setEnabled( False )
        self.__jumpToCodeButton.setEnabled( False )
        self.__delAllButton.setEnabled( False )
        self.__currentItem = None
        self.emit( SIGNAL( 'ClientExceptionsCleared' ) )
        return

    def __onExceptionDoubleClicked( self, item, column ):
        " Triggered when an exception is double clicked "
        if self.__currentItem is not None:
            if self.__currentItem.getType() == STACK_FRAME_ITEM:
                self.__onJumpToCode()
                return

            # This is an exception item itself.
            # Open a separate dialog window with th detailed info.

        return

    def __showContextMenu( self, coord ):
        " Shows the frames list context menu "
        self.__contextItem = self.exceptionsList.itemAt( coord )

        self.__addToIgnoreMenuItem.setEnabled( self.__addToIgnoreButton.isEnabled() )
        self.__jumpToCodeMenuItem.setEnabled( self.__jumpToCodeButton.isEnabled() )

        if self.__contextItem is not None:
            self.__excptMenu.popup( QCursor.pos() )
        return

    def __onAddToIgnore( self ):
        " Adds an exception into the ignore list "
        if self.__currentItem is not None:
            self.__ignoredExceptionsViewer.addExceptionFilter(
                        str( self.__currentItem.getExceptionType() ) )
            self.__addToIgnoreButton.setEnabled( False )
        return

    def __onJumpToCode( self ):
        " Jumps to the corresponding source code line "
        if self.__currentItem is not None:
            if self.__currentItem.getType() == STACK_FRAME_ITEM:
                fileName = self.__currentItem.getFileName()
                if '<' not in fileName and '>' not in fileName:
                    lineNumber = self.__currentItem.getLineNumber()

                    editorsManager = GlobalData().mainWindow.editorsManager()
                    editorsManager.openFile( fileName, lineNumber )
                    editor = editorsManager.currentWidget().getEditor()
                    editor.gotoLine( lineNumber )
                    editorsManager.currentWidget().setFocus()
        return

    def __onDelAll( self ):
        " Triggered when all the exceptions should be deleted "
        self.clear()
        return

    def addException( self, exceptionType, exceptionMessage,
                            stackTrace ):
        " Adds the exception to the view "
        for index in xrange( self.exceptionsList.topLevelItemCount() ):
            item = self.exceptionsList.topLevelItem( index )
            if item.equal( exceptionType, exceptionMessage, stackTrace ):
                item.incrementCounter()
                self.exceptionsList.clearSelection()
                self.exceptionsList.setCurrentItem( item )
                self.__updateExceptionsLabel()
                return

        item = ExceptionItem( self.exceptionsList, exceptionType,
                              exceptionMessage, stackTrace )
        self.exceptionsList.clearSelection()
        self.exceptionsList.setCurrentItem( item )
        self.__updateExceptionsLabel()
        self.__delAllButton.setEnabled( True )
        return

    def __updateExceptionsLabel( self ):
        " Updates the exceptions header label "
        total = self.getTotalCount()
        if total > 0:
            self.__excptLabel.setText( "Exceptions (total: " +
                                       str( total ) + ")" )
        else:
            self.__excptLabel.setText( "Exceptions" )
        return

    def getTotalCount( self ):
        " Provides the total number of exceptions "
        count = 0
        for index in xrange( self.exceptionsList.topLevelItemCount() ):
            count += self.exceptionsList.topLevelItem( index ).getCount()
        return count

    def __onProjectChanged( self, what ):
        " Triggered when a project is changed "
        if what == CodimensionProject.CompleteProject:
            self.clear()
        return

    def __onSelectionChanged( self ):
        " Triggered when the current item is changed "
        selected = list( self.exceptionsList.selectedItems() )
        if selected:
            self.__currentItem = selected[ 0 ]
            if self.__currentItem.getType() == STACK_FRAME_ITEM:
                fileName = self.__currentItem.getFileName()
                if '<' in fileName or '>' in fileName:
                    self.__jumpToCodeButton.setEnabled( False )
                else:
                    self.__jumpToCodeButton.setEnabled( True )
                self.__addToIgnoreButton.setEnabled( False )
            else:
                self.__jumpToCodeButton.setEnabled( False )
                excType = str( self.__currentItem.getExceptionType() )
                if self.__ignoredExceptionsViewer.isIgnored( excType ) or \
                   " " in excType or excType.startswith( "unhandled" ):
                    self.__addToIgnoreButton.setEnabled( False )
                else:
                    self.__addToIgnoreButton.setEnabled( True )
        else:
            self.__currentItem = None
            self.__addToIgnoreButton.setEnabled( False )
            self.__jumpToCodeButton.setEnabled( False )
        return
Example #52
0
class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin):
    """
    Shell base widget
    """
    
    def __init__(self, parent, history_filename, profile=False):
        """
        parent : specifies the parent widget
        """
        ConsoleBaseWidget.__init__(self, parent)
        SaveHistoryMixin.__init__(self)
                
        # Prompt position: tuple (line, index)
        self.current_prompt_pos = None
        self.new_input_line = True
        
        # History
        self.histidx = None
        self.hist_wholeline = False
        assert isinstance(history_filename, (str, unicode))
        self.history_filename = history_filename
        self.history = self.load_history()
        
        # Session
        self.historylog_filename = CONF.get('main', 'historylog_filename',
                                            get_conf_path('history.log'))
        
        # Context menu
        self.menu = None
        self.setup_context_menu()

        # Simple profiling test
        self.profile = profile
        
        # Buffer to increase performance of write/flush operations
        self.__buffer = []
        self.__timestamp = 0.0
        self.__flushtimer = QTimer(self)
        self.__flushtimer.setSingleShot(True)
        self.connect(self.__flushtimer, SIGNAL('timeout()'), self.flush)

        # Give focus to widget
        self.setFocus()
                
        # Calltips
        calltip_size = CONF.get('shell_appearance', 'calltips/size')
        calltip_font = get_font('shell_appearance', 'calltips')
        self.setup_calltips(calltip_size, calltip_font)
        
        # Completion
        completion_size = CONF.get('shell_appearance', 'completion/size')
        completion_font = get_font('shell_appearance', 'completion')
        self.completion_widget.setup_appearance(completion_size,
                                                completion_font)
        # Cursor width
        self.setCursorWidth( CONF.get('shell_appearance', 'cursor/width') )
        
    def toggle_wrap_mode(self, enable):
        """Enable/disable wrap mode"""
        self.set_wrap_mode('character' if enable else None)

    def set_font(self, font):
        """Set shell styles font"""
        self.set_pythonshell_font(font)
        cursor = self.textCursor()
        cursor.select(QTextCursor.Document)
        charformat = QTextCharFormat()
        charformat.setFontFamily(font.family())
        charformat.setFontPointSize(font.pointSize())
        cursor.mergeCharFormat(charformat)


    #------ Context menu
    def setup_context_menu(self):
        """Setup shell context menu"""
        self.menu = QMenu(self)
        self.cut_action = create_action(self, _("Cut"),
                                        shortcut=keybinding('Cut'),
                                        icon=get_icon('editcut.png'),
                                        triggered=self.cut)
        self.copy_action = create_action(self, _("Copy"),
                                         shortcut=keybinding('Copy'),
                                         icon=get_icon('editcopy.png'),
                                         triggered=self.copy)
        paste_action = create_action(self, _("Paste"),
                                     shortcut=keybinding('Paste'),
                                     icon=get_icon('editpaste.png'),
                                     triggered=self.paste)
        save_action = create_action(self, _("Save history log..."),
                                    icon=get_icon('filesave.png'),
                                    tip=_("Save current history log (i.e. all "
                                          "inputs and outputs) in a text file"),
                                    triggered=self.save_historylog)
        self.delete_action = create_action(self, _("Delete"),
                                    shortcut=keybinding('Delete'),
                                    icon=get_icon('editdelete.png'),
                                    triggered=self.delete)
        selectall_action = create_action(self, _("Select All"),
                                    shortcut=keybinding('SelectAll'),
                                    icon=get_icon('selectall.png'),
                                    triggered=self.selectAll)
        add_actions(self.menu, (self.cut_action, self.copy_action,
                                paste_action, self.delete_action, None,
                                selectall_action, None, save_action) )
          
    def contextMenuEvent(self, event):
        """Reimplement Qt method"""
        state = self.has_selected_text()
        self.copy_action.setEnabled(state)
        self.cut_action.setEnabled(state)
        self.delete_action.setEnabled(state)
        self.menu.popup(event.globalPos())
        event.accept()        
        
        
    #------ Input buffer
    def get_current_line_from_cursor(self):
        return self.get_text('cursor', 'eof')
    
    def _select_input(self):
        """Select current line (without selecting console prompt)"""
        line, index = self.get_position('eof')
        if self.current_prompt_pos is None:
            pline, pindex = line, index
        else:
            pline, pindex = self.current_prompt_pos
        self.setSelection(pline, pindex, line, index)
            
    def clear_line(self):
        """Clear current line (without clearing console prompt)"""
        if self.current_prompt_pos is not None:
            self.remove_text(self.current_prompt_pos, 'eof')
        
    def clear_terminal(self):
        """
        Clear terminal window
        Child classes reimplement this method to write prompt
        """
        self.clear()

    # The buffer being edited
    def _set_input_buffer(self, text):
        """Set input buffer"""
        if self.current_prompt_pos is not None:
            self.replace_text(self.current_prompt_pos, 'eol', text)
        else:
            self.insert(text)
        self.set_cursor_position('eof')

    def _get_input_buffer(self):
        """Return input buffer"""
        input_buffer = ''
        if self.current_prompt_pos is not None:
            input_buffer = self.get_text(self.current_prompt_pos, 'eol')
            input_buffer = input_buffer.replace(os.linesep, '\n')
        return input_buffer

    input_buffer = pyqtProperty("QString", _get_input_buffer, _set_input_buffer)
        
        
    #------ Prompt
    def new_prompt(self, prompt):
        """
        Print a new prompt and save its (line, index) position
        """
        if self.get_cursor_line_column()[1] != 0:
            self.write('\n')
        self.write(prompt, prompt=True)
        # now we update our cursor giving end of prompt
        self.current_prompt_pos = self.get_position('cursor')
        self.ensureCursorVisible()
        self.new_input_line = False
        
    def check_selection(self):
        """
        Check if selected text is r/w,
        otherwise remove read-only parts of selection
        """
        if self.current_prompt_pos is None:
            self.set_cursor_position('eof')
        else:
            self.truncate_selection(self.current_prompt_pos)
        
        
    #------ Copy / Keyboard interrupt
    def copy(self):
        """Copy text to clipboard... or keyboard interrupt"""
        if self.has_selected_text():
            ConsoleBaseWidget.copy(self)
        elif not sys.platform == 'darwin':
            self.interrupt()

    def interrupt(self):
        """Keyboard interrupt"""
        self.emit(SIGNAL("keyboard_interrupt()"))

    def cut(self):
        """Cut text"""
        self.check_selection()
        if self.has_selected_text():
            ConsoleBaseWidget.cut(self)

    def delete(self):
        """Remove selected text"""
        self.check_selection()
        if self.has_selected_text():
            ConsoleBaseWidget.remove_selected_text(self)
        
    def save_historylog(self):
        """Save current history log (all text in console)"""
        title = _("Save history log")
        self.emit(SIGNAL('redirect_stdio(bool)'), False)
        filename, _selfilter = getsavefilename(self, title,
                    self.historylog_filename, "%s (*.log)" % _("History logs"))
        self.emit(SIGNAL('redirect_stdio(bool)'), True)
        if filename:
            filename = osp.normpath(filename)
            try:
                encoding.write(unicode(self.get_text_with_eol()), filename)
                self.historylog_filename = filename
                CONF.set('main', 'historylog_filename', filename)
            except EnvironmentError, error:
                QMessageBox.critical(self, title,
                                     _("<b>Unable to save file '%s'</b>"
                                       "<br><br>Error message:<br>%s"
                                       ) % (osp.basename(filename),
                                            unicode(error)))
Example #53
0
class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin):
    """
    Shell base widget
    """
    def __init__(self, parent, history_filename, profile=False):
        """
        parent : specifies the parent widget
        """
        ConsoleBaseWidget.__init__(self, parent)
        SaveHistoryMixin.__init__(self)

        # Prompt position: tuple (line, index)
        self.current_prompt_pos = None
        self.new_input_line = True

        # History
        self.histidx = None
        self.hist_wholeline = False
        assert isinstance(history_filename, (str, unicode))
        self.history_filename = history_filename
        self.history = self.load_history()

        # Session
        self.historylog_filename = CONF.get('main', 'historylog_filename',
                                            get_conf_path('history.log'))

        # Context menu
        self.menu = None
        self.setup_context_menu()

        # Simple profiling test
        self.profile = profile

        # Buffer to increase performance of write/flush operations
        self.__buffer = []
        self.__timestamp = 0.0
        self.__flushtimer = QTimer(self)
        self.__flushtimer.setSingleShot(True)
        self.connect(self.__flushtimer, SIGNAL('timeout()'), self.flush)

        # Give focus to widget
        self.setFocus()

        # Calltips
        calltip_size = CONF.get('shell_appearance', 'calltips/size')
        calltip_font = get_font('shell_appearance', 'calltips')
        self.setup_calltips(calltip_size, calltip_font)

        # Completion
        completion_size = CONF.get('shell_appearance', 'completion/size')
        completion_font = get_font('shell_appearance', 'completion')
        self.completion_widget.setup_appearance(completion_size,
                                                completion_font)
        # Cursor width
        self.setCursorWidth(CONF.get('shell_appearance', 'cursor/width'))

    def toggle_wrap_mode(self, enable):
        """Enable/disable wrap mode"""
        self.set_wrap_mode('character' if enable else None)

    def set_font(self, font):
        """Set shell styles font"""
        self.set_pythonshell_font(font)
        cursor = self.textCursor()
        cursor.select(QTextCursor.Document)
        charformat = QTextCharFormat()
        charformat.setFontFamily(font.family())
        charformat.setFontPointSize(font.pointSize())
        cursor.mergeCharFormat(charformat)

    #------ Context menu
    def setup_context_menu(self):
        """Setup shell context menu"""
        self.menu = QMenu(self)
        self.cut_action = create_action(self,
                                        _("Cut"),
                                        shortcut=keybinding('Cut'),
                                        icon=get_icon('editcut.png'),
                                        triggered=self.cut)
        self.copy_action = create_action(self,
                                         _("Copy"),
                                         shortcut=keybinding('Copy'),
                                         icon=get_icon('editcopy.png'),
                                         triggered=self.copy)
        paste_action = create_action(self,
                                     _("Paste"),
                                     shortcut=keybinding('Paste'),
                                     icon=get_icon('editpaste.png'),
                                     triggered=self.paste)
        save_action = create_action(self,
                                    _("Save history log..."),
                                    icon=get_icon('filesave.png'),
                                    tip=_(
                                        "Save current history log (i.e. all "
                                        "inputs and outputs) in a text file"),
                                    triggered=self.save_historylog)
        self.delete_action = create_action(self,
                                           _("Delete"),
                                           shortcut=keybinding('Delete'),
                                           icon=get_icon('editdelete.png'),
                                           triggered=self.delete)
        selectall_action = create_action(self,
                                         _("Select All"),
                                         shortcut=keybinding('SelectAll'),
                                         icon=get_icon('selectall.png'),
                                         triggered=self.selectAll)
        add_actions(
            self.menu,
            (self.cut_action, self.copy_action, paste_action,
             self.delete_action, None, selectall_action, None, save_action))

    def contextMenuEvent(self, event):
        """Reimplement Qt method"""
        state = self.has_selected_text()
        self.copy_action.setEnabled(state)
        self.cut_action.setEnabled(state)
        self.delete_action.setEnabled(state)
        self.menu.popup(event.globalPos())
        event.accept()

    #------ Input buffer
    def get_current_line_from_cursor(self):
        return self.get_text('cursor', 'eof')

    def _select_input(self):
        """Select current line (without selecting console prompt)"""
        line, index = self.get_position('eof')
        if self.current_prompt_pos is None:
            pline, pindex = line, index
        else:
            pline, pindex = self.current_prompt_pos
        self.setSelection(pline, pindex, line, index)

    def clear_line(self):
        """Clear current line (without clearing console prompt)"""
        if self.current_prompt_pos is not None:
            self.remove_text(self.current_prompt_pos, 'eof')

    def clear_terminal(self):
        """
        Clear terminal window
        Child classes reimplement this method to write prompt
        """
        self.clear()

    # The buffer being edited
    def _set_input_buffer(self, text):
        """Set input buffer"""
        if self.current_prompt_pos is not None:
            self.replace_text(self.current_prompt_pos, 'eol', text)
        else:
            self.insert(text)
        self.set_cursor_position('eof')

    def _get_input_buffer(self):
        """Return input buffer"""
        input_buffer = ''
        if self.current_prompt_pos is not None:
            input_buffer = self.get_text(self.current_prompt_pos, 'eol')
            input_buffer = input_buffer.replace(os.linesep, '\n')
        return input_buffer

    input_buffer = pyqtProperty("QString", _get_input_buffer,
                                _set_input_buffer)

    #------ Prompt
    def new_prompt(self, prompt):
        """
        Print a new prompt and save its (line, index) position
        """
        if self.get_cursor_line_column()[1] != 0:
            self.write('\n')
        self.write(prompt, prompt=True)
        # now we update our cursor giving end of prompt
        self.current_prompt_pos = self.get_position('cursor')
        self.ensureCursorVisible()
        self.new_input_line = False

    def check_selection(self):
        """
        Check if selected text is r/w,
        otherwise remove read-only parts of selection
        """
        if self.current_prompt_pos is None:
            self.set_cursor_position('eof')
        else:
            self.truncate_selection(self.current_prompt_pos)

    #------ Copy / Keyboard interrupt
    def copy(self):
        """Copy text to clipboard... or keyboard interrupt"""
        if self.has_selected_text():
            ConsoleBaseWidget.copy(self)
        elif not sys.platform == 'darwin':
            self.interrupt()

    def interrupt(self):
        """Keyboard interrupt"""
        self.emit(SIGNAL("keyboard_interrupt()"))

    def cut(self):
        """Cut text"""
        self.check_selection()
        if self.has_selected_text():
            ConsoleBaseWidget.cut(self)

    def delete(self):
        """Remove selected text"""
        self.check_selection()
        if self.has_selected_text():
            ConsoleBaseWidget.remove_selected_text(self)

    def save_historylog(self):
        """Save current history log (all text in console)"""
        title = _("Save history log")
        self.emit(SIGNAL('redirect_stdio(bool)'), False)
        filename, _selfilter = getsavefilename(
            self, title, self.historylog_filename,
            "%s (*.log)" % _("History logs"))
        self.emit(SIGNAL('redirect_stdio(bool)'), True)
        if filename:
            filename = osp.normpath(filename)
            try:
                encoding.write(unicode(self.get_text_with_eol()), filename)
                self.historylog_filename = filename
                CONF.set('main', 'historylog_filename', filename)
            except EnvironmentError, error:
                QMessageBox.critical(
                    self, title,
                    _("<b>Unable to save file '%s'</b>"
                      "<br><br>Error message:<br>%s") %
                    (osp.basename(filename), unicode(error)))
Example #54
0
class BasicMonitor(QTableWidget):
    """
    基础监控
    
    headerDict中的值对应的字典格式如下
    {'chinese': u'中文名', 'cellType': BasicCell}
    
    """
    signal = QtCore.pyqtSignal(type(Event()))
    signal_clear = QtCore.pyqtSignal(type(Event()))
    
    # ----------------------------------------------------------------------
    def __init__(self, mainEngine=None, eventEngine=None, parent=None):
        """Constructor"""
        super(BasicMonitor, self).__init__(parent)
        
        self.mainEngine = mainEngine
        self.eventEngine = eventEngine
        
        self.signalemit = None
        self.signalclearemit = None
        
        # 保存表头标签用
        self.headerDict = OrderedDict()  # 有序字典,key是英文名,value是对应的配置字典
        self.headerList = []  # 对应self.headerDict.keys()
        
        # 保存相关数据用
        self.dataDict = {}  # 字典,key是字段对应的数据,value是保存相关单元格的字典
        self.dataKey = ''  # 字典键对应的数据字段
        
        # 监控的事件类型
        self.eventType = ''
        self.eventTypeClear = ''
        # 字体
        self.font = None
        
        # 保存数据对象到单元格
        self.saveData = False
        
        # 默认不允许根据表头进行排序,需要的组件可以开启
        self.sorting = False
        
        # 初始化右键菜单
        self.initMenu()
    
    # ----------------------------------------------------------------------
    def setHeaderDict(self, headerDict):
        """设置表头有序字典"""
        self.headerDict = headerDict
        self.headerList = list(headerDict.keys())
    
    # ----------------------------------------------------------------------
    def setDataKey(self, dataKey):
        """设置数据字典的键"""
        self.dataKey = dataKey
    
    # ----------------------------------------------------------------------
    def setEventType(self, eventType1, eventType2=''):
        """设置监控的事件类型"""
        self.eventType = eventType1
        self.eventTypeClear = eventType2
    
    # ----------------------------------------------------------------------
    def setFont(self, font):
        """设置字体"""
        self.font = font
    
    # ----------------------------------------------------------------------
    def setSaveData(self, saveData):
        """设置是否要保存数据到单元格"""
        self.saveData = saveData
    
    # ----------------------------------------------------------------------
    def initTable(self):
        """初始化表格"""
        # 设置表格的列数
        col = len(self.headerDict)
        self.setColumnCount(col)
        
        # 设置列表头
        labels = [d['chinese'] for d in list(self.headerDict.values())]
        self.setHorizontalHeaderLabels(labels)
        
        # 关闭左边的垂直表头
        self.verticalHeader().setVisible(False)
        
        # 设为不可编辑
        self.setEditTriggers(self.NoEditTriggers)
        
        # 设为行交替颜色
        self.setAlternatingRowColors(True)
        
        # 设置允许排序
        self.setSortingEnabled(self.sorting)
        
        # set stretch
        # self.horizontalHeader().setResizeMode(QHeaderView.Stretch)
    
    # ----------------------------------------------------------------------
    def registerEvent(self):
        """注册GUI更新相关的事件监听"""
        self.signal.connect(self.updateEvent)
        self.signalemit = self.signal.emit
        self.eventEngine.register(self.eventType, self.signalemit)
        if len(self.eventTypeClear) > 0:
            self.signal_clear.connect(self.clearEvent)
            self.signalclearemit = self.signal_clear.emit
            self.eventEngine.register(self.eventTypeClear, self.signalclearemit)
    
    def unRegister(self):
        self.eventEngine.unregister(self.eventType, self.signalemit)
        if len(self.eventTypeClear) > 0:
            self.eventEngine.unregister(self.eventTypeClear, self.signalclearemit)
    
    # ----------------------------------------------------------------------
    def updateEvent(self, event):
        """收到事件更新"""
        data = event.dict_['data']
        self.updateData(data)
    
    def clearEvent(self, event):
        """收到事件更新"""
        self.dataDict.clear()
        self.setRowCount(0)
    
    # ----------------------------------------------------------------------
    def updateData(self, data):
        """将数据更新到表格中"""
        # 如果允许了排序功能,则插入数据前必须关闭,否则插入新的数据会变乱
        if self.sorting:
            self.setSortingEnabled(False)
        
        # 如果设置了dataKey,则采用存量更新模式
        if self.dataKey:
            #key = data.__getattribute__(self.dataKey)
            key = getattr(data, self.dataKey, None)
            # 如果键在数据字典中不存在,则先插入新的一行,并创建对应单元格
            if key not in self.dataDict:
                self.insertRow(0)
                d = {}
                for n, header in enumerate(self.headerList):
                    content = safeUnicode(data.__getattribute__(header))
                    # content = safeUnicode(getattr(data, header, None))
                    cellType = self.headerDict[header]['cellType']
                    try:
                        cell = cellType(content, self.mainEngine)
                    except Exception as e:
                        print(cellType)
                        print(data)
                        print(content)
                        raise(e)
                    
                    if self.font:
                        cell.setFont(self.font)  # 如果设置了特殊字体,则进行单元格设置
                    
                    if self.saveData:  # 如果设置了保存数据对象,则进行对象保存
                        cell.data = data
                    
                    self.setItem(0, n, cell)
                    d[header] = cell
                self.dataDict[key] = d
            # 否则如果已经存在,则直接更新相关单元格
            else:
                d = self.dataDict[key]
                for header in self.headerList:
                    content = safeUnicode(getattr(data, header, None))
                    cell = d[header]
                    cell.setContent(content)
                    
                    if self.saveData:  # 如果设置了保存数据对象,则进行对象保存
                        cell.data = data
                        # 否则采用增量更新模式
        else:
            self.insertRow(0)
            for n, header in enumerate(self.headerList):
                content = safeUnicode(data.__getattribute__(header))
                cellType = self.headerDict[header]['cellType']
                cell = cellType(content, self.mainEngine)
                
                if self.font:
                    cell.setFont(self.font)
                
                if self.saveData:
                    cell.data = data
                
                self.setItem(0, n, cell)
                
                # 调整列宽
        self.resizeColumns()
        
        # 重新打开排序
        if self.sorting:
            self.setSortingEnabled(True)
    
    # ----------------------------------------------------------------------
    def resizeColumns(self):
        """调整各列的大小"""
        self.horizontalHeader().resizeSections(QHeaderView.ResizeToContents)
    
    # ----------------------------------------------------------------------
    def setSorting(self, sorting):
        """设置是否允许根据表头排序"""
        self.sorting = sorting
    
    # ----------------------------------------------------------------------
    def saveToCsv(self):
        """保存表格内容到CSV文件"""
        # 先隐藏右键菜单
        self.menu.close()
        
        # 获取想要保存的文件名
        path = QtGui.QFileDialog.getSaveFileName(self, '保存数据', '', 'CSV(*.csv)')
        
        try:
            if not path.isEmpty():
                with open(safeUnicode(path), 'wb') as f:
                    writer = csv.writer(f)
                    
                    # 保存标签
                    headers = [header.encode('gbk') for header in self.headerList]
                    writer.writerow(headers)
                    
                    # 保存每行内容
                    for row in range(self.rowCount()):
                        rowdata = []
                        for column in range(self.columnCount()):
                            item = self.item(row, column)
                            if item is not None:
                                rowdata.append(
                                        safeUnicode(item.text()).encode('gbk'))
                            else:
                                rowdata.append('')
                        writer.writerow(rowdata)
        except IOError:
            pass
    
    # ----------------------------------------------------------------------
    def initMenu(self):
        """初始化右键菜单"""
        self.menu = QMenu(self)

        '''
        saveAction = QAction(u'保存内容', self)
        saveAction.triggered.connect(self.saveToCsv)
        
        resizeAction = QAction(u'调整列宽', self)
        resizeAction.triggered.connect(self.resizeColumns)
        
        self.menu.addAction(resizeAction)
        self.menu.addAction(saveAction)
        '''

    # ----------------------------------------------------------------------
    def contextMenuEvent(self, event):
        """右键点击事件"""
        self.menu.popup(QtGui.QCursor.pos())
Example #55
0
class AdaptersTableView(QTableView):
    """
    Adapters table view
    """
    DataChanged = pyqtSignal()

    def __init__(self, parent, helper, testParams, testDescrs):
        """
        Description table view constructor
        """
        QTableView.__init__(self, parent)

        self.__parent = parent
        self.helper = helper
        self.testParams = testParams
        self.testDescrs = testDescrs
        self.createWidgets()
        self.createConnections()
        self.createActions()

    def getAgents(self):
        """
        Get test agents 
        """
        return self.testParams.agents.table().model.getData()

    def getInputs(self):
        """
        Get test inputs 
        """
        return self.testParams.parameters.table().model.getData()

    def getOutputs(self):
        """
        Get test outputs 
        """
        return self.testParams.parametersOutput.table().model.getData()

    def createWidgets(self):
        """
        Create qt widgets
        """
        self.proxyModel = QSortFilterProxyModel(self)
        self.proxyModel.setDynamicSortFilter(True)

        self.model = DescriptionTableModel(self)
        self.setModel(self.proxyModel)
        self.proxyModel.setSourceModel(self.model)

        self.setFrameShape(QFrame.StyledPanel)
        self.setShowGrid(True)
        self.setGridStyle(Qt.DotLine)

        self.setSelectionMode(QAbstractItemView.SingleSelection)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.verticalHeader().setVisible(False)
        self.horizontalHeader().setHighlightSections(False)
        self.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
        self.horizontalHeader().setStretchLastSection(True)

        self.setItemDelegateForColumn(COL_SUMMARY_ACTION,
                                      AdapterDelegate(self))

        self.setColumnWidth(COL_ID_ACTION, 45)

    def createConnections(self):
        """
        Create qt connections
        """
        self.customContextMenuRequested.connect(self.onPopupMenu)
        self.clicked.connect(self.onAbstractItemClicked)

    def createActions(self):
        """
        Qt actions
        """
        self.delAction = QtHelper.createAction(
            self,
            self.tr("&Delete"),
            self.deleteAction,
            icon=QIcon(":/adapters-del.png"),
            tip=self.tr('Delete the selected adapter'))
        self.delAllAction = QtHelper.createAction(
            self,
            self.tr("&Delete All"),
            self.clearItems,
            icon=QIcon(":/test-parameter-clear.png"),
            tip=self.tr('Delete all adapters'))

        # set default actions
        self.delAction.setEnabled(False)
        self.delAllAction.setEnabled(False)

    def onAbstractItemClicked(self):
        """
        Called on item clicked
        """
        indexes = self.selectedIndexes()
        if not indexes:
            self.delAction.setEnabled(False)
        else:
            self.delAction.setEnabled(True)

    def deleteAction(self):
        """
        Delete action
        """
        indexes = self.selectedIndexes()
        if not indexes:
            return

        # map proxy indexes to source
        sourceIndexes = []
        for proxyIndex in indexes:
            if not proxyIndex.isValid():
                return
            else:
                sourceIndexes.append(self.proxyModel.mapToSource(proxyIndex))

        if sourceIndexes:
            answer = QMessageBox.question(
                self, self.tr("Remove"),
                self.tr("Do you want to remove the selection?"),
                QMessageBox.Yes | QMessageBox.No)
            if answer == QMessageBox.Yes:
                self.removeValues(sourceIndexes)

    def removeValues(self, indexes):
        """
        Remove values from data

        @param indexes: 
        @type indexes:
        """
        if not indexes:
            return

        # data from model
        datas = self.model.getData()

        # remove duplicate index
        cleanIndexes = {}
        for index in indexes:
            if index.row() not in cleanIndexes:
                cleanIndexes[index.row()] = index

        for cleanIndex in list(cleanIndexes.keys()):  # for python3 support
            datas.pop(cleanIndex)

        self.model.beginResetModel()
        self.model.endResetModel()
        self.setData(signal=True)

    def getHelpAdapters(self):
        """
        Return the help of all adapters according to the current
        version of the test
        """
        testDescrs = self.testDescrs.table().model.getData()
        currentAdpVersion = None
        for descr in testDescrs:
            if descr['key'] == 'adapters':
                currentAdpVersion = descr['value']
                break
        return Helper.instance().helpAdapters(name=currentAdpVersion)

    def onPopupMenu(self, pos):
        """
        Display menu on right click

        @param pos: 
        @type pos:
        """
        self.menu = QMenu(self)
        index = self.currentIndex()
        indexes = self.selectedIndexes()

        adapters = self.getHelpAdapters()

        # adapters
        adpsMenu = QMenu("Add", self)
        if adapters is not None:
            for adp in adapters:

                adpMenu = QMenu(adp['name'], self)
                adpsMenu.addMenu(adpMenu)

                for cls in adp['classes']:

                    # extract __init__ function only
                    fct = None
                    for fct in cls['functions']:
                        if fct['name'] == '__init__':
                            break

                    if fct is not None:
                        argsFct = self.parseDocString(docstring=fct['desc'])
                        argsFct['function'] = "%s::%s" % (adp['name'],
                                                          cls['name'])
                        argsFct['main-name'] = "%s" % adp['name']
                        argsFct['sub-name'] = "%s" % cls['name']
                        if 'default-args' in fct:
                            self.addDefaultValues(
                                defaultValues=fct['default-args'],
                                currentFunction=argsFct)

                        adpMenu.addAction(
                            QtHelper.createAction(self,
                                                  cls['name'],
                                                  self.addAdapter,
                                                  cb_arg=argsFct))

        if not indexes:
            self.delAction.setEnabled(False)

            self.menu.addAction(self.delAction)
            self.menu.addSeparator()
            self.menu.addMenu(adpsMenu)
            self.menu.addSeparator()

        else:
            self.delAction.setEnabled(True)

            self.menu.addAction(self.delAction)
            self.menu.addSeparator()
            self.menu.addMenu(adpsMenu)
            self.menu.addSeparator()

        self.menu.popup(self.mapToGlobal(pos))

    def addDefaultValues(self, defaultValues, currentFunction):
        """
        Add default values
        """
        for curArg in currentFunction['obj']:
            for k, v in defaultValues:
                if k == curArg['name']:
                    curArg['advanced'] = "True"
                    if curArg['type'] in ['strconstant', 'intconstant']:
                        curArg['default-value'] = self.parseConstant(
                            descr=curArg['descr'])
                    else:
                        curArg['default-value'] = unicode(v)

    def parseDocString(self, docstring):
        """
        Parse doc string
        """
        val = {}

        desc = docstring.strip()
        desc_splitted = desc.splitlines()

        val['return-value'] = "False"

        params = []
        param = {}
        for line in desc_splitted:
            line = line.strip()
            if line.startswith('@param '):
                paramName = line.split(':', 1)[0].split('@param ')[1].strip()
                paramDescr = line.split(':', 1)[1].strip()
                param['name'] = paramName
                param['value'] = ''
                param['descr'] = paramDescr
                param['selected-type'] = ''
                param['advanced'] = "False"
            elif line.startswith('@type '):
                paramType = line.split(':', 1)[1].strip()
                param['type'] = paramType
                params.append(param)
                param = {}
            elif line.startswith('@return'):
                val['return-value'] = "True"
                val['return-descr'] = line.split(':', 1)[1].strip()
            else:
                pass

        val['obj'] = params
        return val

    def parseConstant(self, descr):
        """
        Parse constant
        """
        tmpvals = descr.split("|")
        nameConstant = ''
        for zz in xrange(len(tmpvals)):
            if '(default)' in tmpvals[zz]:
                nameConstant = tmpvals[zz].split('(default)')[0].strip()
        return nameConstant

    def addAdapter(self, fctParams):
        """
        Add testcase function
        """
        actionId = self.getActionId()
        tpl = {'action': ACTION_ADAPTER, 'data': fctParams}
        self.insertItem(actionParams=tpl)

    def getActionId(self):
        """
        Return action Id
        """
        data = self.model.getData()
        actionId = len(data) + 1
        return actionId

    def insertItem(self, actionParams):
        """
        Insert item
        """
        indexes = self.selectedIndexes()
        if not len(indexes):
            row = self.model.rowCount()
        else:
            index = self.currentIndex()
            row = index.row()
        data = self.model.getData()

        # add data to model
        data.insert(row + 1, actionParams)
        # self.model.reset()
        self.model.beginResetModel()
        self.model.endResetModel()

        # open properties on adding, workaround to fix an error (bad agent type)
        actionDialog = GenericConfigDialog.ActionDialog(
            self,
            self.helper,
            actionParams,
            owner=self,
            variables=[],
            adapterMode=True,
            testParams=self.testParams,
            noCancel=True)
        actionDialog.exec_()
        newActionParams = actionDialog.getValues()
        data[row]['data']['obj'] = newActionParams

        self.delAllAction.setEnabled(True)

        self.setData()

    def setAdapters(self, adapters):
        """
        Set adapters
        """
        self.model.setDataModel(adapters)
        self.setData(signal=False)

    def clearItems(self):
        """
        Clear all items
        """
        reply = QMessageBox.question(self, self.tr("Clear all adapters"),
                                     self.tr("Are you sure ?"),
                                     QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            data = self.model.getData()
            try:
                for i in xrange(len(data)):
                    data.pop()
            except Exception as e:
                pass
            # self.model.reset()
            self.model.beginResetModel()
            self.model.endResetModel()
            self.setData()

            self.delAllAction.setEnabled(False)
            self.delAction.setEnabled(False)

    def clear(self):
        """
        clear contents
        """
        self.model.setDataModel([])

    def setData(self, signal=True):
        """
        Set table data

        @param signal: 
        @type signal: boolean
        """
        if signal: self.DataChanged.emit()
class Repository(QWidget, Logger.ClassLogger):
    """
    Repository widget
    """
    OpenFile = pyqtSignal(str, str, str, bool, object, int)

    def __init__(self, parent=None, withFile=True):
        """
        Repository widget

        @param parent: 
        @type parent:

        @param withFile: 
        @type withFile:
        """
        QWidget.__init__(self, parent)
        self.parent = parent
        self.withFile = withFile
        self.itemCurrent = None

        self.wrepository = None

        style = self.parent.style()
        self.folderIcon = QIcon()
        self.rootIcon = QIcon()
        self.folderIcon.addPixmap(
            style.standardPixmap(QStyle.SP_DirClosedIcon), QIcon.Normal,
            QIcon.Off)
        self.folderIcon.addPixmap(style.standardPixmap(QStyle.SP_DirOpenIcon),
                                  QIcon.Normal, QIcon.On)
        self.rootIcon.addPixmap(style.standardPixmap(QStyle.SP_DriveHDIcon))
        self.testSuiteIcon = QIcon(":/%s.png" % EXTENSION_TSX)
        self.testPlanIcon = QIcon(":/%s.png" % EXTENSION_TPX)
        self.testGlobalIcon = QIcon(":/%s.png" % EXTENSION_TGX)
        self.testConfigIcon = QIcon(":/%s.png" % EXTENSION_TCX)
        self.testDataIcon = QIcon(":/%s.png" % EXTENSION_TDX)
        self.testUnitIcon = QIcon(":/%s.png" % EXTENSION_TUX)
        self.testAbstractIcon = QIcon(":/%s.png" % EXTENSION_TAX)
        self.pngIcon = QIcon(":/%s.png" % EXTENSION_PNG)

        self.createWidgets()
        self.createConnections()
        self.createActions()
        self.createToolbarLocal()

        self.itemEdited = None

    def initRepo(self):
        """
        Initialize the repository
        """
        if RCI.instance().isAuthenticated():
            testcasesRoot = Item(
                repo=self,
                parent=self.wrepository,
                txt="%s" %
                Settings.instance().readValue(key='Repositories/local-repo'),
                type=QTreeWidgetItem.UserType + 10,
                isRoot=True,
                itemTxt="Root")
            testcasesRoot.setSelected(True)
            self.createRepository(
                "%s" %
                Settings.instance().readValue(key='Repositories/local-repo'),
                parent=testcasesRoot)

    def active(self):
        """
        Active the repository
        """
        self.wrepository.clear()
        self.wrepository.setEnabled(True)
        self.initRepo()

    def deactive(self):
        """
        Disable the repository
        """
        self.wrepository.setEnabled(False)
        self.wrepository.clear()

    def keyPressEvent(self, event):
        """
        Called on key press
        Reimplement from widget
        """
        if event.key() == Qt.Key_Delete:
            self.deleteItem()
        return QWidget.keyPressEvent(self, event)

    def createActions(self):
        """
        Create qt actions
        """
        self.refreshAction = QtHelper.createAction(
            self,
            "&Refresh",
            self.refreshAll,
            icon=QIcon(":/refresh.png"),
            tip='Refresh local repository content')
        self.addDirAction = QtHelper.createAction(
            self,
            "&Add",
            self.createItem,
            icon=QIcon(":/folder_add.png"),
            tip='Create new folder')
        self.delFileAction = QtHelper.createAction(
            self,
            "&Delete File",
            self.deleteItem,
            icon=QIcon(":/delete_file.png"),
            shortcut=QKeySequence.Delete,
            tip='Delete file')
        self.delDirAction = QtHelper.createAction(
            self,
            "&Delete Folder",
            self.deleteItem,
            icon=QIcon(":/folder_delete.png"),
            shortcut=QKeySequence.Delete,
            tip='Delete folder')
        self.renameAction = QtHelper.createAction(self,
                                                  "&Rename",
                                                  self.renameItem,
                                                  icon=QIcon(":/rename.png"),
                                                  tip='Rename')

        self.expandSubtreeAction = QtHelper.createAction(self,
                                                         "&Expand folder...",
                                                         self.expandSubFolder,
                                                         icon=None,
                                                         tip='Expand folder')
        self.expandAllAction = QtHelper.createAction(self,
                                                     "&Expand All",
                                                     self.expandAllFolders,
                                                     icon=None,
                                                     tip='Expand all folders')
        self.collapseAllAction = QtHelper.createAction(
            self,
            "&Collapse All",
            self.collapseAllFolders,
            icon=None,
            tip='Collapse all folder')

        self.defaultActions()

    def expandAllFolders(self):
        """
        Expand all folders
        """
        self.wrepository.expandAll()

    def collapseAllFolders(self):
        """
        Collapse all folders
        """
        self.wrepository.collapseAll()

    def expandSubFolder(self):
        """
        Expand the sub folder
        """
        currentItem = self.wrepository.currentItem()
        if currentItem is not None:
            self.expandItem(itm=currentItem)

    def expandItem(self, itm):
        """
        Expand item
        """
        itm.setExpanded(True)
        if itm.childCount() > 0:
            for i in xrange(itm.childCount()):
                itm.child(i).setExpanded(True)
                if itm.child(i).childCount() > 0:
                    self.expandItem(itm=itm.child(i))

    def defaultActions(self):
        """
        Set the default actions values
        """
        self.refreshAction.setEnabled(False)
        self.addDirAction.setEnabled(False)
        self.delFileAction.setEnabled(False)
        self.delDirAction.setEnabled(False)
        self.renameAction.setEnabled(False)
        self.expandSubtreeAction.setEnabled(False)
        self.expandAllAction.setEnabled(False)
        self.collapseAllAction.setEnabled(False)

    def onPopupMenu(self, pos):
        """
        Called on popup right menu

        @param pos: 
        @type pos:
        """
        item = self.wrepository.itemAt(pos)
        self.menu = QMenu()
        if item:
            self.itemCurrent = item
            self.wrepository.itemCurrent = item
            if item.type() == QTreeWidgetItem.UserType + 0:  # file
                self.menu.addAction(self.delFileAction)
                self.menu.addSeparator()
                self.menu.addAction(self.renameAction)
            elif item.type() == QTreeWidgetItem.UserType + 1:  # dir
                self.menu.addAction(self.expandSubtreeAction)
                self.menu.addSeparator()
                self.menu.addAction(self.addDirAction)
                self.menu.addSeparator()
                self.menu.addAction(self.delDirAction)
                self.menu.addSeparator()
                self.menu.addAction(self.renameAction)
            if item.type() == QTreeWidgetItem.UserType + 10:
                self.menu.addAction(self.refreshAction)
                self.menu.addSeparator()
                self.menu.addAction(self.expandAllAction)
                self.menu.addAction(self.collapseAllAction)
                self.menu.addSeparator()
                self.menu.addAction(self.addDirAction)
            self.menu.popup(self.mapToGlobal(pos))

    def createConnections(self):
        """
        Create qc connections
        """
        self.wrepository.itemDoubleClicked.connect(self.openFile)
        self.wrepository.itemChanged.connect(self.onItemChanged)
        self.wrepository.currentItemChanged.connect(self.onCurrentItemChanged)
        self.wrepository.customContextMenuRequested.connect(self.onPopupMenu)

    def createWidgets(self):
        """
        Create qt widgets
        """
        self.dockToolbarLocal = QToolBar(self)
        self.dockToolbarLocal.setStyleSheet(
            "QToolBar { border: 0px; }")  # remove 3D border

        self.wrepository = TreeWidgetRepository(parent=self)
        self.wrepository.setFrameShape(QFrame.NoFrame)
        if USE_PYQT5:
            self.wrepository.header().setSectionResizeMode(QHeaderView.Stretch)
        else:
            self.wrepository.header().setResizeMode(QHeaderView.Stretch)
        self.wrepository.setHeaderHidden(True)
        self.wrepository.setContextMenuPolicy(Qt.CustomContextMenu)
        self.wrepository.setIndentation(10)

        layout = QVBoxLayout()
        layout.addWidget(self.wrepository)
        layout.addWidget(self.dockToolbarLocal)

        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

    def createToolbarLocal(self):
        """
        Toolbar creation
            
        ||--|||
        ||  |||
        ||--|||
        """
        self.dockToolbarLocal.setObjectName("Local Repository toolbar")
        self.dockToolbarLocal.addAction(self.refreshAction)
        self.dockToolbarLocal.addSeparator()
        self.dockToolbarLocal.addAction(self.addDirAction)
        self.dockToolbarLocal.addAction(self.delDirAction)
        self.dockToolbarLocal.addAction(self.delFileAction)
        self.dockToolbarLocal.addSeparator()
        self.dockToolbarLocal.addAction(self.renameAction)
        self.dockToolbarLocal.setIconSize(QSize(16, 16))

    def createRepository(self, path, parent):
        """
        Create repository

        @param path: 
        @type path:

        @param parent: 
        @type parent:
        """
        self.refreshAction.setEnabled(True)
        try:
            for d in os.listdir(path):
                if not os.path.isfile(path + '/' + d):
                    # is directory
                    item = Item(repo=self, parent=parent, txt=d)
                    self.createRepository(path + '/' + d, item)
                else:
                    if self.withFile:
                        if d.lower().endswith(tuple(SUPPORTED_EXTENSIONS)):
                            # is file
                            item = Item(repo=self,
                                        parent=parent,
                                        txt=d,
                                        type=QTreeWidgetItem.UserType + 0)
        except Exception as e:
            self.error(e)

    def openFile(self, witem, col):
        """
        Open file

        @param witem: 
        @type witem:

        @param col: 
        @type col:
        """
        if witem.type() == QTreeWidgetItem.UserType + 0:
            path = witem.getPath(withFileName=False)
            self.OpenFile.emit(path, witem.fileName, witem.fileExtension,
                               False, None, UCI.REPO_TESTS_LOCAL)

    def deleteItem(self):
        """
        Delete item
        """
        if self.itemCurrent.type() == QTreeWidgetItem.UserType + 0:
            self.itemCurrent.rmFile()
        elif self.itemCurrent.type() == QTreeWidgetItem.UserType + 1:
            self.itemCurrent.rmDir()
        else:
            self.error("should not be happened")

    def createItem(self):
        """
        Create item
        """
        if self.itemCurrent is not None:
            txt, ok = QInputDialog.getText(self, "Create", "Enter name:",
                                           QLineEdit.Normal)
            if ok and txt:
                self.itemCurrent.createSubDirectory(folderName=txt)
                self.itemCurrent.setSelected(False)

    def refreshAll(self):
        """
        Refresh all
        """
        self.wrepository.clear()
        testcasesRoot = Item(
            repo=self,
            parent=self.wrepository,
            txt="%s" %
            Settings.instance().readValue(key='Repositories/local-repo'),
            type=QTreeWidgetItem.UserType + 10,
            isRoot=True,
            itemTxt="Root")
        testcasesRoot.setSelected(True)
        if "%s" % Settings.instance().readValue(
                key='Repositories/local-repo') == 'Undefined':
            self.wrepository.setEnabled(False)
            self.refreshAction.setEnabled(False)
        else:
            self.createRepository(
                "%s" %
                Settings.instance().readValue(key='Repositories/local-repo'),
                parent=testcasesRoot)
        self.defaultActions()
        self.refreshAction.setEnabled(True)

    def renameItem(self):
        """
        Rename item
        """
        self.itemCurrent.setFlags(Qt.ItemIsEditable | Qt.ItemIsEnabled)
        self.wrepository.editItem(self.itemCurrent, 0)
        self.itemEdited = (self.itemCurrent, self.itemCurrent.text(0))
        self.itemCurrent.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)

    def onCurrentItemChanged(self, witem1, witem2):
        """
        Called when the current item changed

        @param witem1: 
        @type witem1:

        @param witem2: 
        @type witem2:
        """
        self.itemEdited = None
        self.itemCurrent = witem1
        self.wrepository.itemCurrent = witem1
        if self.itemCurrent is not None:
            if self.itemCurrent.type() == QTreeWidgetItem.UserType + 0:  # file
                self.addDirAction.setEnabled(False)
                self.delFileAction.setEnabled(True)
                self.delDirAction.setEnabled(False)
                self.renameAction.setEnabled(True)
                self.expandSubtreeAction.setEnabled(False)
                self.expandAllAction.setEnabled(False)
                self.collapseAllAction.setEnabled(False)
            elif self.itemCurrent.type(
            ) == QTreeWidgetItem.UserType + 1:  # dir
                self.addDirAction.setEnabled(True)
                self.delFileAction.setEnabled(False)
                self.delDirAction.setEnabled(True)
                self.renameAction.setEnabled(True)
                self.expandSubtreeAction.setEnabled(True)
                self.expandAllAction.setEnabled(False)
                self.collapseAllAction.setEnabled(False)
            elif self.itemCurrent.type(
            ) == QTreeWidgetItem.UserType + 10:  #root
                self.addDirAction.setEnabled(True)
                self.delFileAction.setEnabled(False)
                self.delDirAction.setEnabled(False)
                self.renameAction.setEnabled(False)
                self.expandSubtreeAction.setEnabled(False)
                self.expandAllAction.setEnabled(True)
                self.collapseAllAction.setEnabled(True)
            else:
                pass

    def onItemChanged(self, witem, col):
        """
        Called when item changed

        @param witem: 
        @type witem:

        @param col: 
        @type col:
        """
        if self.itemEdited != None:
            if witem.text(0) != self.itemEdited[1]:
                if self.itemCurrent.type() == QTreeWidgetItem.UserType + 0:
                    witem.renameFile(oldName=self.itemEdited[1],
                                     newName=witem.text(0))
                elif self.itemCurrent.type() == QTreeWidgetItem.UserType + 1:
                    witem.renameDir(oldName=self.itemEdited[1],
                                    newName=witem.text(0))
                else:
                    self.error("should not be happened")
                self.itemEdited = None