class ShortcutSection(QWidget): def __init__(self): super(ShortcutSection, self).__init__() container = QVBoxLayout(self) self.tree = QTreeWidget() self.tree.setHeaderLabels([self.tr("Keys"), self.tr("Description")]) self.tree.header().setStretchLastSection(True) self.tree.setColumnWidth(0, 200) container.addWidget(self.tree) self.items = { "new": "Create a new editor to work in a file", "new-project": "Create a new project", "open": "Open one or more files", "open-project": "Opens an existing project Edis", "reload": "Reload file", "save": "Save file" } for i, e in list(self.items.items()): item = QTreeWidgetItem(self.tree, [keymap.get_keymap(i).toString(), e]) item.setFlags(Qt.ItemIsEditable | Qt.ItemIsEnabled) self.tree.itemDoubleClicked.connect(self._change_shortcut) # Install EnvironmentConfiguration.install_widget(self.tr("Shortcuts"), self) def _change_shortcut(self, item, column): pass def save(self): print("save")
def __addGenericTable( self, table ): " Adds a generic table to the report " theTable = QTreeWidget( self.bodyWidget ) theTable.setAlternatingRowColors( True ) theTable.setRootIsDecorated( False ) theTable.setItemsExpandable( False ) theTable.setSortingEnabled( False ) theTable.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) theTable.setUniformRowHeights( True ) headerLabels = [] for index in range( 0, len( table.header ) ): headerLabels.append( table.header[ index ] ) theTable.setHeaderLabels( headerLabels ) for item in table.body: row = [] for index in range( 0, len( table.header ) ): row.append( item[ index ] ) theTable.addTopLevelItem( QTreeWidgetItem( row ) ) theTable.setFocusPolicy( Qt.NoFocus ) # Resizing theTable.header().resizeSections( QHeaderView.ResizeToContents ) theTable.header().setStretchLastSection( True ) # Height self.__setTableHeight( theTable ) self.__vLayout.addWidget( theTable ) self.__widgets.append( theTable ) return
def __addGenericTable(self, table): " Adds a generic table to the report " theTable = QTreeWidget(self.bodyWidget) theTable.setAlternatingRowColors(True) theTable.setRootIsDecorated(False) theTable.setItemsExpandable(False) theTable.setSortingEnabled(False) theTable.setItemDelegate(NoOutlineHeightDelegate(4)) theTable.setUniformRowHeights(True) headerLabels = [] for index in range(0, len(table.header)): headerLabels.append(table.header[index]) theTable.setHeaderLabels(headerLabels) for item in table.body: row = [] for index in range(0, len(table.header)): row.append(item[index]) theTable.addTopLevelItem(QTreeWidgetItem(row)) theTable.setFocusPolicy(Qt.NoFocus) # Resizing theTable.header().resizeSections(QHeaderView.ResizeToContents) theTable.header().setStretchLastSection(True) # Height self.__setTableHeight(theTable) self.__vLayout.addWidget(theTable) self.__widgets.append(theTable) return
def initUI(self): layout = QVBoxLayout(self) #Input part input_label = QLabel(inputlabeltext, self) input_label.setWordWrap(True) input_field = QLineEdit("MOM: Oh, good!", self) input_search = QPushButton("Search!", self) splitview = QSplitter(self) splitview.setOrientation(Qt.Vertical) splitview.setChildrenCollapsible(False) #Results list results_label = QLabel(resultslabeltext, self) results_label.setWordWrap(True) results_list = QTreeWidget() results_list.setColumnCount(3) #pointer, refs to pointer, text results_list.header().resizeSection(0, 100) results_list.header().resizeSection(1, 40) results_list.setFocusPolicy(Qt.NoFocus) #results_list.setMaximumSize(QSize(16777215, 100)) stringeditor = self.scripteditcontroller.getview() #Pack all into the layout layout.addWidget(input_label) layout.addWidget(input_field) layout.addWidget(input_search) layout.addWidget(results_label) #layout.addWidget(results_list) #layout.addWidget(stringeditor) splitview.addWidget(results_list) splitview.addWidget(stringeditor) splitview.setSizes([100, 500]) layout.addWidget(splitview) #Connect to actions input_search.clicked.connect(self.searchClick) results_list.itemSelectionChanged.connect(self.resultSelected) #Keeps some elements for later use self.input_field = input_field self.results_list = results_list self.stringeditor = stringeditor #Show the widget self.move(300, 150) self.setWindowTitle('Pokemon GBA String Editor') self.show()
class Results(QWidget): def __init__(self, parent): QWidget.__init__(self, parent) self._parent = parent vbox = QVBoxLayout(self) self._tree = QTreeWidget() self._tree.setHeaderLabels((self.tr("Content"), self.tr("File"), self.tr("Line"))) self._tree.header().setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self._tree.header().setResizeMode(0, QHeaderView.ResizeToContents) self._tree.header().setResizeMode(1, QHeaderView.ResizeToContents) self._tree.header().setResizeMode(2, QHeaderView.ResizeToContents) self._tree.header().setStretchLastSection(True) self._tree.sortByColumn(1, Qt.AscendingOrder) vbox.addWidget(self._tree) # Signals self.connect(self._tree, SIGNAL("itemClicked(QTreeWidgetItem*, int)"), self._open_result) def _open_result(self, item, col): filename = unicode(item.toolTip(1)) line = int(item.text(2)) - 1 main_container.MainContainer().open_file(fileName=filename, cursorPosition=line, positionIsLineNumber=True) self._parent.hide() def update_result(self, items): self._tree.clear() for i in items: item = QTreeWidgetItem(self._tree, (i[3], i[0], QString.number(i[2] + 1))) item.setToolTip(1, i[1])
class Results(QWidget): """Show results of occurrences in files inside the tools dock.""" def __init__(self, parent): super(Results, self).__init__(parent) self._parent = parent vbox = QVBoxLayout(self) self._tree = QTreeWidget() self._tree.setHeaderLabels((self.tr("Content"), self.tr('File'), self.tr('Line'))) self._tree.header().setHorizontalScrollMode( QAbstractItemView.ScrollPerPixel) self._tree.header().setResizeMode(0, QHeaderView.ResizeToContents) self._tree.header().setResizeMode(1, QHeaderView.ResizeToContents) self._tree.header().setResizeMode(2, QHeaderView.ResizeToContents) self._tree.header().setStretchLastSection(True) self._tree.sortByColumn(1, Qt.AscendingOrder) vbox.addWidget(self._tree) #Signals self.connect(self._tree, SIGNAL("itemActivated(QTreeWidgetItem*, int)"), self._open_result) self.connect(self._tree, SIGNAL("itemClicked(QTreeWidgetItem*, int)"), self._open_result) def _open_result(self, item, col): """Get the data of the selected item and open the file.""" filename = item.toolTip(1) line = int(item.text(2)) - 1 main_container = IDE.get_service('main_container') if main_container: main_container.open_file( filename=filename, cursorPosition=line, positionIsLineNumber=True) self._parent.hide() def update_result(self, items): """Update the result tree with the new items.""" self._tree.clear() for i in items: item = QTreeWidgetItem(self._tree, (i[3], i[0], str(i[2] + 1))) item.setToolTip(1, i[1])
class Results(QWidget): """Show results of occurrences in files inside the tools dock.""" def __init__(self, parent): super(Results, self).__init__(parent) self._parent = parent vbox = QVBoxLayout(self) self._tree = QTreeWidget() self._tree.setHeaderLabels( (translations.TR_CONTENT, translations.TR_FILE, translations.TR_LINE)) self._tree.header().setHorizontalScrollMode( QAbstractItemView.ScrollPerPixel) self._tree.header().setResizeMode(0, QHeaderView.ResizeToContents) self._tree.header().setResizeMode(1, QHeaderView.ResizeToContents) self._tree.header().setResizeMode(2, QHeaderView.ResizeToContents) self._tree.header().setStretchLastSection(True) self._tree.sortByColumn(1, Qt.AscendingOrder) vbox.addWidget(self._tree) #Signals self.connect(self._tree, SIGNAL("itemActivated(QTreeWidgetItem*, int)"), self._open_result) self.connect(self._tree, SIGNAL("itemClicked(QTreeWidgetItem*, int)"), self._open_result) def _open_result(self, item, col): """Get the data of the selected item and open the file.""" filename = item.toolTip(1) line = int(item.text(2)) - 1 main_container = IDE.get_service('main_container') if main_container: main_container.open_file(filename=filename, cursorPosition=line, positionIsLineNumber=True) self._parent.hide() def update_result(self, items): """Update the result tree with the new items.""" self._tree.clear() for i in items: item = QTreeWidgetItem(self._tree, (i[3], i[0], str(i[2] + 1))) item.setToolTip(1, i[1])
def __addErrorsTable(self, messages, showFileName): " Creates the messages table " errTable = QTreeWidget(self.bodyWidget) errTable.setAlternatingRowColors(True) errTable.setRootIsDecorated(False) errTable.setItemsExpandable(False) errTable.setSortingEnabled(True) errTable.setItemDelegate(NoOutlineHeightDelegate(4)) errTable.setUniformRowHeights(True) errTable.itemActivated.connect(self.__errorActivated) headerLabels = ["File name", "Line", "Message ID", "Object", "Message"] errTable.setHeaderLabels(headerLabels) for item in messages: if item.position is None: lineNumber = str(item.lineNumber) else: lineNumber = str(item.lineNumber) + ":" + str(item.position) values = [ item.fileName, lineNumber, item.messageID, item.objectName, item.message ] errTable.addTopLevelItem(ErrorTableItem(values, 1)) # Hide the file name column if required if not showFileName: errTable.setColumnHidden(0, True) # Resizing errTable.header().resizeSections(QHeaderView.ResizeToContents) errTable.header().setStretchLastSection(True) # Sort indicator if showFileName: sortIndex = 0 # By file names else: sortIndex = 1 # By line number because this is from the same file errTable.header().setSortIndicator(sortIndex, Qt.AscendingOrder) errTable.sortItems(sortIndex, errTable.header().sortIndicatorOrder()) # Height self.__setTableHeight(errTable) self.__vLayout.addWidget(errTable) self.__widgets.append(errTable) return
def __addErrorsTable( self, messages, showFileName ): " Creates the messages table " errTable = QTreeWidget( self.bodyWidget ) errTable.setAlternatingRowColors( True ) errTable.setRootIsDecorated( False ) errTable.setItemsExpandable( False ) errTable.setSortingEnabled( True ) errTable.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) errTable.setUniformRowHeights( True ) errTable.itemActivated.connect( self.__errorActivated ) headerLabels = [ "File name", "Line", "Message ID", "Object", "Message" ] errTable.setHeaderLabels( headerLabels ) for item in messages: if item.position is None: lineNumber = str( item.lineNumber ) else: lineNumber = str( item.lineNumber ) + ":" + str( item.position ) values = [ item.fileName, lineNumber, item.messageID, item.objectName, item.message ] errTable.addTopLevelItem( ErrorTableItem( values, 1 ) ) # Hide the file name column if required if not showFileName: errTable.setColumnHidden( 0, True ) # Resizing errTable.header().resizeSections( QHeaderView.ResizeToContents ) errTable.header().setStretchLastSection( True ) # Sort indicator if showFileName: sortIndex = 0 # By file names else: sortIndex = 1 # By line number because this is from the same file errTable.header().setSortIndicator( sortIndex, Qt.AscendingOrder ) errTable.sortItems( sortIndex, errTable.header().sortIndicatorOrder() ) # Height self.__setTableHeight( errTable ) self.__vLayout.addWidget( errTable ) self.__widgets.append( errTable ) return
class Results(QWidget): def __init__(self, parent): QWidget.__init__(self, parent) self._parent = parent vbox = QVBoxLayout(self) self._tree = QTreeWidget() self._tree.setHeaderLabels( (self.tr("Content"), self.tr('File'), self.tr('Line'))) self._tree.header().setHorizontalScrollMode( QAbstractItemView.ScrollPerPixel) self._tree.header().setResizeMode(0, QHeaderView.ResizeToContents) self._tree.header().setResizeMode(1, QHeaderView.ResizeToContents) self._tree.header().setResizeMode(2, QHeaderView.ResizeToContents) self._tree.header().setStretchLastSection(True) self._tree.sortByColumn(1, Qt.AscendingOrder) vbox.addWidget(self._tree) #Signals self.connect(self._tree, SIGNAL("itemActivated(QTreeWidgetItem*, int)"), self._open_result) self.connect(self._tree, SIGNAL("itemClicked(QTreeWidgetItem*, int)"), self._open_result) def _open_result(self, item, col): filename = unicode(item.toolTip(1)) line = int(item.text(2)) - 1 main_container.MainContainer().open_file(filename=filename, cursorPosition=line, positionIsLineNumber=True) self._parent.hide() def update_result(self, items): self._tree.clear() for i in items: item = QTreeWidgetItem(self._tree, (i[3], i[0], QString.number(i[2] + 1))) item.setToolTip(1, i[1])
class SVNPluginAddDialog(QDialog): " SVN Plugin add dialog " def __init__(self, pathsToAdd, parent=None): QDialog.__init__(self, parent) self.addPaths = [] self.__createLayout(pathsToAdd) self.setWindowTitle("SVN add") # Fill the lists for item in pathsToAdd: newItem = QTreeWidgetItem(["", item]) newItem.setCheckState(CHECK_COL, Qt.Checked) newItem.setToolTip(PATH_COL, item[0]) self.__pathToAddView.addTopLevelItem(newItem) self.__resizeAddPaths() self.__sortAddPaths() self.__updateOKStatus() return def __resizeAddPaths(self): " Resizes the add table " self.__pathToAddView.header().setStretchLastSection(True) self.__pathToAddView.header().resizeSections( QHeaderView.ResizeToContents) self.__pathToAddView.header().resizeSection(CHECK_COL, 28) self.__pathToAddView.header().setResizeMode(CHECK_COL, QHeaderView.Fixed) return def __sortAddPaths(self): " Sorts the commit paths table " self.__pathToAddView.sortItems( self.__pathToAddView.sortColumn(), self.__pathToAddView.header().sortIndicatorOrder()) return @staticmethod def __configTable(table): " Sets common properties for a table " table.setAlternatingRowColors(True) table.setRootIsDecorated(False) table.setItemsExpandable(False) table.setSortingEnabled(True) table.setItemDelegate(NoOutlineHeightDelegate(4)) table.setUniformRowHeights(True) return def __createLayout(self, pathsToAdd): " Creates the dialog layout " self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) # Paths to add part vboxLayout.addWidget( QLabel("Paths to add (total: " + str(len(pathsToAdd)) + ")")) self.__pathToAddView = QTreeWidget() self.__configTable(self.__pathToAddView) self.__pathToAddHeader = QTreeWidgetItem(["", "Path"]) self.__pathToAddView.setHeaderItem(self.__pathToAddHeader) self.__pathToAddView.header().setSortIndicator(PATH_COL, Qt.AscendingOrder) self.__pathToAddView.itemChanged.connect(self.__onAddPathChanged) vboxLayout.addWidget(self.__pathToAddView) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.__OKButton = buttonBox.button(QDialogButtonBox.Ok) self.__OKButton.setText("Add") buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) buttonBox.accepted.connect(self.userAccept) buttonBox.rejected.connect(self.close) vboxLayout.addWidget(buttonBox) return def userAccept(self): " Triggered when the user clicks OK " # Collect the list of checked paths self.addPaths = [] index = 0 while index < self.__pathToAddView.topLevelItemCount(): item = self.__pathToAddView.topLevelItem(index) if item.checkState(CHECK_COL) == Qt.Checked: path = str(item.text(1)) if os.path.isdir( path ) and not os.path.islink( path ) and \ not path.endswith( os.path.sep ): path += os.path.sep self.addPaths.append(path) index += 1 self.accept() return def __getCheckedCount(self): " Provides the number of selected items in the add paths section " index = 0 checkedCount = 0 while index < self.__pathToAddView.topLevelItemCount(): item = self.__pathToAddView.topLevelItem(index) if item.checkState(0) == Qt.Checked: checkedCount += 1 index += 1 return checkedCount def __updateOKStatus(self): " Updates the OK button status " self.__OKButton.setEnabled(self.__getCheckedCount() > 0) return def __onAddPathChanged(self, item, column): " Triggered when an item is changed " self.__updateOKStatus() return
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( getIcon('openitem.png'), 'Open', self.__openFile) self.__copyPathFileMenuItem = self.__fileMenu.addAction( getIcon('copytoclipboard.png'), 'Copy path to clipboard', self.__filePathToClipboard) self.__fileMenu.addSeparator() self.__delFileMenuItem = self.__fileMenu.addAction( 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( getIcon('load.png'), 'Load', self.__loadProject) self.__projectMenu.addSeparator() self.__propsMenuItem = self.__projectMenu.addAction( getIcon('smalli.png'), 'Properties', self.__viewProperties) self.__prjCopyPathMenuItem = self.__projectMenu.addAction( getIcon('copytoclipboard.png'), 'Copy path to clipboard', self.__prjPathToClipboard) self.__projectMenu.addSeparator() self.__delPrjMenuItem = self.__projectMenu.addAction( getIcon('trash.png'), 'Delete from recent', self.__deleteProject) self.projectsView.setContextMenuPolicy(Qt.CustomContextMenu) self.connect(self.projectsView, SIGNAL("customContextMenuRequested(const QPoint &)"), self.__handleShowPrjContextMenu) Settings().recentListChanged.connect(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(getIcon('openitem.png'), 'Open the highlighted file', self) self.connect(self.openFileButton, SIGNAL("triggered()"), self.__openFile) self.copyFilePathButton = QAction(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(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(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(getIcon('load.png'), 'Load the highlighted project', self) self.connect(self.loadButton, SIGNAL("triggered()"), self.__loadProject) self.propertiesButton = QAction( getIcon('smalli.png'), 'Show the highlighted project ' 'properties', self) self.connect(self.propertiesButton, SIGNAL("triggered()"), self.__viewProperties) self.copyPrjPathButton = QAction(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(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, self) 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, self) 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(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(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
class UploadEditorDialog(QDialog): def __init__(self, tracks, parent=None): super(UploadEditorDialog, self).__init__(parent) self.setWindowTitle('Upload to Strava') self.setFixedSize(300,200) self.tracks = tracks self._list_widget = QTreeWidget(self) self._list_widget.setColumnCount(2) self._list_widget.setRootIsDecorated(False) self._list_widget.setSortingEnabled(False) self._list_widget.setUniformRowHeights(True) self._list_widget.setSelectionMode(QTreeWidget.NoSelection) self._list_widget.setAlternatingRowColors(True) self._list_widget.header().resizeSection(0, 150) self._list_widget.header().hide() self._fillTable() self._buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self._buttons.accepted.connect(self.accept) self._buttons.rejected.connect(self.reject) self._createLayout() def getValues(self): for t, w in zip(self.tracks, self._widgets): yield t, str(w.currentText()) def eventFilter(self, o, e): if e.type() == QEvent.Wheel and isinstance(o, QComboBox): e.ignore() return True return super(UploadEditorDialog, self).eventFilter(o, e) def _fillTable(self): self._widgets = [] for track in self.tracks: item = QTreeWidgetItem([track['name'], 'ride']) self._list_widget.addTopLevelItem(item) cb = QComboBox() cb.addItems(['ride', 'run']) cb.setFocusPolicy(Qt.ClickFocus) cb.installEventFilter(self) self._list_widget.setItemWidget(item, 1, cb) self._widgets.append(cb) def _createLayout(self): l = QVBoxLayout() l.addWidget(self._list_widget) l.addWidget(self._buttons) self.setLayout(l)
class SVNPluginCommitDialog(QDialog): " SVN Plugin commit dialog " NODIFF = '<html><body bgcolor="#ffffe6"></body></html>' def __init__(self, plugin, pathsToCommit, pathsToIgnore, parent=None): QDialog.__init__(self, parent) self.__plugin = plugin self.__createLayout(pathsToCommit, pathsToIgnore) self.setWindowTitle("SVN commit") # Fill the lists for item in pathsToCommit: newItem = QTreeWidgetItem(["", item[0], STATUS[item[1]]]) newItem.setCheckState(CHECK_COL, Qt.Checked) newItem.setToolTip(PATH_COL, item[0]) newItem.setToolTip(STATUS_COL, STATUS[item[1]]) self.__pathToCommitView.addTopLevelItem(newItem) diffButton = self.__createDiffButton() diffButton.path = item[0] diffButton.status = item[1] fileType = detectFileType(item[0]) if os.path.isdir( item[ 0 ] ) or item[ 1 ] in [ IND_REPLACED ] \ or not isFileTypeSearchable( fileType ): diffButton.setEnabled(False) diffButton.setToolTip("Diff is not available") else: diffButton.setEnabled(True) diffButton.setToolTip("Click to see diff") self.__pathToCommitView.setItemWidget(newItem, DIFF_COL, diffButton) self.__resizeCommitPaths() self.__sortCommitPaths() for item in pathsToIgnore: newItem = QTreeWidgetItem([item[0], STATUS[item[1]]]) newItem.setToolTip(0, item[0]) newItem.setToolTip(1, STATUS[item[1]]) self.__pathToIgnoreView.addTopLevelItem(newItem) self.__pathToIgnoreView.header().resizeSections( QHeaderView.ResizeToContents) self.__updateSelectAllStatus() self.__updateOKStatus() self.__message.setFocus() return def __resizeCommitPaths(self): " Resizes the plugins table " self.__pathToCommitView.header().setStretchLastSection(False) self.__pathToCommitView.header().resizeSections( QHeaderView.ResizeToContents) self.__pathToCommitView.header().resizeSection(CHECK_COL, 28) self.__pathToCommitView.header().setResizeMode(CHECK_COL, QHeaderView.Fixed) # By some reasons, to have PATH_COL visually adjustable the only STATUS_COL # must be set to be stretchable, so there is a comment below. # self.__pathToCommitView.header().setResizeMode( PATH_COL, QHeaderView.Stretch ) self.__pathToCommitView.header().setResizeMode(STATUS_COL, QHeaderView.Stretch) self.__pathToCommitView.header().resizeSection(DIFF_COL, 24) self.__pathToCommitView.header().setResizeMode(DIFF_COL, QHeaderView.Fixed) return def __sortCommitPaths(self): " Sorts the commit paths table " self.__pathToCommitView.sortItems( self.__pathToCommitView.sortColumn(), self.__pathToCommitView.header().sortIndicatorOrder()) return def __createDiffButton(self): " Creates a diff button for a path " button = DiffButton() self.connect(button, SIGNAL('CustomClick'), self.onDiff) return button @staticmethod def __setLightPalette(frame): " Creates a lighter paletter for the widget background " palette = frame.palette() background = palette.color(QPalette.Background) background.setRgb(min(background.red() + 30, 255), min(background.green() + 30, 255), min(background.blue() + 30, 255)) palette.setColor(QPalette.Background, background) frame.setPalette(palette) return @staticmethod def __configTable(table): " Sets common properties for a table " table.setAlternatingRowColors(True) table.setRootIsDecorated(False) table.setItemsExpandable(False) table.setSortingEnabled(True) table.setItemDelegate(NoOutlineHeightDelegate(4)) table.setUniformRowHeights(True) return def __createLayout(self, pathsToCommit, pathsToIgnore): " Creates the dialog layout " self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) # Paths to commit part commitHeaderFrame = QFrame() commitHeaderFrame.setFrameStyle(QFrame.StyledPanel) commitHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(commitHeaderFrame) commitHeaderFrame.setFixedHeight(24) expandingCommitSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__selectAllButton = QToolButton() self.__selectAllButton.setAutoRaise(True) self.__selectAllButton.setIcon( PixmapCache().getIcon(pluginHomeDir + 'svnselectall.png')) self.__selectAllButton.setFixedSize(20, 20) self.__selectAllButton.setToolTip("Select all") self.__selectAllButton.setFocusPolicy(Qt.NoFocus) self.__selectAllButton.clicked.connect(self.__onSelectAll) commitHeaderLayout = QHBoxLayout() commitHeaderLayout.setContentsMargins(3, 0, 0, 0) commitHeaderLayout.addWidget( QLabel("Paths to commit (total: " + str(len(pathsToCommit)) + ")")) commitHeaderLayout.addSpacerItem(expandingCommitSpacer) commitHeaderLayout.addWidget(self.__selectAllButton) commitHeaderFrame.setLayout(commitHeaderLayout) vboxLayout.addWidget(commitHeaderFrame) self.__pathToCommitView = QTreeWidget() self.__configTable(self.__pathToCommitView) self.__pathToCommitHeader = QTreeWidgetItem(["", "Path", "Status", ""]) self.__pathToCommitView.setHeaderItem(self.__pathToCommitHeader) self.__pathToCommitView.header().setSortIndicator( PATH_COL, Qt.AscendingOrder) self.__pathToCommitView.itemChanged.connect(self.__onCommitPathChanged) vboxLayout.addWidget(self.__pathToCommitView) # Paths to ignore part headerFrame = QFrame() headerFrame.setFrameStyle(QFrame.StyledPanel) headerFrame.setAutoFillBackground(True) self.__setLightPalette(headerFrame) headerFrame.setFixedHeight(24) ignoreLabel = QLabel("Ignored paths (total: " + str(len(pathsToIgnore)) + ")") expandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideIgnoredButton = QToolButton() self.__showHideIgnoredButton.setAutoRaise(True) self.__showHideIgnoredButton.setIcon(PixmapCache().getIcon('less.png')) self.__showHideIgnoredButton.setFixedSize(20, 20) self.__showHideIgnoredButton.setToolTip("Show ignored path list") self.__showHideIgnoredButton.setFocusPolicy(Qt.NoFocus) self.__showHideIgnoredButton.clicked.connect(self.__onShowHideIgnored) ignoredHeaderLayout = QHBoxLayout() ignoredHeaderLayout.setContentsMargins(3, 0, 0, 0) ignoredHeaderLayout.addWidget(ignoreLabel) ignoredHeaderLayout.addSpacerItem(expandingSpacer) ignoredHeaderLayout.addWidget(self.__showHideIgnoredButton) headerFrame.setLayout(ignoredHeaderLayout) vboxLayout.addWidget(headerFrame) self.__pathToIgnoreView = QTreeWidget() self.__configTable(self.__pathToIgnoreView) self.__pathToIgnoreView.setVisible(False) pathToIgnoreHeader = QTreeWidgetItem(["Path", "Status"]) self.__pathToIgnoreView.setHeaderItem(pathToIgnoreHeader) self.__pathToIgnoreView.header().setSortIndicator(0, Qt.AscendingOrder) vboxLayout.addWidget(self.__pathToIgnoreView) # Message part vboxLayout.addWidget(QLabel("Message")) self.__message = QTextEdit() self.__message.setAcceptRichText(False) metrics = QFontMetrics(self.__message.font()) rect = metrics.boundingRect("X") self.__message.setFixedHeight(rect.height() * 4 + 5) vboxLayout.addWidget(self.__message) # Diff part diffHeaderFrame = QFrame() diffHeaderFrame.setFrameStyle(QFrame.StyledPanel) diffHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(diffHeaderFrame) diffHeaderFrame.setFixedHeight(24) diffLabel = QLabel("Diff") diffExpandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideDiffButton = QToolButton() self.__showHideDiffButton.setAutoRaise(True) self.__showHideDiffButton.setIcon(PixmapCache().getIcon('less.png')) self.__showHideDiffButton.setFixedSize(20, 20) self.__showHideDiffButton.setToolTip("Show diff") self.__showHideDiffButton.setFocusPolicy(Qt.NoFocus) self.__showHideDiffButton.clicked.connect(self.__onShowHideDiff) diffLayout = QHBoxLayout() diffLayout.setContentsMargins(3, 0, 0, 0) diffLayout.addWidget(diffLabel) diffLayout.addSpacerItem(diffExpandingSpacer) diffLayout.addWidget(self.__showHideDiffButton) diffHeaderFrame.setLayout(diffLayout) self.__diffViewer = DiffTabWidget() self.__diffViewer.setHTML(self.NODIFF) self.__diffViewer.setVisible(False) vboxLayout.addWidget(diffHeaderFrame) vboxLayout.addWidget(self.__diffViewer) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.__OKButton = buttonBox.button(QDialogButtonBox.Ok) self.__OKButton.setText("Commit") buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) buttonBox.accepted.connect(self.userAccept) buttonBox.rejected.connect(self.close) vboxLayout.addWidget(buttonBox) return def __onShowHideDiff(self): if self.__diffViewer.isVisible(): self.__diffViewer.setVisible(False) self.__showHideDiffButton.setIcon( PixmapCache().getIcon('less.png')) self.__showHideDiffButton.setToolTip("Show diff") else: self.__diffViewer.setVisible(True) self.__showHideDiffButton.setIcon( PixmapCache().getIcon('more.png')) self.__showHideDiffButton.setToolTip("Hide diff") return def __onShowHideIgnored(self): if self.__pathToIgnoreView.isVisible(): self.__pathToIgnoreView.setVisible(False) self.__showHideIgnoredButton.setIcon( PixmapCache().getIcon('less.png')) self.__showHideIgnoredButton.setToolTip("Show ignored path list") else: self.__pathToIgnoreView.setVisible(True) self.__showHideIgnoredButton.setIcon( PixmapCache().getIcon('more.png')) self.__showHideIgnoredButton.setToolTip("Hide ignored path list") return def userAccept(self): " Triggered when the user clicks OK " # Collect the list of checked paths self.commitMessage = self.__message.toPlainText().strip() self.commitPaths = [] index = 0 while index < self.__pathToCommitView.topLevelItemCount(): item = self.__pathToCommitView.topLevelItem(index) if item.checkState(0) == Qt.Checked: path = str(item.text(1)) if os.path.isdir( path ) and not os.path.islink( path ) and \ not path.endswith( os.path.sep ): path += os.path.sep self.commitPaths.append(path) index += 1 self.accept() return def __getCheckedCount(self): " Provides the number of selected items in the commit paths section " index = 0 checkedCount = 0 while index < self.__pathToCommitView.topLevelItemCount(): item = self.__pathToCommitView.topLevelItem(index) if item.checkState(0) == Qt.Checked: checkedCount += 1 index += 1 return checkedCount def __updateSelectAllStatus(self): " Updates the select all status button " total = self.__pathToCommitView.topLevelItemCount() if total == 0 or total == self.__getCheckedCount(): self.__selectAllButton.setEnabled(False) else: self.__selectAllButton.setEnabled(True) return def __updateOKStatus(self): " Updates the OK button status " self.__OKButton.setEnabled(self.__getCheckedCount() > 0) return def __onCommitPathChanged(self, item, column): " Triggered when an item is changed " self.__updateSelectAllStatus() self.__updateOKStatus() return def __onSelectAll(self): " Triggered when select all button is clicked " index = 0 while index < self.__pathToCommitView.topLevelItemCount(): item = self.__pathToCommitView.topLevelItem(index) item.setCheckState(0, Qt.Checked) index += 1 self.__updateSelectAllStatus() self.__updateOKStatus() return def onDiff(self, path, status): " Triggered when diff for the path is called " if not path: return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) try: # Status is one of the following: # IND_ADDED, IND_DELETED, IND_MERGED, IND_MODIFIED_LR, IND_MODIFIED_L, IND_CONFLICTED repositoryContent = "" localContent = "" if status != IND_ADDED: client = self.__plugin.getSVNClient( self.__plugin.getSettings()) repositoryContent = client.cat(path) if status != IND_DELETED: with open(path) as f: localContent = f.read() diff = difflib.unified_diff(repositoryContent.splitlines(), localContent.splitlines()) nodiffMessage = path + " has no difference to the " \ "repository at revision HEAD" if diff is None: QApplication.restoreOverrideCursor() logging.info(nodiffMessage) return # There are changes, so replace the text and tell about the changes diffAsText = '\n'.join(list(diff)) if diffAsText.strip() == '': QApplication.restoreOverrideCursor() logging.info(nodiffMessage) return source = "+++ local " + os.path.basename(path) diffAsText = diffAsText.replace("+++ ", source, 1) diffAsText = diffAsText.replace("--- ", "--- repository at revision HEAD", 1) self.__diffViewer.setHTML( parse_from_memory(diffAsText, False, True)) if not self.__diffViewer.isVisible(): self.__onShowHideDiff() except Exception, exc: logging.error(str(exc)) except:
class mainwindow(QtGui.QMainWindow): '''主窗体''' def __init__(self): super(mainwindow, self).__init__() self.setWindowTitle('组件设计工具') self.setWindowIcon(QIcon(':/image/组件设计工具.png')) self.setMinimumWidth(1024) self.setMinimumHeight(800) self.showMaximized() self.menuBar().show() self.createMenus() #self.setWindowFlags(QtCore.Qt.WindowMinimizeButtonHint) labelSizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) editSizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) cwVLayout = QVBoxLayout() cwHLayout = QHBoxLayout() lLayout = QVBoxLayout() rLayout = QVBoxLayout() self.lw = QListWidget() self.lw.setSelectionMode(QAbstractItemView.SingleSelection) lLayout.addWidget(self.lw) self.lw.itemSelectionChanged.connect(self.on_select) lGroup = QGroupBox('项目列表') lGroup.setLayout(lLayout) cwHLayout.addWidget(lGroup, 2) lGroup.setContentsMargins(0, 12, 0, 22) tLayout = QVBoxLayout() bLayout = QHBoxLayout() self.tGroup = QGroupBox('配置信息') self.bGroup = QGroupBox('生成代码') self.tGroup.setLayout(tLayout) self.tGroup.setEnabled(False) self.bGroup.setLayout(bLayout) self.bGroup.setEnabled(False) cwHLayout.addWidget(self.tGroup, 8) cwVLayout.addLayout(cwHLayout) cwVLayout.addWidget(self.bGroup) self.tw_config = QTreeWidget() headerLabels = QStringList() headerLabels.append(' 项目') headerLabels.append(' 值') self.tw_config.setHeaderLabels(headerLabels) self.tw_config.setColumnWidth(0, 312) self.tw_config.setColumnWidth(1, 660) thLayout = QHBoxLayout() thLayout.setContentsMargins(0, 6, 0, 0) thLayout.addSpacing(10) modify_btn = QPushButton('') #修改 modify_btn.setObjectName('modify_btn') modify_btn.clicked.connect(self.on_modify) del_btn = QPushButton('') #删除 del_btn.setObjectName('del_btn') del_btn.clicked.connect(self.on_del) thLayout.addWidget(modify_btn) thLayout.addWidget(del_btn) thLayout.addStretch(0) tLayout.addLayout(thLayout) tLayout.addWidget(self.tw_config) bhLayout = QHBoxLayout() lable1 = QLabel('工程名称:') lable1.setSizePolicy(labelSizePolicy) self.et_project_name = QLineEdit() self.et_project_name.setSizePolicy(editSizePolicy) bhLayout.addWidget(lable1) bhLayout.addWidget(self.et_project_name) bhLayout.addSpacing(16) lable2 = QLabel('工程位置:') lable2.setSizePolicy(labelSizePolicy) self.et_project_location = QLineEdit() self.et_project_location.setReadOnly(True) self.et_project_location.setSizePolicy(editSizePolicy) btn_location = QPushButton('') #打开 btn_location.setObjectName('btn_location') btn_location.setSizePolicy(labelSizePolicy) btn_location.clicked.connect(self.getProjectLocation) bhLayout.addWidget(lable2) bhLayout.addWidget(self.et_project_location) bhLayout.addSpacing(10) bhLayout.addWidget(btn_location) #bhLayout.addStretch(0) gen_btn = QPushButton('') # 生成 gen_btn.setObjectName('gen_btn') gen_btn.setSizePolicy(labelSizePolicy) gen_btn.clicked.connect(self.on_gen) bhLayout.addSpacing(45) bhLayout.addWidget(gen_btn) bLayout.addLayout(bhLayout) bLayout.setContentsMargins(10, 24, 22, 34) statusBar = self.statusBar() sBH = QHBoxLayout() copyright = QLabel('') copyright.setAlignment(QtCore.Qt.AlignCenter) copyright.setStyleSheet("color:#acacac") statusBar.setMinimumHeight(30) statusBar.addWidget(copyright, 10) cw = QWidget() cw.setLayout(cwVLayout) self.setCentralWidget(cw) self._initByConfig() self.setMinimumSize(400, 200) def _initByConfig(self): '''初始化''' pass def createMenus(self): '''创建菜单''' self.ToolBar = self.addToolBar('') self.ToolBar.setMinimumHeight(54) newBtn = QToolButton() newBtn.setText('创建项目') newBtn.setIcon(QIcon(':/image/创建项目.png')) newBtn.setToolButtonStyle(3) newBtn.setFixedWidth(99) OpenBtn = QToolButton() OpenBtn.setText('打开项目') OpenBtn.setIcon(QIcon(':/image/打开.png')) OpenBtn.setToolButtonStyle(3) OpenBtn.setFixedWidth(99) AboutBtn = QToolButton() AboutBtn.setText('关于') AboutBtn.setIcon(QIcon(':/image/关于.png')) AboutBtn.setToolButtonStyle(3) AboutBtn.setFixedWidth(99) HelpBtn = QToolButton() HelpBtn.setText('帮助') HelpBtn.setIcon(QIcon(':/image/帮助.png')) HelpBtn.setToolButtonStyle(3) HelpBtn.setFixedWidth(99) newBtn.clicked.connect(self.on_new) OpenBtn.clicked.connect(self.on_open) AboutBtn.clicked.connect(self.on_about) HelpBtn.clicked.connect(self.on_help) self.ToolBar.addWidget(newBtn) self.ToolBar.addWidget(OpenBtn) self.ToolBar.addWidget(AboutBtn) self.ToolBar.addWidget(HelpBtn) self.ToolBar.setMovable(False) self.ToolBar.setVisible(True) def on_help(self): app.g_pwd = os.getcwd() if not (QtGui.QDesktopServices.openUrl( QUrl.fromLocalFile(app.g_pwd + os.sep + 'image' + os.sep + 'help.pdf'))): print app.g_pwd + os.sep + '/image/help.pdf' QMessageBox.critical(None, "Failure", "Cannot open help manual") def on_about(self): abt = AboutDlg() abt.exec_() def on_new(self): '''新建向导''' app.g_configurations = Configuration() # 用来渲染的配置数据 dlg = wizard.MyWizard() if dlg.exec_(): app.g_configurations.initialized = True app.g_projects.append(app.g_configurations) content = app.g_configurations.toJson() self.path = QFileDialog.getSaveFileName( self, "选择模板保存的路径", app.g_pwd + os.sep + "configurations" + os.sep + app.g_configurations.project_name.encode('utf-8') + ".json", "Config (*.json)") fileInfo = QFileInfo(self.path) if not self.path.isEmpty(): path = app.QString2str(self.path) with open(path, 'w+') as f: f.write(content) self.addConfig(fileInfo.baseName(), fileInfo.filePath(), content) #self.lw.addItem(app.g_configurations.project_name) def getProjectLocation(self): '''获取项目路径''' path = QFileDialog.getExistingDirectory() path = QDir.fromNativeSeparators(path) self.et_project_location.setText(path) def on_open(self): '''打开现有配置''' fileName = QFileDialog.getOpenFileName( self, "选择现有模板", app.g_pwd + os.sep + "configurations", "Config (*.json)") if fileName.isEmpty(): return self.path = fileName with open(app.QString2str(fileName), 'r') as f: content = f.read() fileInfo = QFileInfo(fileName) if not fileInfo.exists(): return config = Configuration() config.fromJson(content) config.allone_dir = os.getenv('ALLONEDIR', '../..').replace('\\', '/') self.addConfig(fileInfo.baseName(), fileInfo.filePath(), content) self.on_select() def on_del(self): self.tw_config.clear() self.bGroup.setEnabled(False) self.tGroup.setEnabled(False) index = self.lw.currentRow() self.lw.takeItem(index) def on_select(self): '''选取配置''' item = self.lw.currentItem() if item != None: content = item.data(QtCore.Qt.UserRole).toString() config = Configuration() config.fromJson(app.QString2str(content)) self.currentConfig = config self.showConfigInfo(self.currentConfig) self.bGroup.setEnabled(True) self.path = item.data(QtCore.Qt.UserRole + 1).toString() # index = self.lw.currentRow() # if index < len(app.g_projects): # self.currentConfig = app.g_projects[index] # self.showConfigInfo(self.currentConfig) # self.bGroup.setEnabled(True) def addConfig(self, fileName, filePath, config): item = QListWidgetItem(fileName) item.setData(QtCore.Qt.UserRole, config) item.setData(QtCore.Qt.UserRole + 1, filePath) self.lw.addItem(item) self.lw.setCurrentRow(0) def showConfigInfo(self, cf): '''显示配置信息''' self.tw_config.clear() self.et_project_name.setText(cf.project_name) self.et_project_location.setText(cf.project_location) sr = QStringList() sr.append('信息') root1 = QTreeWidgetItem(sr) sr = QStringList() sr.append('Qt库') root2 = QTreeWidgetItem(sr) sr = QStringList() sr.append('模块') root3a = QTreeWidgetItem(sr) sr = QStringList() sr.append('第三方库') root3b = QTreeWidgetItem(sr) sr = QStringList() sr.append('接口') root4 = QTreeWidgetItem(sr) self.tw_config.addTopLevelItem(root1) self.tw_config.addTopLevelItem(root2) self.tw_config.addTopLevelItem(root3a) self.tw_config.addTopLevelItem(root3b) self.tw_config.addTopLevelItem(root4) sr1c00 = QStringList() sr1c00.append("项目名称") sr1c00.append(cf.project_name) r1c00 = QTreeWidgetItem(sr1c00) root1.addChild(r1c00) # sr1c0 = QStringList() # sr1c0.append("项目位置") # sr1c0.append(cf.project_location) # r1c0 = QTreeWidgetItem(sr1c0) # root1.addChild(r1c0) sr1c1 = QStringList() sr1c1.append("组件类型") sr1c1.append(cf.component_type) r1c1 = QTreeWidgetItem(sr1c1) root1.addChild(r1c1) sr1c2 = QStringList() sr1c2.append("源模板") sr1c2.append(cf.template_source) r1c2 = QTreeWidgetItem(sr1c2) root1.addChild(r1c2) sr1c3 = QStringList() sr1c3.append("平台类型") tmp_pt = "" if cf.platform_type & configuration.PT_WIN32: tmp_pt += "win32;" if cf.platform_type & configuration.PT_LINUX: tmp_pt += "linux" sr1c3.append(tmp_pt) r1c3 = QTreeWidgetItem(sr1c3) root1.addChild(r1c3) sr1c4 = QStringList() sr1c4.append("平台级别") sr1c4.append(cf.platform_version) r1c4 = QTreeWidgetItem(sr1c4) root1.addChild(r1c4) sr1c5 = QStringList() sr1c5.append("资源文件") if cf.resourcesFile == "True": sr1c5.append("添加") else: sr1c5.append("未添加") r1c5 = QTreeWidgetItem(sr1c5) root1.addChild(r1c5) sr1c6 = QStringList() sr1c6.append("翻译文件") if cf.translateFile == "True": sr1c6.append("添加") else: sr1c6.append("未添加") r1c6 = QTreeWidgetItem(sr1c6) root1.addChild(r1c6) for qt in cf.qt_libs: sr2 = QStringList() sr2.append(qt['name']) sr2.append(qt['qt']) r2 = QTreeWidgetItem(sr2) root2.addChild(r2) for module in cf.modules: sr3a = QStringList() sr3a.append(module['name']) sr3a.append(module['description']) r3a = QTreeWidgetItem(sr3a) root3a.addChild(r3a) # sr3b = QStringList() # sr3b.append('ALLONE_DIR') # sr3b.append(os.getenv('ALLONEDIR','../..')) # 第二个参数是默认值 # r3b = QTreeWidgetItem(sr3b) # root3b.addChild(r3b) for info in cf.thirdpart_lib: sr3b = QStringList() sr3b.append(info['libname']) sr3b.append(info['libpath']) r3b = QTreeWidgetItem(sr3b) root3b.addChild(r3b) for key in cf.interfaces.keys(): sr4 = QStringList() sr4.append(key) if cf.interfaces[key]: sr4.append('实现') else: sr4.append('未实现') r4 = QTreeWidgetItem(sr4) root4.addChild(r4) self.tw_config.expandAll() self.tw_config.header().resizeSection(0, 300) self.tGroup.setEnabled(True) def on_modify(self): '''修改配置''' if self.currentConfig: app.g_configurations = copy.copy(self.currentConfig) dlg = wizard.MyWizard() if dlg.exec_(): item = self.lw.currentItem() if item != None: content = app.g_configurations.toJson() item.setData(QtCore.Qt.UserRole, content) path = item.data(QtCore.Qt.UserRole + 1).toString() if not path.isEmpty(): path = app.QString2str(path) with open(path, 'w+') as f: f.write(content) self.on_select() def on_gen(self): '''生成工程''' if not self.currentConfig: return #获取工程名及有效路径 project_name = self.et_project_name.text() project_location = self.et_project_location.text() qdir = QDir(project_location) if not qdir.exists(): if not qdir.mkpath(project_location): QMessageBox.warning(self, '警告', '路径无效!') return project_location = qdir.absolutePath() if not project_location.endsWith( '/') and not project_location.endsWith('\\'): project_location += os.sep project_location.replace('\\', '/') if project_name.isEmpty() or project_location.isEmpty(): QMessageBox.warning(self, '警告', '项目名称或路径不能为空!') return self.currentConfig.project_name = app.QString2str(project_name) self.currentConfig.project_location = app.QString2str(project_location) content = self.currentConfig.toJson() fileInfo = QFileInfo(self.path) if not self.path.isEmpty(): path = app.QString2str(self.path) with open(path, 'w+') as f: f.write(content) item = self.lw.currentItem() item.setData(QtCore.Qt.UserRole, content) template_name = self.currentConfig.template_source template_dir = app.g_pwd + os.sep + 'templates' + os.sep + template_name.encode( 'utf-8') with open(template_dir + os.sep + 'config.json', 'r') as f: self.currentConfig.config_content = f.read() ret_json = app.render(self.currentConfig.config_content, config=self.currentConfig) self.currentConfig.config = json.loads(ret_json) for file in self.currentConfig.config['files']: sourcepath = template_dir + os.sep + file['source'].encode('utf-8') targetdir = self.currentConfig.project_location + self.currentConfig.project_name targetpath = targetdir + os.sep + file['target'] fi = QFileInfo(targetpath) qdir = fi.absoluteDir() if not qdir.exists(): qdir.mkpath(fi.absolutePath()) with open(sourcepath, 'r') as f: content = f.read() content = app.render(content, config=self.currentConfig) #渲染文件 with open(targetpath, 'w+') as f: f.write(content.encode('utf-8')) QMessageBox.information(self, '提示', '生成成功!')
class TreeSymbolsWidget(QDialog): """Class of Dialog for Tree Symbols""" def __init__(self, parent=None): super(TreeSymbolsWidget, self).__init__(parent, Qt.WindowStaysOnTopHint) vbox = QVBoxLayout(self) vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) self.tree = QTreeWidget() vbox.addWidget(self.tree) self.tree.header().setHidden(True) self.tree.setSelectionMode(self.tree.SingleSelection) self.tree.setAnimated(True) self.tree.header().setHorizontalScrollMode( QAbstractItemView.ScrollPerPixel) self.tree.header().setResizeMode(0, QHeaderView.ResizeToContents) self.tree.header().setStretchLastSection(False) self.actualSymbols = ('', {}) self.docstrings = {} self.collapsedItems = {} self.connect(self, SIGNAL("itemClicked(QTreeWidgetItem *, int)"), self._go_to_definition) self.connect(self, SIGNAL("itemActivated(QTreeWidgetItem *, int)"), self._go_to_definition) self.tree.setContextMenuPolicy(Qt.CustomContextMenu) self.connect(self, SIGNAL("customContextMenuRequested(const QPoint &)"), self._menu_context_tree) self.connect(self, SIGNAL("itemCollapsed(QTreeWidgetItem *)"), self._item_collapsed) self.connect(self, SIGNAL("itemExpanded(QTreeWidgetItem *)"), self._item_expanded) IDE.register_service('symbols_explorer', self) ExplorerContainer.register_tab(translations.TR_TAB_SYMBOLS, self) def install_tab(self): """Connect signals for goingdown""" ide = IDE.get_service('ide') self.connect(ide, SIGNAL("goingDown()"), self.close) def _menu_context_tree(self, point): """Context menu""" index = self.tree.indexAt(point) if not index.isValid(): return menu = QMenu(self) f_all = menu.addAction(translations.TR_FOLD_ALL) u_all = menu.addAction(translations.TR_UNFOLD_ALL) menu.addSeparator() u_class = menu.addAction(translations.TR_UNFOLD_CLASSES) u_class_method = menu.addAction( translations.TR_UNFOLD_CLASSES_AND_METHODS) u_class_attr = menu.addAction( translations.TR_UNFOLD_CLASSES_AND_ATTRIBUTES) menu.addSeparator() #save_state = menu.addAction(self.tr("Save State")) self.connect(f_all, SIGNAL("triggered()"), lambda: self.tree.collapseAll()) self.connect(u_all, SIGNAL("triggered()"), lambda: self.tree.expandAll()) self.connect(u_class, SIGNAL("triggered()"), self._unfold_class) self.connect(u_class_method, SIGNAL("triggered()"), self._unfold_class_method) self.connect(u_class_attr, SIGNAL("triggered()"), self._unfold_class_attribute) #self.connect(save_state, SIGNAL("triggered()"), #self._save_symbols_state) menu.exec_(QCursor.pos()) def _get_classes_root(self): """Return the root of classes""" class_root = None for i in range(self.tree.topLevelItemCount()): item = self.tree.topLevelItem(i) if item.isClass and not item.isClickable: class_root = item break return class_root def _unfold_class(self): """Method to Unfold Classes""" self.tree.collapseAll() classes_root = self._get_classes_root() if not classes_root: return classes_root.setExpanded(True) def _unfold_class_method(self): """Method to Unfold Methods""" self.tree.expandAll() classes_root = self._get_classes_root() if not classes_root: return #for each class! for i in range(classes_root.childCount()): class_item = classes_root.child(i) #for each attribute or functions for j in range(class_item.childCount()): item = class_item.child(j) #METHODS ROOT!! if not item.isMethod and not item.isClickable: item.setExpanded(False) break def _unfold_class_attribute(self): """Method to Unfold Attributes""" self.tree.expandAll() classes_root = self._get_classes_root() if not classes_root: return #for each class! for i in range(classes_root.childCount()): class_item = classes_root.child(i) #for each attribute or functions for j in range(class_item.childCount()): item = class_item.child(j) #ATTRIBUTES ROOT!! if not item.isAttribute and not item.isClickable: item.setExpanded(False) break def _save_symbols_state(self): """Method to Save a persistent Symbols state""" #filename = self.actualSymbols[0] #TODO: persist self.collapsedItems[filename] in QSettings pass def _get_expand(self, item): """ Returns True or False to be used as setExpanded() with the items It method is based on the click that the user made in the tree """ name = self._get_unique_name(item) filename = self.actualSymbols[0] collapsed_items = self.collapsedItems.get(filename, []) can_check = (not item.isClickable) or item.isClass or item.isMethod if can_check and name in collapsed_items: return False return True @staticmethod def _get_unique_name(item): """ Returns a string used as unique name """ # className_Attributes/className_Functions parent = item.parent() if parent: return "%s_%s" % (parent.text(0), item.text(0)) return "_%s" % item.text(0) def update_symbols_tree(self, symbols, filename='', parent=None): """Method to Update the symbols on the Tree""" if not parent: if filename == self.actualSymbols[0] and \ self.actualSymbols[1] and not symbols: return if symbols == self.actualSymbols[1]: # Nothing new then return return # we have new symbols refresh it self.tree.clear() self.actualSymbols = (filename, symbols) self.docstrings = symbols.get('docstrings', {}) parent = self.tree if 'attributes' in symbols: globalAttribute = ItemTree(parent, [translations.TR_ATTRIBUTES]) globalAttribute.isClickable = False globalAttribute.isAttribute = True globalAttribute.setExpanded(self._get_expand(globalAttribute)) for glob in sorted(symbols['attributes']): globItem = ItemTree(globalAttribute, [glob], lineno=symbols['attributes'][glob]) globItem.isAttribute = True globItem.setIcon(0, QIcon(":img/attribute")) globItem.setExpanded(self._get_expand(globItem)) if 'functions' in symbols and symbols['functions']: functionsItem = ItemTree(parent, [translations.TR_FUNCTIONS]) functionsItem.isClickable = False functionsItem.isMethod = True functionsItem.setExpanded(self._get_expand(functionsItem)) for func in sorted(symbols['functions']): item = ItemTree(functionsItem, [func], lineno=symbols['functions'][func]['lineno']) tooltip = self.create_tooltip( func, symbols['functions'][func]['lineno']) item.isMethod = True item.setIcon(0, QIcon(":img/function")) item.setToolTip(0, tooltip) item.setExpanded(self._get_expand(item)) self.update_symbols_tree( symbols['functions'][func]['functions'], parent=item) if 'classes' in symbols and symbols['classes']: classItem = ItemTree(parent, [translations.TR_CLASSES]) classItem.isClickable = False classItem.isClass = True classItem.setExpanded(self._get_expand(classItem)) for claz in sorted(symbols['classes']): line_number = symbols['classes'][claz]['lineno'] item = ItemTree(classItem, [claz], lineno=line_number) item.isClass = True tooltip = self.create_tooltip(claz, line_number) item.setToolTip(0, tooltip) item.setIcon(0, QIcon(":img/class")) item.setExpanded(self._get_expand(item)) self.update_symbols_tree(symbols['classes'][claz]['members'], parent=item) def _go_to_definition(self, item): """Takes and item object and goes to definition on the editor""" main_container = IDE.get_service('main_container') if item.isClickable and main_container: main_container.editor_go_to_line(item.lineno - 1) def create_tooltip(self, name, lineno): """Takes a name and line number and returns a tooltip""" doc = self.docstrings.get(lineno, None) if doc is None: doc = '' else: doc = '\n' + doc tooltip = name + doc return tooltip def _item_collapsed(self, item): """When item collapsed""" super(TreeSymbolsWidget, self).collapseItem(item) can_check = (not item.isClickable) or item.isClass or item.isMethod if can_check: n = self._get_unique_name(item) filename = self.actualSymbols[0] self.collapsedItems.setdefault(filename, []) if not n in self.collapsedItems[filename]: self.collapsedItems[filename].append(n) def _item_expanded(self, item): """When item expanded""" super(TreeSymbolsWidget, self).expandItem(item) n = self._get_unique_name(item) filename = self.actualSymbols[0] if n in self.collapsedItems.get(filename, []): self.collapsedItems[filename].remove(n) if not len(self.collapsedItems[filename]): # no more items, free space del self.collapsedItems[filename] def clean(self): """ Reset the tree and reset attributes """ self.tree.clear() self.collapsedItems = {} def reject(self): if self.parent() is None: self.emit(SIGNAL("dockWidget(PyQt_PyObject)"), self) def closeEvent(self, event): """On Close event handling""" self.emit(SIGNAL("dockWidget(PyQt_PyObject)"), self) event.ignore()
class XConsoleEdit(XLoggerWidget): __designer_icon__ = projexui.resources.find('img/ui/console.png') def __init__( self, parent ): super(XConsoleEdit, self).__init__(parent) self.setLogger(logging.getLogger()) # create custom properties self._completerTree = None self._commandStack = [] self._highlighter = XConsoleHighlighter(self.document()) # set properties font = QFont('Courier New') font.setPointSize(9) self.setFont(font) self.setReadOnly(False) self.waitForInput() metrics = QFontMetrics(font) self.setTabStopWidth(4 * metrics.width(' ')) # create connections XStream.stdout().messageWritten.connect( self.information ) XStream.stderr().messageWritten.connect( self.error ) def __del__( self ): XStream.stdout().messageWritten.disconnect( self.information ) XStream.stderr().messageWritten.disconnect( self.error ) def acceptCompletion( self ): """ Accepts the current completion and inserts the code into the edit. :return <bool> accepted """ tree = self._completerTree if not tree: return False tree.hide() item = tree.currentItem() if not item: return False # clear the previously typed code for the block cursor = self.textCursor() text = cursor.block().text() col = cursor.columnNumber() end = col while col: col -= 1 if text[col] == '.': col += 1 break # insert the current text cursor.setPosition(cursor.position() - (end-col), cursor.KeepAnchor) cursor.removeSelectedText() self.insertPlainText(item.text(0)) return True def applyCommand( self ): """ Applies the current line of code as an interactive python command. """ # grab the command from the current line block = self.textCursor().block().text() match = INPUT_EXPR.match(projex.text.toUtf8(block)) # if there is no command, then wait for the input if not match: self.waitForInput() return self.executeCommand(match.group(2).rstrip(), match.group(1).strip()) def cancelCompletion( self ): """ Cancels the current completion. """ if ( self._completerTree ): self._completerTree.hide() def clear( self ): """ Clears the current text and starts a new input line. """ super(XConsoleEdit, self).clear() self.waitForInput() def closeEvent( self, event ): """ Disconnects from the stderr/stdout on close. :param event | <QCloseEvent> """ if ( self.clearOnClose() ): XStream.stdout().messageWritten.disconnect( self.information ) XStream.stderr().messageWritten.disconnect( self.error ) super(XConsoleEdit, self).closeEvent(event) def completerTree( self ): """ Returns the completion tree for this instance. :return <QTreeWidget> """ if ( not self._completerTree ): self._completerTree = QTreeWidget(self) self._completerTree.setWindowFlags(Qt.Popup) self._completerTree.setAlternatingRowColors( True ) self._completerTree.installEventFilter(self) self._completerTree.itemClicked.connect( self.acceptCompletion ) self._completerTree.setRootIsDecorated(False) self._completerTree.header().hide() return self._completerTree def eventFilter( self, obj, event ): """ Filters particular events for a given QObject through this class. \ Will use this to intercept events to the completer tree widget while \ filtering. :param obj | <QObject> event | <QEvent> :return <bool> consumed """ if ( not obj == self._completerTree ): return False if ( event.type() != event.KeyPress ): return False if ( event.key() == Qt.Key_Escape ): QToolTip.hideText() self.cancelCompletion() return False elif ( event.key() in (Qt.Key_Enter, Qt.Key_Return, Qt.Key_Tab) ): self.acceptCompletion() return False elif ( event.key() in (Qt.Key_Up, Qt.Key_Down) ): return False else: self.keyPressEvent(event) # update the completer cursor = self.textCursor() text = projex.text.toUtf8(cursor.block().text()) text = text[:cursor.columnNumber()].split(' ')[-1] text = text.split('.')[-1] self._completerTree.blockSignals(True) self._completerTree.setUpdatesEnabled(False) self._completerTree.setCurrentItem(None) for i in range(self._completerTree.topLevelItemCount()): item = self._completerTree.topLevelItem(i) if projex.text.toUtf8(item.text(0)).startswith(text): self._completerTree.setCurrentItem(item) break self._completerTree.blockSignals(False) self._completerTree.setUpdatesEnabled(True) return True def executeCommand(self, command, mode='>>>'): """ Executes the inputed command in the global scope. :param command | <unicode> :return <variant> """ # check to see if we're starting a new line if mode == '...' and not command.strip(): command = '\n'.join(self._commandStack) elif command.endswith(':') or mode == '...': self._commandStack.append(command) self.insertPlainText('\n... ') return # if we're not at the end of the console, then add it to the end elif not self.textCursor().atEnd(): self.waitForInput() self.insertPlainText(command) return self._commandStack = [] # insert a new line self.insertPlainText('\n') cmdresult = None try: cmdresult = eval(command, __main__.__dict__, __main__.__dict__) except SyntaxError: exec(command) in __main__.__dict__, __main__.__dict__ # print the resulting commands if cmdresult != None: self.information(projex.text.toUtf8(cmdresult)) self.waitForInput() def highlighter(self): """ Returns the console highlighter for this widget. :return <XConsoleHighlighter> """ return self._highlighter def gotoHome( self ): """ Navigates to the home position for the edit. """ mode = QTextCursor.MoveAnchor # select the home if QApplication.instance().keyboardModifiers() == Qt.ShiftModifier: mode = QTextCursor.KeepAnchor cursor = self.textCursor() block = projex.text.toUtf8(cursor.block().text()) cursor.movePosition( QTextCursor.StartOfBlock, mode ) if ( block.startswith('>>> ') ): cursor.movePosition( QTextCursor.Right, mode, 4 ) self.setTextCursor(cursor) def keyPressEvent( self, event ): """ Overloads the key press event to control keystroke modifications for \ the console widget. :param event | <QKeyEvent> """ # enter || return keys will apply the command if event.key() in (Qt.Key_Return, Qt.Key_Enter): self.applyCommand() # home key will move the cursor to the home position elif event.key() == Qt.Key_Home: self.gotoHome() elif event.key() in (Qt.Key_Backspace, Qt.Key_Delete): super(XConsoleEdit, self).keyPressEvent(event) # update the completer cursor = self.textCursor() text = projex.text.toUtf8(cursor.block().text()) text = text[:cursor.columnNumber()].split(' ')[-1] if not '.' in text: self.cancelCompletion() # period key will trigger a completion popup elif event.key() == Qt.Key_Period: self.startCompletion() super(XConsoleEdit, self).keyPressEvent(event) # space, tab, backspace and delete will cancel the completion elif event.key() == Qt.Key_Space: self.cancelCompletion() super(XConsoleEdit, self).keyPressEvent(event) # left parenthesis will start method help elif event.key() == Qt.Key_ParenLeft: self.cancelCompletion() self.showMethodToolTip() super(XConsoleEdit, self).keyPressEvent(event) # otherwise, handle the event like normal else: super(XConsoleEdit, self).keyPressEvent(event) def objectAtCursor( self ): """ Returns the python object that the text is representing. :return <object> || None """ # determine the text block cursor = self.textCursor() text = projex.text.toUtf8(cursor.block().text()) col = cursor.columnNumber() end = col while ( col ): col -= 1 if ( re.match('[^a-zA-Z\._\(\)]', text[col]) ): break symbol = text[col:end].rstrip('.(') try: return eval(symbol, __main__.__dict__, __main__.__dict__) except: return None def showMethodToolTip( self ): """ Pops up a tooltip message with the help for the object under the \ cursor. :return <bool> success """ self.cancelCompletion() obj = self.objectAtCursor() if ( not obj ): return False docs = inspect.getdoc(obj) if ( not docs ): return False # determine the cursor position rect = self.cursorRect() cursor = self.textCursor() point = QPoint(rect.left(), rect.top() + 18) QToolTip.showText( self.mapToGlobal(point), docs, self ) return True def startCompletion( self ): """ Starts a new completion popup for the current object. :return <bool> success """ # add the top level items tree = self.completerTree() tree.clear() # make sure we have a valid object obj = self.objectAtCursor() if ( obj is None ): return False # determine the cursor position rect = self.cursorRect() cursor = self.textCursor() point = QPoint(rect.left(), rect.top() + 18) try: o_keys = obj.__dir__() except (AttributeError, TypeError): o_keys = dir(obj) keys = [key for key in sorted(o_keys) if not key.startswith('_')] if ( not keys ): return False for key in keys: tree.addTopLevelItem(QTreeWidgetItem([key])) tree.move(self.mapToGlobal(point)) tree.show() return True def waitForInput( self ): """ Inserts a new input command into the console editor. """ if ( self.isReadOnly() ): return self.moveCursor( QTextCursor.End ) if ( self.textCursor().block().text() == '>>> ' ): return # if there is already text on the line, then start a new line newln = '>>> ' if projex.text.toUtf8(self.textCursor().block().text()): newln = '\n' + newln # insert the text self.setCurrentMode('standard') self.insertPlainText(newln) self.scrollToEnd() self._blankCache = ''
class OWPIPAx(widget.OWWidget): name = "PIPAx" description = "Access data from PIPA RNA-Seq database." icon = "../widgets/icons/PIPA.svg" priority = 35 inputs = [] outputs = [("Data", Orange.data.Table)] username = settings.Setting("") password = settings.Setting("") log2 = settings.Setting(False) rtypei = settings.Setting(5) # hardcoded rpkm mapability polya excludeconstant = settings.Setting(False) joinreplicates = settings.Setting(False) #: The stored current selection (in experiments view) #: SelectionByKey | None currentSelection = settings.Setting(None) #: Stored selections (presets) #: list of SelectionByKey storedSelections = settings.Setting([]) #: Stored column sort keys (from Sort view) #: list of strings storedSortingOrder = settings.Setting( ["Strain", "Experiment", "Genotype", "Timepoint"]) experimentsHeaderState = settings.Setting( {name: False for _, name in HEADER[:ID_INDEX + 1]}) def __init__(self, parent=None, signalManager=None, name="PIPAx"): super().__init__(parent) self.selectedExperiments = [] self.buffer = dicty.CacheSQLite(bufferfile) self.searchString = "" self.result_types = [] self.mappings = {} self.controlArea.setMaximumWidth(250) self.controlArea.setMinimumWidth(250) gui.button(self.controlArea, self, "Reload", callback=self.Reload) gui.button(self.controlArea, self, "Clear cache", callback=self.clear_cache) b = gui.widgetBox(self.controlArea, "Experiment Sets") self.selectionSetsWidget = SelectionSetsWidget(self) self.selectionSetsWidget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) def store_selections(modified): if not modified: self.storedSelections = self.selectionSetsWidget.selections self.selectionSetsWidget.selectionModified.connect(store_selections) b.layout().addWidget(self.selectionSetsWidget) gui.separator(self.controlArea) b = gui.widgetBox(self.controlArea, "Sort output columns") self.columnsSortingWidget = SortedListWidget(self) self.columnsSortingWidget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) def store_sort_order(): self.storedSortingOrder = self.columnsSortingWidget.sortingOrder self.columnsSortingWidget.sortingOrderChanged.connect(store_sort_order) b.layout().addWidget(self.columnsSortingWidget) sorting_model = QStringListModel(SORTING_MODEL_LIST) self.columnsSortingWidget.setModel(sorting_model) gui.separator(self.controlArea) box = gui.widgetBox(self.controlArea, 'Expression Type') self.expressionTypesCB = gui.comboBox(box, self, "rtypei", items=[], callback=self.UpdateResultsList) gui.checkBox(self.controlArea, self, "excludeconstant", "Exclude labels with constant values") gui.checkBox(self.controlArea, self, "joinreplicates", "Average replicates (use median)") gui.checkBox(self.controlArea, self, "log2", "Logarithmic (base 2) transformation") self.commit_button = gui.button(self.controlArea, self, "&Commit", callback=self.Commit) self.commit_button.setDisabled(True) gui.rubber(self.controlArea) box = gui.widgetBox(self.controlArea, "Authentication") gui.lineEdit(box, self, "username", "Username:"******"password", "Password:"******"searchString", "Search", callbackOnType=True, callback=self.SearchUpdate) self.headerLabels = [t[1] for t in HEADER] self.experimentsWidget = QTreeWidget() self.experimentsWidget.setHeaderLabels(self.headerLabels) self.experimentsWidget.setSelectionMode(QTreeWidget.ExtendedSelection) self.experimentsWidget.setRootIsDecorated(False) self.experimentsWidget.setSortingEnabled(True) contextEventFilter = gui.VisibleHeaderSectionContextEventFilter( self.experimentsWidget, self.experimentsWidget) self.experimentsWidget.header().installEventFilter(contextEventFilter) self.experimentsWidget.setItemDelegateForColumn( 0, gui.IndicatorItemDelegate(self, role=Qt.DisplayRole)) self.experimentsWidget.setAlternatingRowColors(True) self.experimentsWidget.selectionModel().selectionChanged.connect( self.onSelectionChanged) self.selectionSetsWidget.setSelectionModel( self.experimentsWidget.selectionModel()) self.mainArea.layout().addWidget(self.experimentsWidget) # Restore the selection states from the stored settings self.selectionSetsWidget.selections = self.storedSelections self.columnsSortingWidget.sortingOrder = self.storedSortingOrder self.restoreHeaderState() self.experimentsWidget.header().geometriesChanged.connect( self.saveHeaderState) self.dbc = None self.AuthSet() QTimer.singleShot(100, self.UpdateExperiments) def sizeHint(self): return QSize(800, 600) def AuthSet(self): if len(self.username): self.passf.setDisabled(False) else: self.passf.setDisabled(True) def AuthChanged(self): self.AuthSet() self.ConnectAndUpdate() def ConnectAndUpdate(self): self.Connect() self.UpdateExperiments(reload=True) def Connect(self): self.error(1) self.warning(1) def en(x): return x if len(x) else None self.dbc = dicty.PIPAx(cache=self.buffer, username=en(self.username), password=self.password) # check password if en(self.username) != None: try: self.dbc.mappings(reload=True) except dicty.AuthenticationError: self.error(1, "Wrong username or password") self.dbc = None except Exception as ex: print("Error when contacting the PIPA database", ex) sys.excepthook(*sys.exc_info()) try: # maybe cached? self.dbc.mappings() self.warning( 1, "Can not access database - using cached data.") except Exception as ex: self.dbc = None self.error(1, "Can not access database.") def Reload(self): self.UpdateExperiments(reload=True) def clear_cache(self): self.buffer.clear() self.Reload() def rtype(self): """Return selected result template type """ if self.result_types: return self.result_types[self.rtypei][0] else: return "-1" def UpdateExperimentTypes(self): self.expressionTypesCB.clear() items = [desc for _, desc in self.result_types] self.expressionTypesCB.addItems(items) self.rtypei = max(0, min(self.rtypei, len(self.result_types) - 1)) def UpdateExperiments(self, reload=False): self.experimentsWidget.clear() self.items = [] self.progressBarInit() if not self.dbc: self.Connect() mappings = {} result_types = [] sucind = False # success indicator for database index try: mappings = self.dbc.mappings(reload=reload) result_types = self.dbc.result_types(reload=reload) sucind = True except Exception as ex: try: mappings = self.dbc.mappings() result_types = self.dbc.result_types() self.warning(0, "Can not access database - using cached data.") sucind = True except Exception as ex: self.error(0, "Can not access database.") if sucind: self.warning(0) self.error(0) self.mappings = mappings self.result_types = result_types self.UpdateExperimentTypes() self.UpdateResultsList(reload=reload) self.progressBarFinished() if self.currentSelection: self.currentSelection.select( self.experimentsWidget.selectionModel()) self.handle_commit_button() def UpdateResultsList(self, reload=False): results_list = {} try: results_list = self.dbc.results_list(self.rtype(), reload=reload) except Exception as ex: try: results_list = self.dbc.results_list(self.rtype()) except Exception as ex: self.error(0, "Can not access database.") self.results_list = results_list mappings_key_dict = dict(((m["data_id"], m["id"]), key) \ for key, m in self.mappings.items()) def mapping_unique_id(annot): """Map annotations dict from results_list to unique `mappings` ids. """ data_id, mappings_id = annot["data_id"], annot["mappings_id"] return mappings_key_dict[data_id, mappings_id] elements = [] # softly change the view so that the selection stays the same items_shown = {} for i, item in enumerate(self.items): c = str(item.text(10)) items_shown[c] = i items_to_show = dict((mapping_unique_id(annot), annot) for annot in self.results_list.values()) add_items = set(items_to_show) - set(items_shown) delete_items = set(items_shown) - set(items_to_show) i = 0 while i < self.experimentsWidget.topLevelItemCount(): it = self.experimentsWidget.topLevelItem(i) if str(it.text(10)) in delete_items: self.experimentsWidget.takeTopLevelItem(i) else: i += 1 delete_ind = set([items_shown[i] for i in delete_items]) self.items = [ it for i, it in enumerate(self.items) if i not in delete_ind ] for r_annot in [items_to_show[i] for i in add_items]: d = defaultdict(lambda: "?", r_annot) row_items = [""] + [d.get(key, "?") for key, _ in HEADER[1:]] try: time_dict = literal_eval(row_items[DATE_INDEX]) date_rna = date( time_dict["fullYearUTC"], time_dict["monthUTC"] + 1, # Why is month 0 based? time_dict["dateUTC"]) row_items[DATE_INDEX] = date_rna.strftime("%x") except Exception: row_items[DATE_INDEX] = '' row_items[ID_INDEX] = mapping_unique_id(r_annot) elements.append(row_items) ci = MyTreeWidgetItem(self.experimentsWidget, row_items) self.items.append(ci) for i in range(len(self.headerLabels)): self.experimentsWidget.resizeColumnToContents(i) # which is the ok buffer version # FIXME: what attribute to use for version? self.wantbufver = \ lambda x, ad=self.results_list: \ defaultdict(lambda: "?", ad[x])["date"] self.wantbufver = lambda x: "0" self.UpdateCached() def UpdateCached(self): if self.wantbufver and self.dbc: fn = self.dbc.download_key_function() result_id_key = dict(((m["data_id"], m["mappings_id"]), key) \ for key, m in self.results_list.items()) for item in self.items: c = str(item.text(10)) mapping = self.mappings[c] data_id, mappings_id = mapping["data_id"], mapping["id"] r_id = result_id_key[data_id, mappings_id] # Get the buffered version buffered = self.dbc.inBuffer(fn(r_id)) value = " " if buffered == self.wantbufver(r_id) else "" item.setData(0, Qt.DisplayRole, value) def SearchUpdate(self, string=""): for item in self.items: item.setHidden(not all(s in item \ for s in self.searchString.split()) ) def Commit(self): if not self.dbc: self.Connect() pb = gui.ProgressBar(self, iterations=100) table = None ids = [] for item in self.experimentsWidget.selectedItems(): unique_id = str(item.text(10)) annots = self.mappings[unique_id] ids.append((annots["data_id"], annots["id"])) transfn = None if self.log2: transfn = lambda x: math.log(x + 1.0, 2) reverse_header_dict = dict((name, key) for key, name in HEADER) hview = self.experimentsWidget.header() shownHeaders = [label for i, label in \ list(enumerate(self.headerLabels))[1:] \ if not hview.isSectionHidden(i) ] allowed_labels = [reverse_header_dict.get(label, label) \ for label in shownHeaders] if self.joinreplicates and "id" not in allowed_labels: # need 'id' labels in join_replicates for attribute names allowed_labels.append("id") if len(ids): table = self.dbc.get_data( ids=ids, result_type=self.rtype(), callback=pb.advance, exclude_constant_labels=self.excludeconstant, # bufver=self.wantbufver, transform=transfn, allowed_labels=allowed_labels) if self.joinreplicates: table = dicty.join_replicates(table, ignorenames=[ "replicate", "data_id", "mappings_id", "data_name", "id", "unique_id" ], namefn=None, avg=dicty.median) # Sort attributes sortOrder = self.columnsSortingWidget.sortingOrder all_values = defaultdict(set) for at in table.domain.attributes: atts = at.attributes for name in sortOrder: all_values[name].add( atts.get(reverse_header_dict[name], "")) isnum = {} for at, vals in all_values.items(): vals = filter(None, vals) try: for a in vals: float(a) isnum[at] = True except: isnum[at] = False def optfloat(x, at): if x == "": return "" else: return float(x) if isnum[at] else x def sorting_key(attr): atts = attr.attributes return tuple([optfloat(atts.get(reverse_header_dict[name], ""), name) \ for name in sortOrder]) attributes = sorted(table.domain.attributes, key=sorting_key) domain = Orange.data.Domain(attributes, table.domain.class_var, table.domain.metas) table = table.from_table(domain, table) data_hints.set_hint(table, "taxid", "352472") data_hints.set_hint(table, "genesinrows", False) self.send("Data", table) self.UpdateCached() pb.finish() def onSelectionChanged(self, selected, deselected): self.handle_commit_button() def handle_commit_button(self): self.currentSelection = \ SelectionByKey(self.experimentsWidget.selectionModel().selection(), key=(1, 2, 3, 10)) self.commit_button.setDisabled(not len(self.currentSelection)) def saveHeaderState(self): hview = self.experimentsWidget.header() for i, label in enumerate(self.headerLabels): self.experimentsHeaderState[label] = hview.isSectionHidden(i) def restoreHeaderState(self): hview = self.experimentsWidget.header() state = self.experimentsHeaderState for i, label in enumerate(self.headerLabels): hview.setSectionHidden(i, state.get(label, True)) self.experimentsWidget.resizeColumnToContents(i)
class VersionSelectDialog(QDialog): def __init__(self, parent): # initialize the super class super(VersionSelectDialog, self).__init__(parent) # create the tree self.uiVersionsTREE = QTreeWidget(self) self.uiVersionsTREE.setAlternatingRowColors(True) self.uiVersionsTREE.setRootIsDecorated(False) self.uiVersionsTREE.setSelectionMode(self.uiVersionsTREE.NoSelection) header = self.uiVersionsTREE.header() header.setVisible(False) # create the layout layout = QVBoxLayout() layout.addWidget(self.uiVersionsTREE) layout.setContentsMargins(0, 0, 0, 0) # inherit the highlight palette palette = self.palette() palette.setColor(palette.Highlight, parent.palette().color(palette.Highlight)) self.setPalette(palette) # set dialog information self.setLayout(layout) self.setWindowFlags(Qt.Popup) self.resize(500, 250) # create connections self.uiVersionsTREE.itemClicked.connect(self.acceptItem) def closeEvent(self, event): # update all the items for this for i in range(self.uiVersionsTREE.topLevelItemCount()): item = self.uiVersionsTREE.topLevelItem(i) widget = item.versionWidget() version = widget.version() # match the active state version.setActive(widget.isActive()) super(VersionSelectDialog, self).closeEvent(event) def acceptItem(self, item): # handle version change information widget = item.versionWidget() widget.toggleActive() # accept the dialog self.close() def popup(self, versions): self.uiVersionsTREE.setUpdatesEnabled(False) self.uiVersionsTREE.blockSignals(True) self.uiVersionsTREE.clear() for version in versions: item = VersionItem(self.uiVersionsTREE, version) self.uiVersionsTREE.addTopLevelItem(item) self.uiVersionsTREE.setItemWidget(item, 0, item.versionWidget()) # reset the scrolling self.uiVersionsTREE.verticalScrollBar().setValue(0) self.uiVersionsTREE.setUpdatesEnabled(True) self.uiVersionsTREE.blockSignals(False) return self.exec_()
class AddToProject(QDialog): def __init__(self, pathProjects, parent=None): #pathProjects must be a list QDialog.__init__(self, parent) self.setWindowTitle(self.tr("Add File to Project")) self.pathSelected = '' vbox = QVBoxLayout(self) self._tree = QTreeWidget() self._tree.header().setHidden(True) self._tree.setSelectionMode(QTreeWidget.SingleSelection) self._tree.setAnimated(True) vbox.addWidget(self._tree) hbox = QHBoxLayout() btnAdd = QPushButton(self.tr("Add here!")) btnCancel = QPushButton(self.tr("Cancel")) hbox.addWidget(btnCancel) hbox.addWidget(btnAdd) vbox.addLayout(hbox) #load folders self._root = None for pathProject in pathProjects: folderStructure = file_manager.open_project(pathProject) self._load_project(folderStructure, pathProject) self.connect(btnCancel, SIGNAL("clicked()"), self.close) self.connect(btnAdd, SIGNAL("clicked()"), self._select_path) def _select_path(self): item = self._tree.currentItem() if item: self.pathSelected = unicode(item.toolTip(0)) self.close() def _load_project(self, folderStructure, folder): if not folder: return name = file_manager.get_basename(folder) item = QTreeWidgetItem(self._tree) item.setText(0, name) item.setToolTip(0, folder) item.setIcon(0, QIcon(resources.IMAGES['tree-folder'])) if folderStructure[folder][1] is not None: folderStructure[folder][1].sort() self._load_folder(folderStructure, folder, item) item.setExpanded(True) self._root = item def _load_folder(self, folderStructure, folder, parentItem): items = folderStructure[folder] if items[1] is not None: items[1].sort() for _file in items[1]: if _file.startswith('.'): continue subfolder = QTreeWidgetItem(parentItem) subfolder.setText(0, _file) subfolder.setToolTip(0, os.path.join(folder, _file)) subfolder.setIcon(0, QIcon(resources.IMAGES['tree-folder'])) self._load_folder(folderStructure, os.path.join(folder, _file), subfolder)
class StepKwMultiClassifications(WizardStep, FORM_CLASS): """InaSAFE Wizard Step Multi Classifications.""" def __init__(self, parent=None): """Constructor for the tab. :param parent: widget to use as parent (Wizard Dialog). :type parent: QWidget """ WizardStep.__init__(self, parent) self.exposures = [] self.exposure_labels = [] self.exposure_combo_boxes = [] self.exposure_edit_buttons = [] self.mode = CHOOSE_MODE self.layer_purpose = None self.layer_mode = None # Store the current representative state of the UI. # self.classifications = {} self.value_maps = {} self.thresholds = {} # Temporary attributes self.threshold_classes = OrderedDict() self.active_exposure = None self.list_unique_values = None self.tree_mapping_widget = None # GUI, good for testing self.save_button = None # Has default threshold # Trick for EQ raster for population #3853 self.use_default_thresholds = False # Index of the special case exposure classification self.special_case_index = None def is_ready_to_next_step(self): """Check if the step is complete. :returns: True if new step may be enabled. :rtype: bool """ # Still editing if self.mode == EDIT_MODE: return False for combo_box in self.exposure_combo_boxes: # Enable if there is one that has classification if combo_box.currentIndex() > 0: return True # Trick for EQ raster for population #3853 if self.use_default_thresholds: return True return False def get_next_step(self): """Find the proper step when user clicks the Next button. :returns: The step to be switched to. :rtype: WizardStep instance or None """ if self.layer_purpose != layer_purpose_aggregation: subcategory = self.parent.step_kw_subcategory.\ selected_subcategory() else: subcategory = {'key': None} if is_raster_layer(self.parent.layer): return self.parent.step_kw_source # Check if it can go to inasafe field step inasafe_fields = get_non_compulsory_fields( self.layer_purpose['key'], subcategory['key']) if not skip_inasafe_field(self.parent.layer, inasafe_fields): return self.parent.step_kw_inasafe_fields # Check if it can go to inasafe default field step default_inasafe_fields = get_fields( self.layer_purpose['key'], subcategory['key'], replace_null=True, in_group=False ) if default_inasafe_fields: return self.parent.step_kw_default_inasafe_fields # Any other case return self.parent.step_kw_source def set_wizard_step_description(self): """Set the text for description.""" subcategory = self.parent.step_kw_subcategory.selected_subcategory() field = self.parent.step_kw_field.selected_fields() is_raster = is_raster_layer(self.parent.layer) if is_raster: if self.layer_mode == layer_mode_continuous: text_label = multiple_continuous_hazard_classifications_raster else: text_label = multiple_classified_hazard_classifications_raster # noinspection PyAugmentAssignment text_label = text_label % ( subcategory['name'], self.layer_purpose['name']) else: if self.layer_mode == layer_mode_continuous: text_label = multiple_continuous_hazard_classifications_vector else: text_label = multiple_classified_hazard_classifications_vector # noinspection PyAugmentAssignment text_label = text_label % ( subcategory['name'], self.layer_purpose['name'], field) self.multi_classifications_label.setText(text_label) def setup_left_panel(self): """Setup the UI for left panel. Generate all exposure, combobox, and edit button. """ hazard = self.parent.step_kw_subcategory.selected_subcategory() left_panel_heading = QLabel(tr('Classifications')) left_panel_heading.setFont(big_font) self.left_layout.addWidget(left_panel_heading) inner_left_layout = QGridLayout() row = 0 for exposure in exposure_all: special_case = False # Filter out unsupported exposure for the hazard if exposure in hazard['disabled_exposures']: # Remove from the storage if the exposure is disabled if self.layer_mode == layer_mode_continuous: if exposure['key'] in self.thresholds: self.thresholds.pop(exposure['key']) else: if exposure['key'] in self.value_maps: self.value_maps.pop(exposure['key']) continue # Trick for EQ raster for population #3853 if exposure == exposure_population and hazard == hazard_earthquake: if is_raster_layer(self.parent.layer): if self.layer_mode == layer_mode_continuous: self.use_default_thresholds = True special_case = True # Set classification for EQ Raster for Population self.thresholds[exposure_population['key']] = { earthquake_mmi_scale['key']: { 'classes': default_classification_thresholds( earthquake_mmi_scale), 'active': True } } # Add label # Hazard on Exposure Classifications label = tr( '{hazard_name} on {exposure_name} Classifications').format( hazard_name=hazard['name'], exposure_name=exposure['name'] ) exposure_label = QLabel(label) # Add combo box exposure_combo_box = QComboBox() hazard_classifications = hazard.get('classifications') exposure_combo_box.addItem(tr('No classifications')) exposure_combo_box.setItemData( 0, None, Qt.UserRole) current_index = 0 i = 0 # Iterate through all available hazard classifications for hazard_classification in hazard_classifications: # Skip if the classification is not for the exposure if 'exposures' in hazard_classification: if exposure not in hazard_classification['exposures']: continue exposure_combo_box.addItem(hazard_classification['name']) exposure_combo_box.setItemData( i + 1, hazard_classification, Qt.UserRole) if self.layer_mode == layer_mode_continuous: current_hazard_classifications = self.thresholds.get( exposure['key']) else: current_hazard_classifications = self.value_maps.get( exposure['key']) if current_hazard_classifications: current_hazard_classification = \ current_hazard_classifications.get( hazard_classification['key']) if current_hazard_classification: is_active = current_hazard_classification.get('active') if is_active: current_index = i + 1 i += 1 # Set current classification exposure_combo_box.setCurrentIndex(current_index) # Add edit button exposure_edit_button = QPushButton(tr('Edit')) # For special case. Raster EQ on Population. if special_case: mmi_index = exposure_combo_box.findText( earthquake_mmi_scale['name']) exposure_combo_box.setCurrentIndex(mmi_index) exposure_combo_box.setEnabled(False) exposure_edit_button.setEnabled(False) tool_tip_message = tr( 'InaSAFE use default classification for Raster Earthquake ' 'hazard on population.') exposure_label.setToolTip(tool_tip_message) exposure_combo_box.setToolTip(tool_tip_message) exposure_edit_button.setToolTip(tool_tip_message) else: if current_index == 0: # Disable if there is no classification chosen. exposure_edit_button.setEnabled(False) exposure_edit_button.clicked.connect( partial(self.edit_button_clicked, edit_button=exposure_edit_button, exposure_combo_box=exposure_combo_box, exposure=exposure)) exposure_combo_box.currentIndexChanged.connect( partial( self.classifications_combo_box_changed, exposure=exposure, exposure_combo_box=exposure_combo_box, edit_button=exposure_edit_button)) # Arrange in layout inner_left_layout.addWidget(exposure_label, row, 0) inner_left_layout.addWidget(exposure_combo_box, row, 1) inner_left_layout.addWidget(exposure_edit_button, row, 2) # Adding to step's attribute self.exposures.append(exposure) self.exposure_combo_boxes.append(exposure_combo_box) self.exposure_edit_buttons.append(exposure_edit_button) self.exposure_labels.append(label) if special_case: self.special_case_index = len(self.exposures) - 1 row += 1 self.left_layout.addLayout(inner_left_layout) # To push the inner_left_layout up self.left_layout.addStretch(1) # noinspection PyUnusedLocal def edit_button_clicked(self, edit_button, exposure_combo_box, exposure): """Method to handle when an edit button is clicked. :param edit_button: The edit button. :type edit_button: QPushButton :param exposure_combo_box: The combo box of the exposure, contains list of classifications. :type exposure_combo_box: QComboBox :param exposure: Exposure definition. :type exposure: dict """ # Note(IS): Do not change the text of edit button for now until we # have better behaviour. classification = self.get_classification(exposure_combo_box) if self.mode == CHOOSE_MODE: # Change mode self.mode = EDIT_MODE # Set active exposure self.active_exposure = exposure # Disable all edit button for exposure_edit_button in self.exposure_edit_buttons: exposure_edit_button.setEnabled(False) # Except one that was clicked # edit_button.setEnabled(True) # Disable all combo box for exposure_combo_box in self.exposure_combo_boxes: exposure_combo_box.setEnabled(False) # Change the edit button to cancel # edit_button.setText(tr('Cancel')) # Clear right panel clear_layout(self.right_layout) # Show edit threshold or value mapping if self.layer_mode == layer_mode_continuous: self.setup_thresholds_panel(classification) else: self.setup_value_mapping_panels(classification) self.add_buttons(classification) elif self.mode == EDIT_MODE: # Behave the same as cancel button clicked. self.cancel_button_clicked() self.parent.pbnNext.setEnabled(self.is_ready_to_next_step()) def show_current_state(self): """Setup the UI for QTextEdit to show the current state.""" right_panel_heading = QLabel(tr('Status')) right_panel_heading.setFont(big_font) right_panel_heading.setSizePolicy( QSizePolicy.Maximum, QSizePolicy.Maximum) self.right_layout.addWidget(right_panel_heading) message = m.Message() if self.layer_mode == layer_mode_continuous: title = tr('Thresholds') else: title = tr('Value maps') message.add(m.Heading(title, **INFO_STYLE)) for i in range(len(self.exposures)): message.add(m.Text(self.exposure_labels[i])) classification = self.get_classification( self.exposure_combo_boxes[i]) if self.layer_mode == layer_mode_continuous: thresholds = self.thresholds.get(self.exposures[i]['key']) if not thresholds or not classification: message.add(m.Paragraph(tr('No classifications set.'))) continue table = m.Table( style_class='table table-condensed table-striped') header = m.Row() header.add(m.Cell(tr('Class name'))) header.add(m.Cell(tr('Minimum'))) header.add(m.Cell(tr('Maximum'))) table.add(header) classes = classification.get('classes') # Sort by value, put the lowest first classes = sorted(classes, key=lambda k: k['value']) for the_class in classes: threshold = thresholds[classification['key']]['classes'][ the_class['key']] row = m.Row() row.add(m.Cell(the_class['name'])) row.add(m.Cell(threshold[0])) row.add(m.Cell(threshold[1])) table.add(row) else: value_maps = self.value_maps.get(self.exposures[i]['key']) if not value_maps or not classification: message.add(m.Paragraph(tr('No classifications set.'))) continue table = m.Table( style_class='table table-condensed table-striped') header = m.Row() header.add(m.Cell(tr('Class name'))) header.add(m.Cell(tr('Value'))) table.add(header) classes = classification.get('classes') # Sort by value, put the lowest first classes = sorted(classes, key=lambda k: k['value']) for the_class in classes: value_map = value_maps[classification['key']][ 'classes'].get(the_class['key'], []) row = m.Row() row.add(m.Cell(the_class['name'])) row.add(m.Cell(', '.join([str(v) for v in value_map]))) table.add(row) message.add(table) # status_text_edit = QTextBrowser(None) status_text_edit = QWebView(None) status_text_edit.setSizePolicy( QSizePolicy.Ignored, QSizePolicy.Ignored) status_text_edit.page().mainFrame().setScrollBarPolicy( Qt.Horizontal, Qt.ScrollBarAlwaysOff) html_string = html_header() + message.to_html() + html_footer() status_text_edit.setHtml(html_string) self.right_layout.addWidget(status_text_edit) def set_widgets(self): """Set widgets on the Multi classification step.""" self.clear() self.layer_mode = self.parent.step_kw_layermode.selected_layermode() self.layer_purpose = self.parent.step_kw_purpose.selected_purpose() self.set_current_state() # Set the step description self.set_wizard_step_description() # Set the left panel self.setup_left_panel() # Set the right panel, for the beginning show the viewer self.show_current_state() def clear(self): """Clear current state.""" self.exposures = [] self.exposure_labels = [] self.exposure_combo_boxes = [] self.exposure_edit_buttons = [] self.mode = CHOOSE_MODE self.layer_purpose = None self.layer_mode = None self.special_case_index = None self.value_maps = {} self.thresholds = {} # Temporary attributes self.threshold_classes = OrderedDict() self.active_exposure = None self.list_unique_values = None self.tree_mapping_widget = None clear_layout(self.left_layout) clear_layout(self.right_layout) def get_current_state(self): """Obtain current classification and value map / threshold.""" def clean_state(dictionary): """Clean dictionary from bad value. :param dictionary: Dictionary of value maps or thresholds. :type dictionary: dict :returns: Clean state. :rtype: dict """ clean_dictionary = { k: v for k, v in dictionary.items() if isinstance(v, dict)} return clean_dictionary if self.layer_mode == layer_mode_continuous: output = {'thresholds': clean_state(self.thresholds)} key = 'thresholds' else: output = {'value_maps': clean_state(self.value_maps)} key = 'value_maps' # Clean non existing hazard class key empty_exposure_classifications = [] for the_exposure, the_hazard_classifications in output[key].items(): for the_hazard_classification in the_hazard_classifications.\ keys(): invalid_classifications = [] if not definition(the_hazard_classification): invalid_classifications.append( the_hazard_classification) for invalid_classification in invalid_classifications: the_hazard_classifications.pop(invalid_classification) if not the_hazard_classifications: empty_exposure_classifications.append(the_exposure) for empty_exposure_classification in empty_exposure_classifications: output[key].pop(empty_exposure_classification) return output @staticmethod def get_classification(combo_box): """Helper to obtain the classification from a combo box. :param combo_box: A classification combo box. :type combo_box: QComboBox. :returns: Classification definitions. :rtype: dict """ return combo_box.itemData(combo_box.currentIndex(), Qt.UserRole) def setup_thresholds_panel(self, classification): """Setup threshold panel in the right panel. :param classification: Classification definition. :type classification: dict """ # Set text in the label layer_purpose = self.parent.step_kw_purpose.selected_purpose() layer_subcategory = self.parent.step_kw_subcategory.\ selected_subcategory() if is_raster_layer(self.parent.layer): statistics = self.parent.layer.dataProvider().bandStatistics( 1, QgsRasterBandStats.All, self.parent.layer.extent(), 0) description_text = continuous_raster_question % ( layer_purpose['name'], layer_subcategory['name'], classification['name'], statistics.minimumValue, statistics.maximumValue) else: field_name = self.parent.step_kw_field.selected_fields() field_index = self.parent.layer.fieldNameIndex(field_name) min_value_layer = self.parent.layer.minimumValue(field_index) max_value_layer = self.parent.layer.maximumValue(field_index) description_text = continuous_vector_question % ( layer_purpose['name'], layer_subcategory['name'], field_name, classification['name'], min_value_layer, max_value_layer) # Set description description_label = QLabel(description_text) description_label.setWordWrap(True) self.right_layout.addWidget(description_label) if self.thresholds: thresholds = self.thresholds else: thresholds = self.parent.get_existing_keyword('thresholds') selected_unit = self.parent.step_kw_unit.selected_unit()['key'] self.threshold_classes = OrderedDict() classes = classification.get('classes') # Sort by value, put the lowest first classes = sorted(classes, key=lambda the_key: the_key['value']) grid_layout_thresholds = QGridLayout() for i, the_class in enumerate(classes): class_layout = QHBoxLayout() # Class label class_label = QLabel(the_class['name']) # Min label min_label = QLabel(tr('Min >')) # Min value as double spin min_value_input = QDoubleSpinBox() # TODO(IS) We can set the min and max depends on the unit, later min_value_input.setMinimum(0) min_value_input.setMaximum(999999) if thresholds.get(self.active_exposure['key']): exposure_thresholds = thresholds.get( self.active_exposure['key']) if exposure_thresholds.get(classification['key']): exposure_thresholds_classifications = exposure_thresholds\ .get(classification['key']) min_value_input.setValue( exposure_thresholds_classifications['classes'][ the_class['key']][0]) else: default_min = the_class['numeric_default_min'] if isinstance(default_min, dict): default_min = the_class[ 'numeric_default_min'][selected_unit] min_value_input.setValue(default_min) else: default_min = the_class['numeric_default_min'] if isinstance(default_min, dict): default_min = the_class[ 'numeric_default_min'][selected_unit] min_value_input.setValue(default_min) min_value_input.setSingleStep(0.1) # Max label max_label = QLabel(tr('Max <=')) # Max value as double spin max_value_input = QDoubleSpinBox() # TODO(IS) We can set the min and max depends on the unit, later max_value_input.setMinimum(0) max_value_input.setMaximum(999999) if thresholds.get(self.active_exposure['key']): exposure_thresholds = thresholds.get( self.active_exposure['key']) if exposure_thresholds.get(classification['key']): exposure_thresholds_classifications = exposure_thresholds \ .get(classification['key']) max_value_input.setValue( exposure_thresholds_classifications['classes'][ the_class['key']][1]) else: default_max = the_class['numeric_default_max'] if isinstance(default_max, dict): default_max = the_class[ 'numeric_default_max'][selected_unit] max_value_input.setValue(default_max) else: default_max = the_class['numeric_default_max'] if isinstance(default_max, dict): default_max = the_class[ 'numeric_default_max'][selected_unit] max_value_input.setValue(default_max) max_value_input.setSingleStep(0.1) # Add to class_layout class_layout.addWidget(min_label) class_layout.addWidget(min_value_input) class_layout.addWidget(max_label) class_layout.addWidget(max_value_input) class_layout.setStretch(0, 1) class_layout.setStretch(1, 2) class_layout.setStretch(2, 1) class_layout.setStretch(3, 2) # Add to grid_layout grid_layout_thresholds.addWidget(class_label, i, 0) grid_layout_thresholds.addLayout(class_layout, i, 1) self.threshold_classes[the_class['key']] = [ min_value_input, max_value_input] grid_layout_thresholds.setColumnStretch(0, 1) grid_layout_thresholds.setColumnStretch(0, 2) def min_max_changed(double_spin_index, mode): """Slot when min or max value change. :param double_spin_index: The index of the double spin. :type double_spin_index: int :param mode: The flag to indicate the min or max value. :type mode: int """ if mode == MAX_VALUE_MODE: current_max_value = self.threshold_classes.values()[ double_spin_index][1] target_min_value = self.threshold_classes.values()[ double_spin_index + 1][0] if current_max_value.value() != target_min_value.value(): target_min_value.setValue(current_max_value.value()) elif mode == MIN_VALUE_MODE: current_min_value = self.threshold_classes.values()[ double_spin_index][0] target_max_value = self.threshold_classes.values()[ double_spin_index - 1][1] if current_min_value.value() != target_max_value.value(): target_max_value.setValue(current_min_value.value()) # Set behaviour for k, v in self.threshold_classes.items(): index = self.threshold_classes.keys().index(k) if index < len(self.threshold_classes) - 1: # Max value changed v[1].valueChanged.connect(partial( min_max_changed, double_spin_index=index, mode=MAX_VALUE_MODE)) if index > 0: # Min value v[0].valueChanged.connect(partial( min_max_changed, double_spin_index=index, mode=MIN_VALUE_MODE)) grid_layout_thresholds.setSpacing(0) self.right_layout.addLayout(grid_layout_thresholds) def add_buttons(self, classification): """Helper to setup 3 buttons. :param classification: The current classification. :type classification: dict """ # Note(IS): Until we have good behaviour, we will disable load # default and cancel button. # Add 3 buttons: Load default, Cancel, Save # load_default_button = QPushButton(tr('Load Default')) # cancel_button = QPushButton(tr('Cancel')) self.save_button = QPushButton(tr('Save')) # Action for buttons # cancel_button.clicked.connect(self.cancel_button_clicked) self.save_button.clicked.connect( partial(self.save_button_clicked, classification=classification)) button_layout = QHBoxLayout() # button_layout.addWidget(load_default_button) button_layout.addStretch(1) # button_layout.addWidget(cancel_button) button_layout.addWidget(self.save_button) button_layout.setStretch(0, 3) button_layout.setStretch(1, 1) # button_layout.setStretch(2, 1) # button_layout.setStretch(3, 1) self.right_layout.addLayout(button_layout) def setup_value_mapping_panels(self, classification): """Setup value mapping panel in the right panel. :param classification: Classification definition. :type classification: dict """ # Set text in the label layer_purpose = self.parent.step_kw_purpose.selected_purpose() layer_subcategory = self.parent.step_kw_subcategory. \ selected_subcategory() if is_raster_layer(self.parent.layer): description_text = classify_raster_question % ( layer_subcategory['name'], layer_purpose['name'], classification['name']) dataset = gdal.Open(self.parent.layer.source(), GA_ReadOnly) active_band = self.parent.step_kw_band_selector.selected_band() unique_values = numpy.unique(numpy.array( dataset.GetRasterBand(active_band).ReadAsArray())) field_type = 0 # Convert datatype to a json serializable type if numpy.issubdtype(unique_values.dtype, float): unique_values = [float(i) for i in unique_values] else: unique_values = [int(i) for i in unique_values] else: field = self.parent.step_kw_field.selected_fields() field_index = self.parent.layer.dataProvider().fields(). \ indexFromName(field) field_type = self.parent.layer.dataProvider(). \ fields()[field_index].type() description_text = classify_vector_question % ( layer_subcategory['name'], layer_purpose['name'], classification['name'], field.upper()) unique_values = self.parent.layer.uniqueValues(field_index) # Set description description_label = QLabel(description_text) description_label.setWordWrap(True) self.right_layout.addWidget(description_label) self.list_unique_values = QListWidget() self.list_unique_values.setDragDropMode(QAbstractItemView.DragDrop) self.list_unique_values.setDefaultDropAction(Qt.MoveAction) self.tree_mapping_widget = QTreeWidget() self.tree_mapping_widget.setDragDropMode(QAbstractItemView.DragDrop) self.tree_mapping_widget.setDefaultDropAction(Qt.MoveAction) self.tree_mapping_widget.header().hide() self.tree_mapping_widget.itemChanged.connect( self.update_dragged_item_flags) value_mapping_layout = QHBoxLayout() value_mapping_layout.addWidget(self.list_unique_values) value_mapping_layout.addWidget(self.tree_mapping_widget) self.right_layout.addLayout(value_mapping_layout) default_classes = classification['classes'] # Assign unique values to classes (according to default) unassigned_values = list() assigned_values = dict() for default_class in default_classes: assigned_values[default_class['key']] = list() for unique_value in unique_values: if unique_value is None or isinstance( unique_value, QPyNullVariant): # Don't classify features with NULL value continue # Capitalization of the value and removing '_' (raw OSM data). value_as_string = unicode(unique_value).upper().replace('_', ' ') assigned = False for default_class in default_classes: if 'string_defaults' in default_class: condition_1 = ( field_type > 9 and value_as_string in [ c.upper() for c in default_class['string_defaults']]) else: condition_1 = False condition_2 = ( field_type < 10 and 'numeric_default_min' in default_class and 'numeric_default_max' in default_class and ( default_class['numeric_default_min'] <= unique_value < default_class['numeric_default_max'])) if condition_1 or condition_2: assigned_values[default_class['key']] += [unique_value] assigned = True if not assigned: # add to unassigned values list otherwise unassigned_values += [unique_value] self.populate_classified_values( unassigned_values, assigned_values, default_classes, self.list_unique_values, self.tree_mapping_widget ) # Current value map for exposure and classification available_classifications = self.value_maps.get( self.active_exposure['key']) if not available_classifications: return # Get active one current_classification = available_classifications.get( classification['key']) if not current_classification: return current_value_map = current_classification.get('classes') if not current_value_map: return unassigned_values = list() assigned_values = dict() for default_class in default_classes: assigned_values[default_class['key']] = list() for unique_value in unique_values: if unique_value is None or isinstance( unique_value, QPyNullVariant): # Don't classify features with NULL value continue # check in value map assigned = False for key, value_list in current_value_map.items(): if unique_value in value_list and key in assigned_values: assigned_values[key] += [unique_value] assigned = True if not assigned: unassigned_values += [unique_value] self.populate_classified_values( unassigned_values, assigned_values, default_classes, self.list_unique_values, self.tree_mapping_widget ) # noinspection PyMethodMayBeStatic def update_dragged_item_flags(self, item): """Fix the drop flag after the item is dropped. Check if it looks like an item dragged from QListWidget to QTreeWidget and disable the drop flag. For some reasons the flag is set when dragging. :param item: Item which is dragged. :type item: QTreeWidgetItem .. note:: This is a slot executed when the item change. """ if int(item.flags() & Qt.ItemIsDropEnabled) \ and int(item.flags() & Qt.ItemIsDragEnabled): item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled) @staticmethod def populate_classified_values( unassigned_values, assigned_values, default_classes, list_unique_values, tree_mapping_widget): """Populate lstUniqueValues and treeClasses.from the parameters. :param unassigned_values: List of values that haven't been assigned to a class. It will be put in list_unique_values. :type unassigned_values: list :param assigned_values: Dictionary with class as the key and list of value as the value of the dictionary. It will be put in tree_mapping_widget. :type assigned_values: dict :param default_classes: Default classes from unit. :type default_classes: list :param list_unique_values: List Widget for unique values :type list_unique_values: QListWidget :param tree_mapping_widget: Tree Widget for classifying. :type tree_mapping_widget: QTreeWidget """ # Populate the unique values list list_unique_values.clear() list_unique_values.setSelectionMode( QAbstractItemView.ExtendedSelection) for value in unassigned_values: value_as_string = value is not None and unicode(value) or 'NULL' list_item = QListWidgetItem(list_unique_values) list_item.setFlags( Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled) list_item.setData(Qt.UserRole, value) list_item.setText(value_as_string) list_unique_values.addItem(list_item) # Populate assigned values tree tree_mapping_widget.clear() bold_font = QFont() bold_font.setItalic(True) bold_font.setBold(True) bold_font.setWeight(75) tree_mapping_widget.invisibleRootItem().setFlags( Qt.ItemIsEnabled) for default_class in default_classes: # Create branch for class tree_branch = QTreeWidgetItem(tree_mapping_widget) tree_branch.setFlags( Qt.ItemIsDropEnabled | Qt.ItemIsEnabled) tree_branch.setExpanded(True) tree_branch.setFont(0, bold_font) if 'name' in default_class: default_class_name = default_class['name'] else: default_class_name = default_class['key'] tree_branch.setText(0, default_class_name) tree_branch.setData(0, Qt.UserRole, default_class['key']) if 'description' in default_class: tree_branch.setToolTip(0, default_class['description']) # Assign known values for value in assigned_values[default_class['key']]: string_value = value is not None and unicode(value) or 'NULL' tree_leaf = QTreeWidgetItem(tree_branch) tree_leaf.setFlags( Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled) tree_leaf.setData(0, Qt.UserRole, value) tree_leaf.setText(0, string_value) def cancel_button_clicked(self): """Action for cancel button clicked.""" # Change mode self.mode = CHOOSE_MODE # Enable all edit buttons and combo boxes for i in range(len(self.exposures)): if i == self.special_case_index: self.exposure_edit_buttons[i].setEnabled(False) self.exposure_combo_boxes[i].setEnabled(False) continue if self.get_classification(self.exposure_combo_boxes[i]): self.exposure_edit_buttons[i].setEnabled(True) else: self.exposure_edit_buttons[i].setEnabled(False) # self.exposure_edit_buttons[i].setText(tr('Edit')) self.exposure_combo_boxes[i].setEnabled(True) # Clear right panel clear_layout(self.right_layout) # Show current state self.show_current_state() # Unset active exposure self.active_exposure = None self.parent.pbnNext.setEnabled(self.is_ready_to_next_step()) def save_button_clicked(self, classification): """Action for save button clicked. :param classification: The classification that being edited. :type classification: dict """ # Save current edit if self.layer_mode == layer_mode_continuous: thresholds = self.get_threshold() classification_class = { 'classes': thresholds, 'active': True } if self.thresholds.get(self.active_exposure['key']): # Set other class to not active for current_classification in self.thresholds.get( self.active_exposure['key']).values(): current_classification['active'] = False else: self.thresholds[self.active_exposure['key']] = {} self.thresholds[self.active_exposure['key']][ classification['key']] = classification_class else: value_maps = self.get_value_map() classification_class = { 'classes': value_maps, 'active': True } if self.value_maps.get(self.active_exposure['key']): # Set other class to not active for current_classification in self.value_maps.get( self.active_exposure['key']).values(): current_classification['active'] = False else: self.value_maps[self.active_exposure['key']] = {} self.value_maps[self.active_exposure['key']][ classification['key']] = classification_class # Back to choose mode self.cancel_button_clicked() def get_threshold(self): """Return threshold based on current state.""" value_map = dict() for key, value in self.threshold_classes.items(): value_map[key] = [ value[0].value(), value[1].value(), ] return value_map def get_value_map(self): """Obtain the value-to-class mapping set by user. :returns: The complete mapping as a dict of lists. :rtype: dict """ value_map = {} tree_clone = self.tree_mapping_widget.invisibleRootItem().clone() for tree_branch in tree_clone.takeChildren(): value_list = [] for tree_leaf in tree_branch.takeChildren(): value_list += [tree_leaf.data(0, Qt.UserRole)] if value_list: value_map[tree_branch.data(0, Qt.UserRole)] = value_list return value_map def set_current_state(self): """"Helper to set the state of the step from current keywords.""" if not self.thresholds: self.thresholds = self.parent.get_existing_keyword('thresholds') if not self.value_maps: self.value_maps = self.parent.get_existing_keyword('value_maps') def classifications_combo_box_changed( self, index, exposure, exposure_combo_box, edit_button): """Action when classification combo box changed. :param index: The index of the combo box. :type index: int :param exposure: The exposure associated with the combo box. :type exposure: dict :param exposure_combo_box: Combo box for the classification. :type exposure_combo_box: QComboBox :param edit_button: The edit button associate with combo box. :type edit_button: QPushButton """ # Disable button if it's no classification edit_button.setEnabled(bool(index)) classification = self.get_classification(exposure_combo_box) self.activate_classification(exposure, classification) clear_layout(self.right_layout) self.show_current_state() self.parent.pbnNext.setEnabled(self.is_ready_to_next_step()) # Open edit panel directly edit_button.click() def activate_classification(self, exposure, classification=None): """Set active to True for classification for the exposure. If classification = None, all classification set active = False. :param exposure: Exposure definition. :type exposure: dict :param classification: Classification definition. :type classification: dict """ if self.layer_mode == layer_mode_continuous: selected_unit = self.parent.step_kw_unit.selected_unit()['key'] target = self.thresholds.get(exposure['key']) if target is None: self.thresholds[exposure['key']] = {} target = self.thresholds.get(exposure['key']) else: selected_unit = None target = self.value_maps.get(exposure['key']) if target is None: self.value_maps[exposure['key']] = {} target = self.value_maps.get(exposure['key']) if classification is not None: if classification['key'] not in target: if self.layer_mode == layer_mode_continuous: default_classes = default_classification_thresholds( classification, selected_unit) target[classification['key']] = { 'classes': default_classes, 'active': True } else: default_classes = default_classification_value_maps( classification) target[classification['key']] = { 'classes': default_classes, 'active': True } return for classification_key, value in target.items(): if classification is None: value['active'] = False continue if classification_key == classification['key']: value['active'] = True else: value['active'] = False @property def step_name(self): """Get the human friendly name for the wizard step. :returns: The name of the wizard step. :rtype: str """ return tr('Multi Classification Step') def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add(m.Paragraph(tr( 'In this wizard step: {step_name}, you will be able to set the ' 'classification that you will use per exposure type. You can also ' 'set the threshold or value map for each classification.' ).format(step_name=self.step_name))) return message
class DAyarlar(QDialog): def __init__(self, parent): QDialog.__init__(self, parent) self.resize(600, 375) self.gridLayout = QGridLayout(self) self.gridLayout.setMargin(0) self.gridLayout.setSpacing(0) self.treeWidget = QTreeWidget(self) self.treeWidget.setMaximumSize(200, 1500) self.virux = QTreeWidgetItem(self.treeWidget) self.virux.setExpanded(True) icon = QIcon() icon.addPixmap(QPixmap("data/logo.png"), QIcon.Normal, QIcon.On) self.virux.setIcon(0, icon) item_1 = QTreeWidgetItem(self.virux) item_1 = QTreeWidgetItem(self.virux) self.dialog = QTreeWidgetItem(self.treeWidget) self.dialog.setExpanded(True) item_1 = QTreeWidgetItem(self.dialog) item_1 = QTreeWidgetItem(self.dialog) self.treeWidget.header().setVisible(False) self.gridLayout.addWidget(self.treeWidget, 0, 0, 1, 1) self.groupBox = QGroupBox(self) self.groupBox.setFlat(True) self.gridLayout_3 = QGridLayout(self.groupBox) self.gridLayout_3.setMargin(0) self.gridLayout_3.setSpacing(0) self.widget = QWidget(self.groupBox) self.gridLayout_4 = QGridLayout(self.widget) self.gridLayout_4.setMargin(0) self.gridLayout_4.setSpacing(0) self.gridLayout_4.setMargin(0) spacerItem = QSpacerItem(300, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.gridLayout_4.addItem(spacerItem, 0, 0, 1, 1) self.gridLayout_3.addWidget(self.widget, 0, 0, 1, 1) self.gridLayout.addWidget(self.groupBox, 0, 1, 1, 1) self.pButton = QPushButton(self) self.pButton.setText("asd") self.pButton.setDefault(True) self.buttonBox = QDialogButtonBox(self) self.buttonBox.addButton(self.pButton, QDialogButtonBox.AcceptRole) #self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 2) self.setWindowTitle("Virux Ayarlar") self.treeWidget.headerItem().setText(0, "") self.treeWidget.topLevelItem(0).setText(0, u"Virux") self.treeWidget.topLevelItem(0).child(0).setText(0, u"Virux1") self.treeWidget.topLevelItem(0).child(1).setText(0, u"Virux2") self.treeWidget.topLevelItem(1).setText(0, u"Dialog") self.treeWidget.topLevelItem(1).child(0).setText(0, u"Dialog1") self.treeWidget.topLevelItem(1).child(1).setText(0, u"Dialog2") self.groupBox.setTitle(u"GroupBox") self.groupYaz() self.treeWidget.itemPressed.connect(self.lale) def lale(self, item): print item self.groupBox.setTitle(item.text(0)) def groupYaz(self): for option in DOptions: if hasattr(option, "getOption"): #self.gridLayout_3.addWidget(option.getOption(), 0, 0, 1, 1) item = QTreeWidgetItem(self.dialog) a = option.getOption() if hasattr(a, "name"): item.setText(0, a.name) else: item.setText(0, "F**k") #self.gridLayout_3.addWidget(a, 0, 0, 1, 1)
class PluginsDialog( QDialog ): " Codimension plugins dialog " def __init__( self, pluginManager, parent = None ): QDialog.__init__( self, parent ) self.setWindowTitle( "Plugin Manager" ) self.__pluginManager = pluginManager self.__configFuncs = {} # int -> callable self.__createLayout() self.__populate() self.__pluginsView.setFocus() self.__inItemChange = False return def __createLayout( self ): " Creates the dialog layout " self.resize( 640, 480 ) self.setSizeGripEnabled( True ) layout = QVBoxLayout() # Plugins list self.__pluginsView = QTreeWidget() self.__pluginsView.setAlternatingRowColors( True ) self.__pluginsView.setRootIsDecorated( False ) self.__pluginsView.setItemsExpandable( False ) self.__pluginsView.setSortingEnabled( True ) self.__pluginsView.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) self.__pluginsView.setUniformRowHeights( True ) # Alert | system/user | Enable | Name | Version self.__pluginsHeader = QTreeWidgetItem( [ "", "", "", "Name", "Version", "" ] ) self.__pluginsView.setHeaderItem( self.__pluginsHeader ) self.__pluginsView.header().setSortIndicator( NAME_COL, Qt.AscendingOrder ) self.connect( self.__pluginsView, SIGNAL( "itemSelectionChanged()" ), self.__pluginSelectionChanged ) self.connect( self.__pluginsView, SIGNAL( "itemChanged(QTreeWidgetItem*,int)" ), self.__onItemChanged ) layout.addWidget( self.__pluginsView ) # Detailed information detailsLabel = QLabel( "Detailed information" ) layout.addWidget( detailsLabel ) self.__details = QTreeWidget() self.__details.setAlternatingRowColors( False ) self.__details.setRootIsDecorated( False ) self.__details.setItemsExpandable( False ) self.__details.setSortingEnabled( False ) self.__details.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) self.__details.setUniformRowHeights( True ) detailsHeader = QTreeWidgetItem( [ "", "" ] ) self.__details.setHeaderItem( detailsHeader ) self.__details.setHeaderHidden( True ) metrics = QFontMetrics( self.__details.font() ) rect = metrics.boundingRect( "X" ) self.__details.setFixedHeight( rect.height() * 6 + 5 ) layout.addWidget( self.__details ) # Errors/warnings errorsLabel = QLabel( "Errors / warnings" ) layout.addWidget( errorsLabel ) self.__errorsText = QTextEdit() self.__errorsText.setReadOnly( True ) self.__errorsText.setAcceptRichText( False ) metrics = QFontMetrics( self.__errorsText.font() ) rect = metrics.boundingRect( "X" ) self.__errorsText.setFixedHeight( rect.height() * 4 + 5 ) layout.addWidget( self.__errorsText ) # Buttons box buttonBox = QDialogButtonBox( self ) buttonBox.setOrientation( Qt.Horizontal ) buttonBox.setStandardButtons( QDialogButtonBox.Ok ) self.__OKButton = buttonBox.button( QDialogButtonBox.Ok ) self.__OKButton.setDefault( True ) self.connect( buttonBox, SIGNAL( "accepted()" ), self.close ) self.connect( buttonBox, SIGNAL( "rejected()" ), self.close ) layout.addWidget( buttonBox ) self.setLayout( layout ) return def __createConfigButton( self ): " Creates a configure button for a plugin " button = SettingsButton() self.connect( button, SIGNAL( 'CustomClick' ), self.onPluginSettings ) return button def __populate( self ): " Populates the list with the plugins " index = 0 for category in self.__pluginManager.activePlugins: for cdmPlugin in self.__pluginManager.activePlugins[ category ]: newItem = PluginItem( self.__pluginManager, cdmPlugin, True, category ) self.__pluginsView.addTopLevelItem( newItem ) settingsButton = self.__createConfigButton() try: configFunction = cdmPlugin.getObject().getConfigFunction() if configFunction is None: settingsButton.setToolTip( "Plugin does not need configuring" ) settingsButton.setEnabled( False ) else: settingsButton.setToolTip( "Click to configure" ) settingsButton.setEnabled( True ) self.__configFuncs[ index ] = configFunction settingsButton.index = index index += 1 except Exception: settingsButton.setToolTip( "Bad plugin interface. No " "configuration function received." ) settingsButton.setEnabled( False ) self.__pluginsView.setItemWidget( newItem, SETTINGS_COL, settingsButton ) for category in self.__pluginManager.inactivePlugins: for cdmPlugin in self.__pluginManager.inactivePlugins[ category ]: newItem = PluginItem( self.__pluginManager, cdmPlugin, False, category ) self.__pluginsView.addTopLevelItem( newItem ) settingsButton = self.__createConfigButton() try: configFunction = cdmPlugin.getObject().getConfigFunction() if configFunction is None: settingsButton.setToolTip( "Plugin does not need configuring" ) settingsButton.setEnabled( False ) else: settingsButton.setToolTip( "Enable plugin and then click to configure" ) settingsButton.setEnabled( False ) self.__configFuncs[ index ] = configFunction settingsButton.index = index index += 1 except: settingsButton.setToolTip( "Bad plugin interface. No " "configuration function received." ) settingsButton.setEnabled( False ) self.__pluginsView.setItemWidget( newItem, SETTINGS_COL, settingsButton ) for cdmPlugin in self.__pluginManager.unknownPlugins: newItem = PluginItem( self.__pluginManager, cdmPlugin, False, None ) self.__pluginsView.addTopLevelItem( newItem ) settingsButton = self.__createConfigButton() settingsButton.setToolTip( "Unknown plugins are not configurable" ) settingsButton.setEnabled( False ) self.__pluginsView.setItemWidget( newItem, SETTINGS_COL, settingsButton ) self.__sortPlugins() self.__resizePlugins() return def __sortPlugins( self ): " Sorts the plugins table " self.__pluginsView.sortItems( self.__pluginsView.sortColumn(), self.__pluginsView.header().sortIndicatorOrder() ) return def __resizePlugins( self ): " Resizes the plugins table " self.__pluginsView.header().setStretchLastSection( False ) self.__pluginsView.header().resizeSections( QHeaderView.ResizeToContents ) self.__pluginsView.header().resizeSection( STATE_COL, 28 ) self.__pluginsView.header().setResizeMode( STATE_COL, QHeaderView.Fixed ) self.__pluginsView.header().resizeSection( CONFLICT_COL, 28 ) self.__pluginsView.header().setResizeMode( CONFLICT_COL, QHeaderView.Fixed ) self.__pluginsView.header().resizeSection( TYPE_COL, 28 ) self.__pluginsView.header().setResizeMode( TYPE_COL, QHeaderView.Fixed ) self.__pluginsView.header().setResizeMode( VERSION_COL, QHeaderView.Stretch ) self.__pluginsView.header().resizeSection( SETTINGS_COL, 24 ) self.__pluginsView.header().setResizeMode( SETTINGS_COL, QHeaderView.Fixed ) return def __pluginSelectionChanged( self ): " Triggered when an item is selected " selected = list( self.__pluginsView.selectedItems() ) if selected: self.__updateDetails( selected[ 0 ] ) else: self.__updateDetails( None ) return def __updateDetails( self, item ): " Updates the content of the details and the error boxes " self.__details.clear() self.__errorsText.setText( "" ) if item is None: return self.__details.addTopLevelItem( QTreeWidgetItem( [ "Author", item.plugin.getAuthor() ] ) ) self.__details.addTopLevelItem( QTreeWidgetItem( [ "Path", os.path.normpath( item.plugin.getPath() ) ] ) ) self.__details.addTopLevelItem( QTreeWidgetItem( [ "Description", item.plugin.getDescription() ] ) ) self.__details.addTopLevelItem( QTreeWidgetItem( [ "Web site", item.plugin.getWebsite() ] ) ) copyright = item.plugin.getCopyright() if copyright is not None: if copyright.lower() != "unknown": self.__details.addTopLevelItem( QTreeWidgetItem( [ "Copyright", copyright ] ) ) for name in item.plugin.getDetails(): value = item.plugin.getDetails()[ name ] self.__details.addTopLevelItem( QTreeWidgetItem( [ name, value ] ) ) self.__errorsText.setText( item.plugin.conflictMessage ) return def __onItemChanged( self, item, column ): " Triggered when an item is changed " if self.__inItemChange: return if item.active: self.__inItemChange = True item.plugin.disable() item.active = False settingsButton = self.__pluginsView.itemWidget( item, SETTINGS_COL ) settingsButton.setEnabled( False ) if settingsButton.index != -1: settingsButton.setToolTip( "Enable plugin and then click to configure" ) if item.category in self.__pluginManager.inactivePlugins: self.__pluginManager.inactivePlugins[ item.category ].append( item.plugin ) else: self.__pluginManager.inactivePlugins[ item.category ] = [ item.plugin ] self.__pluginManager.activePlugins[ item.category ].remove( item.plugin ) self.__pluginManager.saveDisabledPlugins() self.__inItemChange = False self.__pluginManager.sendPluginDeactivated( item.plugin ) return self.__inItemChange = True message = self.__pluginManager.checkConflict( item.plugin ) if message is not None: item.setCheckState( STATE_COL, Qt.Unchecked ) self.__errorsText.setText( message ) self.__inItemChange = False return try: item.plugin.enable() item.active = True if item.category in self.__pluginManager.activePlugins: self.__pluginManager.activePlugins[ item.category ].append( item.plugin ) else: self.__pluginManager.activePlugins[ item.category ] = [ item.plugin ] self.__pluginManager.inactivePlugins[ item.category ].remove( item.plugin ) self.__pluginManager.saveDisabledPlugins() self.__errorsText.setText( "" ) item.setIcon( CONFLICT_COL, PixmapCache().getIcon( 'empty.png' ) ) item.setToolTip( CONFLICT_COL, "" ) settingsButton = self.__pluginsView.itemWidget( item, SETTINGS_COL ) if settingsButton.index != -1: settingsButton.setToolTip( "Click to configure" ) settingsButton.setEnabled( True ) self.__pluginManager.sendPluginActivated( item.plugin ) except: item.setCheckState( STATE_COL, Qt.Unchecked ) self.__errorsText.setText( "Error activating the plugin - exception is generated" ) self.__inItemChange = False return def onPluginSettings( self, index ): " Triggered when a configuring function is called " if index not in self.__configFuncs: return try: self.__configFuncs[ index ]() except Exception, exc: logging.error( "Error calling the plugin configuration function. " "Message: " + str( exc ) ) return
class OWGenExpress(widget.OWWidget): name = "GenExpress" description = "Expression data from GenExpress." icon = "../widgets/icons/GenCloud.svg" priority = 36 inputs = [] outputs = [("Data", Orange.data.Table)] username = settings.Setting("anonymous") password = settings.Setting("") log2 = settings.Setting(False) transpose = settings.Setting(False) rtypei = settings.Setting(0) projecti = settings.Setting(0) serveri = settings.Setting(0) exnamei = settings.Setting(6) excludeconstant = settings.Setting(False) joinreplicates = settings.Setting(False) currentSelection = settings.Setting(None) experimentsHeaderState = settings.Setting({ name: False for _, name in HEADER[:ID_INDEX + 1]} ) storedSortOrder = settings.Setting([]) storedSelections = settings.Setting([]) def __init__(self, parent=None): super().__init__(parent) self.servers = [ ('https://dictyexpress.research.bcm.edu/', 'dictyExpress'), ('https://cloud.genialis.com/', 'Genialis'), ] self.selectedExperiments = [] self.buffer = dicty.CacheSQLite(bufferfile) self.searchString = "" self.items = [] self.result_types = [] self.controlArea.setMaximumWidth(250) self.controlArea.setMinimumWidth(250) box = gui.widgetBox(self.controlArea, 'Project') self.projectCB = gui.comboBox( box, self, "projecti", items=[], callback=self.ProjectChosen) self.projects = [] b = gui.widgetBox(self.controlArea, "Selection bookmarks") self.selectionSetsWidget = SelectionSetsWidget(self) self.selectionSetsWidget.setSizePolicy( QSizePolicy.Preferred, QSizePolicy.Maximum) def store_selections(modified): if not modified: self.storedSelections = self.selectionSetsWidget.selections self.selectionSetsWidget.selectionModified.connect(store_selections) b.layout().addWidget(self.selectionSetsWidget) gui.separator(self.controlArea) b = gui.widgetBox(self.controlArea, "Sort output columns") self.columnsSortingWidget = SortedListWidget(self) self.columnsSortingWidget.setSizePolicy( QSizePolicy.Preferred, QSizePolicy.Maximum) box = gui.widgetBox(self.controlArea, 'Experiment name') self.experimentNameCB = gui.comboBox( box, self, "exnamei", items=SORTING_MODEL_LIST) b.layout().addWidget(self.columnsSortingWidget) sorting_model = QStringListModel(SORTING_MODEL_LIST) self.columnsSortingWidget.setModel(sorting_model) self.columnsSortingWidget.sortingOrder = self.storedSortOrder def store_sort_order(): self.storedSortOrder = self.columnsSortingWidget.sortingOrder self.columnsSortingWidget.sortingOrderChanged.connect(store_sort_order) gui.separator(self.controlArea) box = gui.widgetBox(self.controlArea, 'Expression Type') self.expressionTypesCB = gui.comboBox( box, self, "rtypei", items=[], callback=self.UpdateResultsList) gui.checkBox(self.controlArea, self, "excludeconstant", "Exclude labels with constant values") gui.checkBox(self.controlArea, self, "joinreplicates", "Average replicates (use median)") gui.checkBox(self.controlArea, self, "log2", "Logarithmic (base 2) transformation") gui.checkBox(self.controlArea, self, "transpose", "Genes as attributes") self.commit_button = gui.button(self.controlArea, self, "&Commit", callback=self.Commit) self.commit_button.setDisabled(True) gui.rubber(self.controlArea) box = gui.widgetBox(self.controlArea, 'Server') gui.comboBox(box, self, "serveri", items=[title for url, title in self.servers], callback=self.ServerChosen) gui.lineEdit(box, self, "username", "Username:"******"password", "Password:"******"Clear cache", callback=self.clear_cache) gui.lineEdit(self.mainArea, self, "searchString", "Search", callbackOnType=True, callback=self.SearchUpdate) self.headerLabels = [t[1] for t in HEADER] self.experimentsWidget = QTreeWidget() self.experimentsWidget.setHeaderLabels(self.headerLabels) self.experimentsWidget.setSelectionMode(QTreeWidget.ExtendedSelection) self.experimentsWidget.setRootIsDecorated(False) self.experimentsWidget.setSortingEnabled(True) contextEventFilter = gui.VisibleHeaderSectionContextEventFilter( self.experimentsWidget, self.experimentsWidget) self.experimentsWidget.header().installEventFilter(contextEventFilter) self.experimentsWidget.setItemDelegateForColumn( 0, gui.IndicatorItemDelegate(self, role=Qt.DisplayRole)) self.experimentsWidget.setAlternatingRowColors(True) self.experimentsWidget.selectionModel().selectionChanged.connect( self.onSelectionChanged) self.selectionSetsWidget.setSelectionModel( self.experimentsWidget.selectionModel()) self.selectionSetsWidget.setSelections(self.storedSelections) self.mainArea.layout().addWidget(self.experimentsWidget) self.restoreHeaderState() self.experimentsWidget.header().geometriesChanged.connect( self.saveHeaderState) self.dbc = None self.AuthSet() QTimer.singleShot(100, self.ConnectAndUpdate) def sizeHint(self): return QSize(800, 600) def AuthSet(self): if len(self.username): self.passf.setDisabled(False) else: self.passf.setDisabled(True) def AuthChanged(self): self.AuthSet() self.ConnectAndUpdate() def ConnectAndUpdate(self): self.Connect() if self.dbc: def get_data_count(project_id): # XXX: is there a better way? # Note: limit 0 would return all objects return self.dbc.gen.api.data.get(case_ids__contains=project_id, type__startswith='data:expression:', limit=1)['meta']['total_count'] self.projects = sorted([p for p in self.dbc.projects().items() if get_data_count(p[0]) > 0], key=lambda x: x[1]) self.UpdateProjects() self.ProjectChosen() self.UpdateExperimentTypes() def Connect(self): self.error(1) self.warning(1) username = '******' password = '******' url = self.servers[self.serveri][0] if self.username: username = self.username password = self.password if username.lower() in ['*****@*****.**', 'anonymous']: username = '******' password = '******' self.dbc = None self.projects = [] self.result_types = [] try: self.dbc = Genesis( address=url, username=username, password=password, cache=self.buffer) except requests.exceptions.ConnectionError: self.dbc = Genesis( address=url, username=username, password=password, connect=False, cache=self.buffer) self.warning(1, "Could not connect to server, working from cache.") except Exception: self.error(1, "Wrong username or password.") self.UpdateProjects() self.UpdateExperimentTypes() # clear lists def Reload(self): self.UpdateExperiments(reload=True) def clear_cache(self): self.buffer.clear() self.Reload() def rtype(self): """Return selected result template type """ if self.result_types: return self.result_types[self.rtypei] else: return None def UpdateExperimentTypes(self): self.expressionTypesCB.clear() items = [self.result_types_labels[desc] for desc in self.result_types] self.expressionTypesCB.addItems(items) #do not update anything if the list is empty if len(self.result_types): self.rtypei = max(0, min(self.rtypei, len(self.result_types) - 1)) def UpdateProjects(self): self.projectCB.clear() items = [desc for pid, desc in self.projects] self.projectCB.addItems(items) #do not update anything if the list if empty if len(self.projects) > 0: self.projecti = max(0, min(self.projecti, len(self.projects) - 1)) def UpdateExperiments(self, reload=False): self.experimentsWidget.clear() if not self.dbc or not self.dbc.projectid: # the connection did not succeed return self.items = [] self.progressBarInit() result_types = [] result_types_labels = [] sucind = False # success indicator for database index try: result_types, result_types_labels = self.dbc.result_types(reload=reload) sucind = True except Exception: try: result_types, result_types_labels = self.dbc.result_types() self.warning(0, "Can not access database - using cached data.") sucind = True except Exception: self.error(0, "Can not access database.") if sucind: self.warning(0) self.error(0) self.result_types = result_types self.result_types_labels = result_types_labels self.UpdateExperimentTypes() self.UpdateResultsList(reload=reload) self.progressBarFinished() if self.currentSelection: self.currentSelection.select(self.experimentsWidget.selectionModel()) self.handle_commit_button() def ProjectChosen(self, reload=False): if self.projects: self.dbc.projectid = self.projects[self.projecti][0] else: self.dbc.projectid = None self.UpdateExperiments(reload=reload) def ServerChosen(self): self.ConnectAndUpdate() def UpdateResultsList(self, reload=False): results_list = self.dbc.results_list(self.rtype(), reload=reload) try: results_list = self.dbc.results_list(self.rtype(), reload=reload) except Exception: try: results_list = self.dbc.results_list(self.rtype()) except Exception: self.error(0, "Can not access database.") self.results_list = results_list #softly change the view so that the selection stays the same items_shown = {} for i, item in enumerate(self.items): c = str(item.text(ID_INDEX)) items_shown[c] = i items_to_show = set(id_ for id_ in self.results_list) add_items = set(items_to_show) - set(items_shown) delete_items = set(items_shown) - set(items_to_show) i = 0 while i < self.experimentsWidget.topLevelItemCount(): it = self.experimentsWidget.topLevelItem(i) if str(it.text(ID_INDEX)) in delete_items: self.experimentsWidget.takeTopLevelItem(i) else: i += 1 delete_ind = set([items_shown[i] for i in delete_items]) self.items = [it for i, it in enumerate(self.items) if i not in delete_ind] for r_annot in add_items: d = defaultdict(lambda: "?", self.results_list[r_annot]) row_items = [""] + [to_text(d.get(key, "?")) for key, _ in HEADER[1:]] row_items[ID_INDEX] = r_annot ci = MyTreeWidgetItem(self.experimentsWidget, row_items) self.items.append(ci) for i in range(len(self.headerLabels)): self.experimentsWidget.resizeColumnToContents(i) self.wantbufver = lambda x: self.results_list[x]["date_modified"] self.UpdateCached() def UpdateCached(self): if self.wantbufver and self.dbc: for item in self.items: id = str(item.text(ID_INDEX)) version = self.dbc._in_buffer(id + "|||" + self.rtype()) value = " " if version == self.wantbufver(id) else "" item.setData(0, Qt.DisplayRole, value) def SearchUpdate(self, string=""): for item in self.items: item.setHidden( not all(s in item for s in self.searchString.split())) def Commit(self): pb = gui.ProgressBar(self, iterations=100) table = None ids = [] for item in self.experimentsWidget.selectedItems(): unique_id = str(item.text(ID_INDEX)) ids.append(unique_id) transfn = None if self.log2: transfn = lambda x: math.log(x + 1.0, 2) reverse_header_dict = {name: name for key, name in HEADER} reverse_header_dict["ID"] = "id" allowed_labels = None def namefn(a): name = SORTING_MODEL_LIST[self.exnamei] name = reverse_header_dict.get(name, "id") return dict(a)[name] if len(ids): table = self.dbc.get_data( ids=ids, result_type=self.rtype(), callback=pb.advance, exclude_constant_labels=self.excludeconstant, bufver=self.wantbufver, transform=transfn, allowed_labels=allowed_labels, namefn=namefn) if self.joinreplicates: table = dicty.join_replicates(table, ignorenames=self.dbc.IGNORE_REPLICATE, namefn="name", avg=dicty.median, fnshow=lambda x: " | ".join(map(str, x))) # Sort attributes sortOrder = self.columnsSortingWidget.sortingOrder all_values = defaultdict(set) for at in table.domain.attributes: atts = at.attributes for name in sortOrder: all_values[name].add(atts.get(reverse_header_dict[name], "")) isnum = {} for at, vals in all_values.items(): vals = filter(None, vals) try: for a in vals: float(a) isnum[at] = True except ValueError: isnum[at] = False def optfloat(x, at): if x == "": return "" else: return float(x) if isnum[at] else x def sorting_key(attr): atts = attr.attributes return tuple([optfloat(atts.get(reverse_header_dict[name], ""), name) for name in sortOrder]) attributes = sorted(table.domain.attributes, key=sorting_key) domain = Orange.data.Domain( attributes, table.domain.class_vars, table.domain.metas) table = Orange.data.Table.from_table(domain, table) table = Orange.data.Table(domain, table) if self.transpose: experiments = [at for at in table.domain.variables] attr = [compat.ContinuousVariable.make(ex['DDB'].value) for ex in table] metavars = sorted(table.domain.variables[0].attributes.keys()) metavars = [compat.StringVariable.make(name) for name in metavars] domain = compat.create_domain(attr, None, metavars) metavars = compat.get_metas(domain) metas = [[exp.attributes[var.name] for var in metavars] for exp in experiments] table = compat.create_table(domain, table.X.transpose(), None, metas) data_hints.set_hint(table, "taxid", "352472") data_hints.set_hint(table, "genesinrows", False) self.send("Data", table) self.UpdateCached() pb.finish() def onSelectionChanged(self, selected, deselected): self.handle_commit_button() def handle_commit_button(self): self.currentSelection = \ SelectionByKey(self.experimentsWidget.selectionModel().selection(), key=(ID_INDEX,)) self.commit_button.setDisabled(not len(self.currentSelection)) def saveHeaderState(self): hview = self.experimentsWidget.header() for i, label in enumerate(self.headerLabels): self.experimentsHeaderState[label] = hview.isSectionHidden(i) def restoreHeaderState(self): hview = self.experimentsWidget.header() state = self.experimentsHeaderState for i, label in enumerate(self.headerLabels): hview.setSectionHidden(i, state.get(label, True)) self.experimentsWidget.resizeColumnToContents(i)
def __addSimilarity(self, similarity, titleText): " Adds a similarity " # Label title = QLabel(titleText) title.setFont(self.__headerFont) self.__vLayout.addWidget(title) self.__widgets.append(title) # List of files simTable = QTreeWidget(self.bodyWidget) simTable.setAlternatingRowColors(True) simTable.setRootIsDecorated(False) simTable.setItemsExpandable(False) simTable.setSortingEnabled(False) simTable.setItemDelegate(NoOutlineHeightDelegate(4)) simTable.setUniformRowHeights(True) simTable.itemActivated.connect(self.__similarityActivated) simTable.setHeaderLabels(["File name", "Line"]) for item in similarity.files: values = [item[0], str(item[1])] simTable.addTopLevelItem(QTreeWidgetItem(values)) # Resizing simTable.header().resizeSections(QHeaderView.ResizeToContents) simTable.header().setStretchLastSection(True) # Height self.__setTableHeight(simTable) self.__vLayout.addWidget(simTable) self.__widgets.append(simTable) # The fragment itself if len(similarity.fragment) > 10: # Take first 9 lines text = "\n".join(similarity.fragment[:9]) + "\n ..." toolTip = "\n".join(similarity.fragment) else: text = "\n".join(similarity.fragment) toolTip = "" fragmentLabel = QLabel("<pre>" + self.__htmlEncode(text) + "</pre>") if toolTip != "": fragmentLabel.setToolTip("<pre>" + self.__htmlEncode(toolTip) + "</pre>") palette = fragmentLabel.palette() palette.setColor(QPalette.Background, QColor(250, 250, 175)) palette.setColor(QPalette.Foreground, QColor(0, 0, 0)) fragmentLabel.setPalette(palette) fragmentLabel.setFrameShape(QFrame.StyledPanel) fragmentLabel.setAutoFillBackground(True) labelFont = fragmentLabel.font() labelFont.setFamily(GlobalData().skin.baseMonoFontFace) fragmentLabel.setFont(labelFont) self.__vLayout.addWidget(fragmentLabel) self.__widgets.append(fragmentLabel) return
class SVNPluginLogDialog( QDialog ): " SVN plugin log dialog " NODIFF = '<html><body bgcolor="#ffffe6"></body></html>' def __init__( self, plugin, client, path, logInfo, parent = None ): QDialog.__init__( self, parent ) self.__plugin = plugin self.__client = client self.__path = path self.__logInfo = logInfo self.__lhsSelected = None self.__rhsSelected = None self.__createLayout() self.setWindowTitle( "SVN Log" ) lastIndex = len( self.__logInfo ) - 1 index = 0 for log in self.__logInfo: newItem = LogItem( log ) self.__logView.addTopLevelItem( newItem ) if index != lastIndex: rev = log.revision.number nextRev = self.__logInfo[ index + 1 ].revision.number diffButton = self.__createDiffButton( log.revision, self.__logInfo[ index + 1 ].revision ) if rev is not None and nextRev is not None: diffButton.setToolTip( "Click to see diff to the older revision (r." + str( rev ) + " to r." + str( nextRev ) + ")" ) else: diffButton.setEnabled( False ) diffButton.setToolTip( "Could not determine current or previous revision" ) else: diffButton = self.__createDiffButton( None, None ) diffButton.setEnabled( False ) diffButton.setToolTip( "Diff to previous revision is not avalable for the first revision" ) self.__logView.setItemWidget( newItem, DIFFTONEXT_COL, diffButton ) index += 1 self.__resizeLogView() self.__sortLogView() self.__logView.setFocus() return def __createDiffButton( self, rev, prevRev ): " Creates a diff button for a path " button = DiffButton() button.rev = rev button.prevRev = prevRev self.connect( button, SIGNAL( 'CustomClick' ), self.onDiffBetween ) return button def __resizeLogView( self ): " Resizes the plugins table " self.__logView.header().setStretchLastSection( True ) self.__logView.header().resizeSections( QHeaderView.ResizeToContents ) self.__logView.header().resizeSection( SELECT_COL, 28 ) self.__logView.header().setResizeMode( SELECT_COL, QHeaderView.Fixed ) self.__logView.header().resizeSection( DIFFTONEXT_COL, 24 ) self.__logView.header().setResizeMode( DIFFTONEXT_COL, QHeaderView.Fixed ) return def __sortLogView( self ): " Sorts the log table " self.__logView.sortItems( self.__logView.sortColumn(), self.__logView.header().sortIndicatorOrder() ) return def __createLayout( self ): " Creates the dialog layout " self.resize( 640, 480 ) self.setSizeGripEnabled( True ) vboxLayout = QVBoxLayout( self ) # Revisions to compare compareGroupbox = QGroupBox( self ) compareGroupbox.setTitle( "Revisions to compare" ) sizePolicy = QSizePolicy( QSizePolicy.Expanding, QSizePolicy.Preferred ) sizePolicy.setHorizontalStretch( 0 ) sizePolicy.setVerticalStretch( 0 ) sizePolicy.setHeightForWidth( compareGroupbox.sizePolicy().hasHeightForWidth() ) compareGroupbox.setSizePolicy( sizePolicy ) revisionLayout = QHBoxLayout( compareGroupbox ) self.__lhsRevisionLabel = QLabel() self.__lhsRevisionLabel.setFrameStyle( QFrame.StyledPanel ) self.__lhsResetButton = QToolButton() self.__lhsResetButton.setIcon( PixmapCache().getIcon( pluginHomeDir + 'svnclearrev.png' ) ) self.__lhsResetButton.setFocusPolicy( Qt.NoFocus ) self.__lhsResetButton.setEnabled( False ) self.__lhsResetButton.setToolTip( "Reset revision to compare" ) self.__lhsResetButton.clicked.connect( self.__onLHSReset ) self.__rhsRevisionLabel = QLabel() self.__rhsRevisionLabel.setFrameStyle( QFrame.StyledPanel ) self.__rhsResetButton = QToolButton() self.__rhsResetButton.setIcon( PixmapCache().getIcon( pluginHomeDir + 'svnclearrev.png' ) ) self.__rhsResetButton.setFocusPolicy( Qt.NoFocus ) self.__rhsResetButton.setEnabled( False ) self.__rhsResetButton.setToolTip( "Reset revision to compare" ) self.__rhsResetButton.clicked.connect( self.__onRHSReset ) lhsLayout = QHBoxLayout() lhsLayout.addWidget( self.__lhsRevisionLabel ) lhsLayout.addWidget( self.__lhsResetButton ) rhsLayout = QHBoxLayout() rhsLayout.addWidget( self.__rhsRevisionLabel ) rhsLayout.addWidget( self.__rhsResetButton ) bothLayout = QVBoxLayout() bothLayout.addLayout( lhsLayout ) bothLayout.addLayout( rhsLayout ) revisionLayout.addLayout( bothLayout ) self.__diffButton = QToolButton() self.__diffButton.setText( "Diff" ) self.__diffButton.setFocusPolicy( Qt.NoFocus ) self.__diffButton.setEnabled( False ) self.__diffButton.clicked.connect( self.__onDiff ) revisionLayout.addWidget( self.__diffButton ) vboxLayout.addWidget( compareGroupbox ) # Log table logHeaderFrame = QFrame() logHeaderFrame.setFrameStyle( QFrame.StyledPanel ) logHeaderFrame.setAutoFillBackground( True ) self.__setLightPalette( logHeaderFrame ) logHeaderFrame.setFixedHeight( 24 ) logHeaderLayout = QHBoxLayout() logHeaderLayout.setContentsMargins( 3, 0, 0, 0 ) logHeaderLayout.addWidget( QLabel( "Subversion log of " + self.__path ) ) logHeaderFrame.setLayout( logHeaderLayout ) vboxLayout.addWidget( logHeaderFrame ) self.__logView = QTreeWidget() self.__logView.setAlternatingRowColors( True ) self.__logView.setRootIsDecorated( False ) self.__logView.setItemsExpandable( False ) self.__logView.setSortingEnabled( True ) self.__logView.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) self.__logViewHeader = QTreeWidgetItem( [ "", "", "Revision", "Date", "Author", "Message" ] ) self.__logView.setHeaderItem( self.__logViewHeader ) self.__logView.header().setSortIndicator( REVISION_COL, Qt.AscendingOrder ) self.__logView.itemChanged.connect( self.__onLogViewChanged ) vboxLayout.addWidget( self.__logView ) # Diff part diffHeaderFrame = QFrame() diffHeaderFrame.setFrameStyle( QFrame.StyledPanel ) diffHeaderFrame.setAutoFillBackground( True ) self.__setLightPalette( diffHeaderFrame ) diffHeaderFrame.setFixedHeight( 24 ) diffLabel = QLabel( "Diff" ) diffExpandingSpacer = QSpacerItem( 10, 10, QSizePolicy.Expanding ) self.__showHideDiffButton = QToolButton() self.__showHideDiffButton.setAutoRaise( True ) self.__showHideDiffButton.setIcon( PixmapCache().getIcon( 'less.png' ) ) self.__showHideDiffButton.setFixedSize( 20, 20 ) self.__showHideDiffButton.setToolTip( "Show diff" ) self.__showHideDiffButton.setFocusPolicy( Qt.NoFocus ) self.__showHideDiffButton.clicked.connect( self.__onShowHideDiff ) diffLayout = QHBoxLayout() diffLayout.setContentsMargins( 3, 0, 0, 0 ) diffLayout.addWidget( diffLabel ) diffLayout.addSpacerItem( diffExpandingSpacer ) diffLayout.addWidget( self.__showHideDiffButton ) diffHeaderFrame.setLayout( diffLayout ) self.__diffViewer = DiffTabWidget() self.__diffViewer.setHTML( self.NODIFF ) self.__diffViewer.setVisible( False ) vboxLayout.addWidget( diffHeaderFrame ) vboxLayout.addWidget( self.__diffViewer ) # Buttons at the bottom buttonBox = QDialogButtonBox( self ) buttonBox.setOrientation( Qt.Horizontal ) buttonBox.setStandardButtons( QDialogButtonBox.Ok ) buttonBox.button( QDialogButtonBox.Ok ).setDefault( True ) buttonBox.accepted.connect( self.close ) vboxLayout.addWidget( buttonBox ) return @staticmethod def __setLightPalette( frame ): " Creates a lighter paletter for the widget background " palette = frame.palette() background = palette.color( QPalette.Background ) background.setRgb( min( background.red() + 30, 255 ), min( background.green() + 30, 255 ), min( background.blue() + 30, 255 ) ) palette.setColor( QPalette.Background, background ) frame.setPalette( palette ) return def __onShowHideDiff( self ): " On/off the diff section " if self.__diffViewer.isVisible(): self.__diffViewer.setVisible( False ) self.__showHideDiffButton.setIcon( PixmapCache().getIcon( 'less.png' ) ) self.__showHideDiffButton.setToolTip( "Show diff" ) else: self.__diffViewer.setVisible( True ) self.__showHideDiffButton.setIcon( PixmapCache().getIcon( 'more.png' ) ) self.__showHideDiffButton.setToolTip( "Hide diff" ) return def onDiffBetween( self, rev, prevRev ): " Called when diff is requested between revisions " if not rev or not prevRev: return QApplication.setOverrideCursor( QCursor( Qt.WaitCursor ) ) try: lhsContent = self.__client.cat( self.__path, prevRev ) rhsContent = self.__client.cat( self.__path, rev ) except Exception, exc: QApplication.restoreOverrideCursor() logging.error( str( exc ) ) return except:
class SVNPluginStatusDialog( QDialog ): " SVN Plugin status dialog " def __init__( self, statusList, parent = None ): QDialog.__init__( self, parent ) # Split statuses paths = [] ignoredPaths = [] for status in statusList: if status[ 1 ] == IND_IGNORED: ignoredPaths.append( status ) else: paths.append( status ) self.__createLayout( paths, ignoredPaths ) self.setWindowTitle( "SVN status" ) # Fill the lists for item in paths: message = "" if item[ 2 ]: message = item[ 2 ] newItem = QTreeWidgetItem( [ "", item[ 0 ], STATUS[ item[ 1 ] ], message ] ) pixmap = getIndicatorPixmap( item[ 1 ] ) if pixmap: newItem.setIcon( 0, QIcon( pixmap ) ) newItem.setToolTip( 1, item[ 0 ] ) newItem.setToolTip( 2, STATUS[ item[ 1 ] ] ) if message: newItem.setToolTip( 3, message ) self.__pathView.addTopLevelItem( newItem ) self.__pathView.header().resizeSections( QHeaderView.ResizeToContents ) self.__pathView.header().resizeSection( 0, 20 ) self.__pathView.header().setResizeMode( QHeaderView.Fixed ) for item in ignoredPaths: newItem = QTreeWidgetItem( [ item[ 0 ], STATUS[ item[ 1 ] ] ] ) newItem.setToolTip( 0, item[ 0 ] ) newItem.setToolTip( 1, STATUS[ item[ 1 ] ] ) self.__ignoredPathView.addTopLevelItem( newItem ) self.__ignoredPathView.header().resizeSections( QHeaderView.ResizeToContents ) return def __createLayout( self, paths, ignoredPaths ): " Creates the dialog layout " self.resize( 640, 420 ) self.setSizeGripEnabled( True ) vboxLayout = QVBoxLayout( self ) # Paths to commit part vboxLayout.addWidget( QLabel( "Paths (total: " + str( len( paths ) ) + ")" ) ) self.__pathView = QTreeWidget() self.__pathView.setAlternatingRowColors( True ) self.__pathView.setRootIsDecorated( False ) self.__pathView.setItemsExpandable( False ) self.__pathView.setSortingEnabled( True ) self.__pathView.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) self.__pathView.setUniformRowHeights( True ) self.__pathHeader = QTreeWidgetItem( [ "", "Path", "Status", "Message" ] ) self.__pathView.setHeaderItem( self.__pathHeader ) self.__pathView.header().setSortIndicator( 1, Qt.AscendingOrder ) vboxLayout.addWidget( self.__pathView ) # Paths to ignore part vboxLayout.addWidget( QLabel( "Ignored paths (total: " + str( len( ignoredPaths ) ) + ")" ) ) self.__ignoredPathView = QTreeWidget() self.__ignoredPathView.setAlternatingRowColors( True ) self.__ignoredPathView.setRootIsDecorated( False ) self.__ignoredPathView.setItemsExpandable( False ) self.__ignoredPathView.setSortingEnabled( True ) self.__ignoredPathView.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) self.__ignoredPathView.setUniformRowHeights( True ) pathToIgnoreHeader = QTreeWidgetItem( [ "Path", "Status" ] ) self.__ignoredPathView.setHeaderItem( pathToIgnoreHeader ) self.__ignoredPathView.header().setSortIndicator( 0, Qt.AscendingOrder ) vboxLayout.addWidget( self.__ignoredPathView ) # Buttons at the bottom buttonBox = QDialogButtonBox( self ) buttonBox.setOrientation( Qt.Horizontal ) buttonBox.setStandardButtons( QDialogButtonBox.Ok ) buttonBox.button( QDialogButtonBox.Ok ).setDefault( True ) buttonBox.accepted.connect( self.accept ) vboxLayout.addWidget( buttonBox ) return
class OWPIPAx(widget.OWWidget): name = "PIPAx" description = "Access data from PIPA RNA-Seq database." icon = "../widgets/icons/PIPA.svg" priority = 35 inputs = [] outputs = [("Data", Orange.data.Table)] username = settings.Setting("") password = settings.Setting("") log2 = settings.Setting(False) rtypei = settings.Setting(5) # hardcoded rpkm mapability polya excludeconstant = settings.Setting(False) joinreplicates = settings.Setting(False) #: The stored current selection (in experiments view) #: SelectionByKey | None currentSelection = settings.Setting(None) #: Stored selections (presets) #: list of SelectionByKey storedSelections = settings.Setting([]) #: Stored column sort keys (from Sort view) #: list of strings storedSortingOrder = settings.Setting( ["Strain", "Experiment", "Genotype", "Timepoint"]) experimentsHeaderState = settings.Setting( {name: False for _, name in HEADER[:ID_INDEX + 1]} ) def __init__(self, parent=None, signalManager=None, name="PIPAx"): super().__init__(parent) self.selectedExperiments = [] self.buffer = dicty.CacheSQLite(bufferfile) self.searchString = "" self.result_types = [] self.mappings = {} self.controlArea.setMaximumWidth(250) self.controlArea.setMinimumWidth(250) gui.button(self.controlArea, self, "Reload", callback=self.Reload) gui.button(self.controlArea, self, "Clear cache", callback=self.clear_cache) b = gui.widgetBox(self.controlArea, "Experiment Sets") self.selectionSetsWidget = SelectionSetsWidget(self) self.selectionSetsWidget.setSizePolicy( QSizePolicy.Preferred, QSizePolicy.Maximum) def store_selections(modified): if not modified: self.storedSelections = self.selectionSetsWidget.selections self.selectionSetsWidget.selectionModified.connect(store_selections) b.layout().addWidget(self.selectionSetsWidget) gui.separator(self.controlArea) b = gui.widgetBox(self.controlArea, "Sort output columns") self.columnsSortingWidget = SortedListWidget(self) self.columnsSortingWidget.setSizePolicy( QSizePolicy.Preferred, QSizePolicy.Maximum) def store_sort_order(): self.storedSortingOrder = self.columnsSortingWidget.sortingOrder self.columnsSortingWidget.sortingOrderChanged.connect(store_sort_order) b.layout().addWidget(self.columnsSortingWidget) sorting_model = QStringListModel(SORTING_MODEL_LIST) self.columnsSortingWidget.setModel(sorting_model) gui.separator(self.controlArea) box = gui.widgetBox(self.controlArea, 'Expression Type') self.expressionTypesCB = gui.comboBox( box, self, "rtypei", items=[], callback=self.UpdateResultsList) gui.checkBox(self.controlArea, self, "excludeconstant", "Exclude labels with constant values") gui.checkBox(self.controlArea, self, "joinreplicates", "Average replicates (use median)") gui.checkBox(self.controlArea, self, "log2", "Logarithmic (base 2) transformation") self.commit_button = gui.button(self.controlArea, self, "&Commit", callback=self.Commit) self.commit_button.setDisabled(True) gui.rubber(self.controlArea) box = gui.widgetBox(self.controlArea, "Authentication") gui.lineEdit(box, self, "username", "Username:"******"password", "Password:"******"searchString", "Search", callbackOnType=True, callback=self.SearchUpdate) self.headerLabels = [t[1] for t in HEADER] self.experimentsWidget = QTreeWidget() self.experimentsWidget.setHeaderLabels(self.headerLabels) self.experimentsWidget.setSelectionMode(QTreeWidget.ExtendedSelection) self.experimentsWidget.setRootIsDecorated(False) self.experimentsWidget.setSortingEnabled(True) contextEventFilter = gui.VisibleHeaderSectionContextEventFilter( self.experimentsWidget, self.experimentsWidget ) self.experimentsWidget.header().installEventFilter(contextEventFilter) self.experimentsWidget.setItemDelegateForColumn( 0, gui.IndicatorItemDelegate(self, role=Qt.DisplayRole)) self.experimentsWidget.setAlternatingRowColors(True) self.experimentsWidget.selectionModel().selectionChanged.connect( self.onSelectionChanged) self.selectionSetsWidget.setSelectionModel( self.experimentsWidget.selectionModel() ) self.mainArea.layout().addWidget(self.experimentsWidget) # Restore the selection states from the stored settings self.selectionSetsWidget.selections = self.storedSelections self.columnsSortingWidget.sortingOrder = self.storedSortingOrder self.restoreHeaderState() self.experimentsWidget.header().geometriesChanged.connect( self.saveHeaderState) self.dbc = None self.AuthSet() QTimer.singleShot(100, self.UpdateExperiments) def sizeHint(self): return QSize(800, 600) def AuthSet(self): if len(self.username): self.passf.setDisabled(False) else: self.passf.setDisabled(True) def AuthChanged(self): self.AuthSet() self.ConnectAndUpdate() def ConnectAndUpdate(self): self.Connect() self.UpdateExperiments(reload=True) def Connect(self): self.error(1) self.warning(1) def en(x): return x if len(x) else None self.dbc = dicty.PIPAx(cache=self.buffer, username=en(self.username), password=self.password) # check password if en(self.username) != None: try: self.dbc.mappings(reload=True) except dicty.AuthenticationError: self.error(1, "Wrong username or password") self.dbc = None except Exception as ex: print("Error when contacting the PIPA database", ex) sys.excepthook(*sys.exc_info()) try: # maybe cached? self.dbc.mappings() self.warning(1, "Can not access database - using cached data.") except Exception as ex: self.dbc = None self.error(1, "Can not access database.") def Reload(self): self.UpdateExperiments(reload=True) def clear_cache(self): self.buffer.clear() self.Reload() def rtype(self): """Return selected result template type """ if self.result_types: return self.result_types[self.rtypei][0] else: return "-1" def UpdateExperimentTypes(self): self.expressionTypesCB.clear() items = [desc for _, desc in self.result_types] self.expressionTypesCB.addItems(items) self.rtypei = max(0, min(self.rtypei, len(self.result_types) - 1)) def UpdateExperiments(self, reload=False): self.experimentsWidget.clear() self.items = [] self.progressBarInit() if not self.dbc: self.Connect() mappings = {} result_types = [] sucind = False # success indicator for database index try: mappings = self.dbc.mappings(reload=reload) result_types = self.dbc.result_types(reload=reload) sucind = True except Exception as ex: try: mappings = self.dbc.mappings() result_types = self.dbc.result_types() self.warning(0, "Can not access database - using cached data.") sucind = True except Exception as ex: self.error(0, "Can not access database.") if sucind: self.warning(0) self.error(0) self.mappings = mappings self.result_types = result_types self.UpdateExperimentTypes() self.UpdateResultsList(reload=reload) self.progressBarFinished() if self.currentSelection: self.currentSelection.select( self.experimentsWidget.selectionModel()) self.handle_commit_button() def UpdateResultsList(self, reload=False): results_list = {} try: results_list = self.dbc.results_list(self.rtype(), reload=reload) except Exception as ex: try: results_list = self.dbc.results_list(self.rtype()) except Exception as ex: self.error(0, "Can not access database.") self.results_list = results_list mappings_key_dict = dict(((m["data_id"], m["id"]), key) \ for key, m in self.mappings.items()) def mapping_unique_id(annot): """Map annotations dict from results_list to unique `mappings` ids. """ data_id, mappings_id = annot["data_id"], annot["mappings_id"] return mappings_key_dict[data_id, mappings_id] elements = [] # softly change the view so that the selection stays the same items_shown = {} for i, item in enumerate(self.items): c = str(item.text(10)) items_shown[c] = i items_to_show = dict((mapping_unique_id(annot), annot) for annot in self.results_list.values()) add_items = set(items_to_show) - set(items_shown) delete_items = set(items_shown) - set(items_to_show) i = 0 while i < self.experimentsWidget.topLevelItemCount(): it = self.experimentsWidget.topLevelItem(i) if str(it.text(10)) in delete_items: self.experimentsWidget.takeTopLevelItem(i) else: i += 1 delete_ind = set([items_shown[i] for i in delete_items]) self.items = [it for i, it in enumerate(self.items) if i not in delete_ind] for r_annot in [items_to_show[i] for i in add_items]: d = defaultdict(lambda: "?", r_annot) row_items = [""] + [d.get(key, "?") for key, _ in HEADER[1:]] try: time_dict = literal_eval(row_items[DATE_INDEX]) date_rna = date(time_dict["fullYearUTC"], time_dict["monthUTC"] + 1, # Why is month 0 based? time_dict["dateUTC"]) row_items[DATE_INDEX] = date_rna.strftime("%x") except Exception: row_items[DATE_INDEX] = '' row_items[ID_INDEX] = mapping_unique_id(r_annot) elements.append(row_items) ci = MyTreeWidgetItem(self.experimentsWidget, row_items) self.items.append(ci) for i in range(len(self.headerLabels)): self.experimentsWidget.resizeColumnToContents(i) # which is the ok buffer version # FIXME: what attribute to use for version? self.wantbufver = \ lambda x, ad=self.results_list: \ defaultdict(lambda: "?", ad[x])["date"] self.wantbufver = lambda x: "0" self.UpdateCached() def UpdateCached(self): if self.wantbufver and self.dbc: fn = self.dbc.download_key_function() result_id_key = dict(((m["data_id"], m["mappings_id"]), key) \ for key, m in self.results_list.items()) for item in self.items: c = str(item.text(10)) mapping = self.mappings[c] data_id, mappings_id = mapping["data_id"], mapping["id"] r_id = result_id_key[data_id, mappings_id] # Get the buffered version buffered = self.dbc.inBuffer(fn(r_id)) value = " " if buffered == self.wantbufver(r_id) else "" item.setData(0, Qt.DisplayRole, value) def SearchUpdate(self, string=""): for item in self.items: item.setHidden(not all(s in item \ for s in self.searchString.split()) ) def Commit(self): if not self.dbc: self.Connect() pb = gui.ProgressBar(self, iterations=100) table = None ids = [] for item in self.experimentsWidget.selectedItems(): unique_id = str(item.text(10)) annots = self.mappings[unique_id] ids.append((annots["data_id"], annots["id"])) transfn = None if self.log2: transfn = lambda x: math.log(x + 1.0, 2) reverse_header_dict = dict((name, key) for key, name in HEADER) hview = self.experimentsWidget.header() shownHeaders = [label for i, label in \ list(enumerate(self.headerLabels))[1:] \ if not hview.isSectionHidden(i) ] allowed_labels = [reverse_header_dict.get(label, label) \ for label in shownHeaders] if self.joinreplicates and "id" not in allowed_labels: # need 'id' labels in join_replicates for attribute names allowed_labels.append("id") if len(ids): table = self.dbc.get_data(ids=ids, result_type=self.rtype(), callback=pb.advance, exclude_constant_labels=self.excludeconstant, # bufver=self.wantbufver, transform=transfn, allowed_labels=allowed_labels) if self.joinreplicates: table = dicty.join_replicates(table, ignorenames=["replicate", "data_id", "mappings_id", "data_name", "id", "unique_id"], namefn=None, avg=dicty.median ) # Sort attributes sortOrder = self.columnsSortingWidget.sortingOrder all_values = defaultdict(set) for at in table.domain.attributes: atts = at.attributes for name in sortOrder: all_values[name].add(atts.get(reverse_header_dict[name], "")) isnum = {} for at, vals in all_values.items(): vals = filter(None, vals) try: for a in vals: float(a) isnum[at] = True except: isnum[at] = False def optfloat(x, at): if x == "": return "" else: return float(x) if isnum[at] else x def sorting_key(attr): atts = attr.attributes return tuple([optfloat(atts.get(reverse_header_dict[name], ""), name) \ for name in sortOrder]) attributes = sorted(table.domain.attributes, key=sorting_key) domain = Orange.data.Domain( attributes, table.domain.class_var, table.domain.metas) table = table.from_table(domain, table) data_hints.set_hint(table, "taxid", "352472") data_hints.set_hint(table, "genesinrows", False) self.send("Data", table) self.UpdateCached() pb.finish() def onSelectionChanged(self, selected, deselected): self.handle_commit_button() def handle_commit_button(self): self.currentSelection = \ SelectionByKey(self.experimentsWidget.selectionModel().selection(), key=(1, 2, 3, 10)) self.commit_button.setDisabled(not len(self.currentSelection)) def saveHeaderState(self): hview = self.experimentsWidget.header() for i, label in enumerate(self.headerLabels): self.experimentsHeaderState[label] = hview.isSectionHidden(i) def restoreHeaderState(self): hview = self.experimentsWidget.header() state = self.experimentsHeaderState for i, label in enumerate(self.headerLabels): hview.setSectionHidden(i, state.get(label, True)) self.experimentsWidget.resizeColumnToContents(i)
class SVNPluginPropsDialog(QDialog): " SVN plugin properties dialog " def __init__(self, plugin, client, path, parent=None): QDialog.__init__(self, parent) self.__plugin = plugin self.__client = client self.__path = path self.__createLayout() self.setWindowTitle("SVN Properties of " + path) self.__populate() self.__propsView.setFocus() return def __populate(self): " Populate the properties list " # Get the currently selected name selectedName = None selected = list(self.__propsView.selectedItems()) if selected: selectedName = str(selected[0].text(0)) self.__propsView.clear() properties = readProperties(self.__client, self.__path) if properties: for itemPath, itemProps in properties: if self.__path == itemPath or \ self.__path == itemPath + os.path.sep: for name, value in itemProps.iteritems(): name = str(name).strip() value = str(value).strip() newItem = QTreeWidgetItem([name, value]) self.__propsView.addTopLevelItem(newItem) self.__resizePropsView() self.__sortPropsView() if selectedName: index = 0 for index in xrange(0, self.__propsView.topLevelItemCount()): item = self.__propsView.topLevelItem(index) if selectedName == item.text(0): item.setSelected(True) return def __resizePropsView(self): " Resizes the properties table " self.__propsView.header().setStretchLastSection(True) self.__propsView.header().resizeSections(QHeaderView.ResizeToContents) return def __sortPropsView(self): " Sorts the properties table " self.__propsView.sortItems( self.__propsView.sortColumn(), self.__propsView.header().sortIndicatorOrder()) return def __createLayout(self): " Creates the dialog layout " self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) hLayout = QHBoxLayout() self.__propsView = QTreeWidget() self.__propsView.setAlternatingRowColors(True) self.__propsView.setRootIsDecorated(False) self.__propsView.setItemsExpandable(False) self.__propsView.setSortingEnabled(True) self.__propsView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__propsView.itemSelectionChanged.connect( self.__propsSelectionChanged) propsViewHeader = QTreeWidgetItem(["Property Name", "Property Value"]) self.__propsView.setHeaderItem(propsViewHeader) self.__propsView.header().setSortIndicator(0, Qt.DescendingOrder) hLayout.addWidget(self.__propsView) self.__delButton = QToolButton() self.__delButton.setText("Delete") self.__delButton.setFocusPolicy(Qt.NoFocus) self.__delButton.setEnabled(False) self.__delButton.clicked.connect(self.__onDel) hLayout.addWidget(self.__delButton, 0, Qt.AlignBottom) vboxLayout.addLayout(hLayout) # Set property part setGroupbox = QGroupBox(self) setGroupbox.setTitle("Set Property") setLayout = QGridLayout(setGroupbox) setLayout.addWidget(QLabel("Name"), 0, 0, Qt.AlignTop | Qt.AlignRight) setLayout.addWidget(QLabel("Value"), 1, 0, Qt.AlignTop | Qt.AlignRight) self.__nameEdit = QLineEdit() self.__nameEdit.textChanged.connect(self.__nameChanged) setLayout.addWidget(self.__nameEdit, 0, 1) self.__valueEdit = QTextEdit() self.__valueEdit.setAcceptRichText(False) self.__valueEdit.textChanged.connect(self.__valueChanged) metrics = QFontMetrics(self.__valueEdit.font()) rect = metrics.boundingRect("X") self.__valueEdit.setFixedHeight(rect.height() * 4 + 5) setLayout.addWidget(self.__valueEdit, 1, 1) self.__setButton = QToolButton() self.__setButton.setText("Set") self.__setButton.setFocusPolicy(Qt.NoFocus) self.__setButton.setEnabled(False) self.__setButton.clicked.connect(self.__onSet) setLayout.addWidget(self.__setButton, 1, 2, Qt.AlignBottom | Qt.AlignHCenter) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( setGroupbox.sizePolicy().hasHeightForWidth()) setGroupbox.setSizePolicy(sizePolicy) vboxLayout.addWidget(setGroupbox) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) buttonBox.button(QDialogButtonBox.Ok).setDefault(True) buttonBox.accepted.connect(self.close) vboxLayout.addWidget(buttonBox) return def __onSet(self): " Triggered when propery set is clicked " name = self.__nameEdit.text().strip() value = self.__valueEdit.toPlainText().strip() try: commitInfo = self.__client.propset(name, value, self.__path) if commitInfo: logging.info(str(commitInfo)) self.__populate() self.__plugin.notifyPathChanged(self.__path) self.__nameEdit.clear() self.__valueEdit.clear() self.__propsView.setFocus() except pysvn.ClientError, exc: message = exc.args[0] logging.error(message) return except Exception, exc: logging.error(str(exc)) return
class AddToProject(QDialog): def __init__(self, pathProjects, parent=None): #pathProjects must be a list QDialog.__init__(self, parent) self.setWindowTitle(self.tr("Add File to Project")) self.pathSelected = '' vbox = QVBoxLayout(self) self._tree = QTreeWidget() self._tree.header().setHidden(True) self._tree.setSelectionMode(QTreeWidget.SingleSelection) self._tree.setAnimated(True) vbox.addWidget(self._tree) hbox = QHBoxLayout() btnAdd = QPushButton(self.tr("Add here!")) btnCancel = QPushButton(self.tr("Cancel")) hbox.addWidget(btnCancel) hbox.addWidget(btnAdd) vbox.addLayout(hbox) #load folders self._root = None self._loading_items = {} self.loading_projects(pathProjects) self._thread_execution = ThreadExecution(self._thread_load_projects, args=[pathProjects]) self.connect(self._thread_execution, SIGNAL("finished()"), self._callback_load_project) self._thread_execution.start() self.connect(btnCancel, SIGNAL("clicked()"), self.close) self.connect(btnAdd, SIGNAL("clicked()"), self._select_path) def loading_projects(self, projects): for project in projects: loadingItem = LoadingItem() item = loadingItem.add_item_to_tree(project, self._tree, parent=self) self._loading_items[project] = item def _thread_load_projects(self, projects): structures = [] for pathProject in projects: folderStructure = file_manager.open_project(pathProject) structures.append((folderStructure, pathProject)) self._thread_execution.storage_values = structures def _callback_load_project(self): structures = self._thread_execution.storage_values for structure, path in structures: item = self._loading_items.pop(path, None) if item is not None: index = self._tree.indexOfTopLevelItem(item) self._tree.takeTopLevelItem(index) self._load_project(structure, path) def _select_path(self): item = self._tree.currentItem() if item: self.pathSelected = item.toolTip(0) self.close() def _load_project(self, folderStructure, folder): if not folder: return name = file_manager.get_basename(folder) item = QTreeWidgetItem(self._tree) item.setText(0, name) item.setToolTip(0, folder) item.setIcon(0, QIcon(resources.IMAGES['tree-folder'])) if folderStructure[folder][1] is not None: folderStructure[folder][1].sort() self._load_folder(folderStructure, folder, item) item.setExpanded(True) self._root = item def _load_folder(self, folderStructure, folder, parentItem): items = folderStructure[folder] if items[1] is not None: items[1].sort() for _file in items[1]: if _file.startswith('.'): continue subfolder = QTreeWidgetItem(parentItem) subfolder.setText(0, _file) subfolder.setToolTip(0, os.path.join(folder, _file)) subfolder.setIcon(0, QIcon(resources.IMAGES['tree-folder'])) self._load_folder(folderStructure, os.path.join(folder, _file), subfolder)
class OWItemsets(widget.OWWidget): name = 'Frequent Itemsets' description = 'Explore sets of items that frequently appear together.' icon = 'icons/FrequentItemsets.svg' priority = 10 inputs = [("Data", Table, 'set_data')] outputs = [(Output.DATA, Table)] minSupport = settings.Setting(30) maxItemsets = settings.Setting(10000) filterSearch = settings.Setting(True) autoFind = settings.Setting(False) autoSend = settings.Setting(True) filterKeywords = settings.Setting('') filterMinItems = settings.Setting(1) filterMaxItems = settings.Setting(10000) UserAdviceMessages = [ widget.Message('Itemset are listed in item-sorted order, i.e. ' 'an itemset containing A and B is only listed once, as ' 'A > B (and not also B > A).', 'itemsets-order', widget.Message.Warning), widget.Message('To select all the itemsets that are descendants of ' '(include) some item X (i.e. the whole subtree), you ' 'can fold the subtree at that item and then select it.', 'itemsets-order', widget.Message.Information) ] def __init__(self): self.tree = QTreeWidget(self.mainArea, columnCount=2, allColumnsShowFocus=True, alternatingRowColors=True, selectionMode=QTreeWidget.ExtendedSelection, uniformRowHeights=True) self.tree.setHeaderLabels(["Itemsets", "Support", "%"]) self.tree.header().setStretchLastSection(True) self.tree.itemSelectionChanged.connect(self.selectionChanged) self.mainArea.layout().addWidget(self.tree) box = gui.widgetBox(self.controlArea, "Info") self.nItemsets = self.nSelectedExamples = self.nSelectedItemsets = '' gui.label(box, self, "Number of itemsets: %(nItemsets)s") gui.label(box, self, "Selected itemsets: %(nSelectedItemsets)s") gui.label(box, self, "Selected examples: %(nSelectedExamples)s") hbox = gui.widgetBox(box, orientation='horizontal') gui.button(hbox, self, "Expand all", callback=self.tree.expandAll) gui.button(hbox, self, "Collapse all", callback=self.tree.collapseAll) box = gui.widgetBox(self.controlArea, 'Find itemsets') gui.hSlider(box, self, 'minSupport', minValue=1, maxValue=100, label='Minimal support:', labelFormat="%d%%", callback=lambda: self.find_itemsets()) gui.hSlider(box, self, 'maxItemsets', minValue=10000, maxValue=100000, step=10000, label='Max. number of itemsets:', labelFormat="%d", callback=lambda: self.find_itemsets()) gui.checkBox(box, self, 'filterSearch', label='Apply below filters in search', tooltip='If checked, the itemsets are filtered according ' 'to below filter conditions already in the search ' 'phase. \nIf unchecked, the only filters applied ' 'during search are the ones above, ' 'and the itemsets are \nfiltered afterwards only for ' 'display, i.e. only the matching itemsets are shown.') self.button = gui.auto_commit( box, self, 'autoFind', 'Find itemsets', commit=self.find_itemsets) box = gui.widgetBox(self.controlArea, 'Filter itemsets') gui.lineEdit(box, self, 'filterKeywords', 'Contains:', callback=self.filter_change, orientation='horizontal', tooltip='A comma or space-separated list of regular ' 'expressions.') hbox = gui.widgetBox(box, orientation='horizontal') gui.spin(hbox, self, 'filterMinItems', 1, 998, label='Min. items:', callback=self.filter_change) gui.spin(hbox, self, 'filterMaxItems', 2, 999, label='Max. items:', callback=self.filter_change) gui.rubber(hbox) gui.rubber(self.controlArea) gui.auto_commit(self.controlArea, self, 'autoSend', 'Send selection') self.filter_change() def sendReport(self): self.reportSettings("Itemset statistics", [("Number of itemsets", self.nItemsets), ("Selected itemsets", self.nSelectedItemsets), ("Covered examples", self.nSelectedExamples), ]) self.reportSection("Itemsets") self.reportRaw(OWReport.reportTree(self.tree)) ITEM_DATA_ROLE = Qt.UserRole + 1 def selectionChanged(self): X = self.data.X mapping = self.onehot_mapping instances = set() where = np.where def whole_subtree(node): yield node for i in range(node.childCount()): yield from whole_subtree(node.child(i)) def itemset(node): while node: yield node.data(0, self.ITEM_DATA_ROLE) node = node.parent() def selection_ranges(node): n_children = node.childCount() if n_children: yield (self.tree.indexFromItem(node.child(0)), self.tree.indexFromItem(node.child(n_children - 1))) for i in range(n_children): yield from selection_ranges(node.child(i)) nSelectedItemsets = 0 item_selection = QItemSelection() for node in self.tree.selectedItems(): nodes = (node,) if node.isExpanded() else whole_subtree(node) if not node.isExpanded(): for srange in selection_ranges(node): item_selection.select(*srange) for node in nodes: nSelectedItemsets += 1 cols, vals = zip(*(mapping[i] for i in itemset(node))) instances.update(where((X[:, cols] == vals).all(axis=1))[0]) self.tree.itemSelectionChanged.disconnect(self.selectionChanged) self.tree.selectionModel().select(item_selection, QItemSelectionModel.Select | QItemSelectionModel.Rows) self.tree.itemSelectionChanged.connect(self.selectionChanged) self.nSelectedExamples = len(instances) self.nSelectedItemsets = nSelectedItemsets self.output = self.data[sorted(instances)] or None self.commit() def commit(self): self.send(Output.DATA, self.output) def filter_change(self): isRegexMatch = self.isRegexMatch = re.compile( '|'.join(i.strip() for i in re.split('(,|\s)+', self.filterKeywords.strip()) if i.strip())).search def hide(node, depth, has_kw): if not has_kw: has_kw = isRegexMatch(node.text(0)) hidden = (sum(hide(node.child(i), depth + 1, has_kw) for i in range(node.childCount())) == node.childCount() if node.childCount() else (not has_kw or not self.filterMinItems <= depth <= self.filterMaxItems)) node.setHidden(hidden) return hidden hide(self.tree.invisibleRootItem(), 0, False) class TreeWidgetItem(QTreeWidgetItem): def data(self, column, role): """Construct lazy tooltips""" if role != Qt.ToolTipRole: return super().data(column, role) tooltip = [] while self: tooltip.append(self.text(0)) self = self.parent() return ' '.join(reversed(tooltip)) def find_itemsets(self): if self.data is None: return data = self.data self.tree.clear() self.tree.setUpdatesEnabled(False) self.tree.blockSignals(True) class ItemDict(dict): def __init__(self, item): self.item = item top = ItemDict(self.tree.invisibleRootItem()) X, mapping = OneHot.encode(data) self.onehot_mapping = mapping names = {item: '{}={}'.format(var.name, val) for item, var, val in OneHot.decode(mapping.keys(), data, mapping)} nItemsets = 0 filterSearch = self.filterSearch filterMinItems, filterMaxItems = self.filterMinItems, self.filterMaxItems isRegexMatch = self.isRegexMatch # Find itemsets and populate the TreeView progress = gui.ProgressBar(self, self.maxItemsets + 1) for itemset, support in frequent_itemsets(X, self.minSupport / 100): if filterSearch and not filterMinItems <= len(itemset) <= filterMaxItems: continue parent = top first_new_item = None itemset_matches_filter = False for item in sorted(itemset): name = names[item] if filterSearch and not itemset_matches_filter: itemset_matches_filter = isRegexMatch(name) child = parent.get(name) if child is None: wi = self.TreeWidgetItem(parent.item, [name, str(support), '{:.1f}'.format(100 * support / len(data))]) wi.setData(0, self.ITEM_DATA_ROLE, item) child = parent[name] = ItemDict(wi) if first_new_item is None: first_new_item = (parent, name) parent = child if filterSearch and not itemset_matches_filter: parent, name = first_new_item parent.item.removeChild(parent[name].item) del parent[name].item del parent[name] else: nItemsets += 1 progress.advance() if nItemsets >= self.maxItemsets: break if not filterSearch: self.filter_change() self.nItemsets = nItemsets self.nSelectedItemsets = 0 self.nSelectedExamples = 0 self.tree.expandAll() for i in range(self.tree.columnCount()): self.tree.resizeColumnToContents(i) self.tree.setUpdatesEnabled(True) self.tree.blockSignals(False) progress.finish() def set_data(self, data): self.data = data if data is not None: self.warning(0, 'Data has continuous attributes which will be skipped.' if data.domain.has_continuous_attributes() else None) self.error(1, 'Discrete features required but data has none.' if not data.domain.has_discrete_attributes() else None) self.button.setDisabled(not data.domain.has_discrete_attributes()) if self.autoFind: self.find_itemsets()
def __init__(self, callback): super().__init__() self.callback = callback self.setMinimumSize(QSize(210, 200)) self.setMaximumSize(QSize(210, 16777215)) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) self.lockresource = False numbervalidator = QIntValidator(0, 999) #Rom info and emulator emulator = QPushButton("Start Emulator", self) #Map/bank select buttons column_left_layout = QVBoxLayout(self) column_left_layout.setContentsMargins(0, 0, 0, 0) column_left_layout.setSpacing(2) mapinput_l = QLabel('Map:', self) mapinput_f = QLineEdit(self) mapinput_f.setValidator(numbervalidator) bankinput_l = QLabel('Bank:', self) bankinput_f = QLineEdit(self) bankinput_f.setValidator(numbervalidator) button_load = QPushButton(self) button_load.setText("Load scripts") #Select element on the map view select_script = QTreeWidget(self) select_script.setColumnCount(2) select_script.setHeaderHidden(True) select_script.header().resizeSection(0, 160) select_script.header().resizeSection(1, 20) select_script.setStyleSheet("outline: 0;") select_script.setFocusPolicy(Qt.NoFocus) select_script.setSelectionMode(QAbstractItemView.ExtendedSelection) resources_l = QLabel("Script resources:", self) resourceselector = QListWidget(self) resourceselector.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) column_left_layout.addWidget(emulator) column_left_layout.addWidget(bankinput_l) column_left_layout.addWidget(bankinput_f) column_left_layout.addWidget(mapinput_l) column_left_layout.addWidget(mapinput_f) column_left_layout.addWidget(button_load) column_left_layout.addWidget(select_script) column_left_layout.addWidget(resources_l) column_left_layout.addWidget(resourceselector) #Finally connect proper signals button_load.clicked.connect(self.maploadclick) select_script.itemSelectionChanged.connect(self.itemselected) resourceselector.itemSelectionChanged.connect(self.resourceselected) emulator.clicked.connect(self.emulate) #Keep some elements for local thingy self.mapinput = mapinput_f self.bankinput = bankinput_f self.scriptselect = select_script self.resourceselector = resourceselector
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
class AddToProject(QDialog): def __init__(self, pathProjects, parent=None): #pathProjects must be a list QDialog.__init__(self, parent) self.setWindowTitle(self.tr("Add File to Project")) self.pathSelected = '' vbox = QVBoxLayout(self) self._tree = QTreeWidget() self._tree.header().setHidden(True) self._tree.setSelectionMode(QTreeWidget.SingleSelection) self._tree.setAnimated(True) vbox.addWidget(self._tree) hbox = QHBoxLayout() btnAdd = QPushButton(self.tr("Add here!")) btnCancel = QPushButton(self.tr("Cancel")) hbox.addWidget(btnCancel) hbox.addWidget(btnAdd) vbox.addLayout(hbox) #load folders self._root = None self._loading_items = {} self.loading_projects(pathProjects) self._thread_execution = ThreadExecution( self._thread_load_projects, args=[pathProjects]) self.connect(self._thread_execution, SIGNAL("finished()"), self._callback_load_project) self._thread_execution.start() self.connect(btnCancel, SIGNAL("clicked()"), self.close) self.connect(btnAdd, SIGNAL("clicked()"), self._select_path) def loading_projects(self, projects): for project in projects: loadingItem = LoadingItem() item = loadingItem.add_item_to_tree(project, self._tree, parent=self) self._loading_items[project] = item def _thread_load_projects(self, projects): structures = [] for pathProject in projects: folderStructure = file_manager.open_project(pathProject) structures.append((folderStructure, pathProject)) self._thread_execution.storage_values = structures def _callback_load_project(self): structures = self._thread_execution.storage_values if structures: for structure, path in structures: item = self._loading_items.pop(path, None) if item is not None: index = self._tree.indexOfTopLevelItem(item) self._tree.takeTopLevelItem(index) self._load_project(structure, path) def _select_path(self): item = self._tree.currentItem() if item: self.pathSelected = item.toolTip(0) self.close() def _load_project(self, folderStructure, folder): if not folder: return name = file_manager.get_basename(folder) item = QTreeWidgetItem(self._tree) item.setText(0, name) item.setToolTip(0, folder) item.setIcon(0, QIcon(resources.IMAGES['tree-folder'])) if folderStructure[folder][1] is not None: folderStructure[folder][1].sort() self._load_folder(folderStructure, folder, item) item.setExpanded(True) self._root = item def _load_folder(self, folderStructure, folder, parentItem): items = folderStructure[folder] if items[1] is not None: items[1].sort() for _file in items[1]: if _file.startswith('.'): continue subfolder = QTreeWidgetItem(parentItem) subfolder.setText(0, _file) subfolder.setToolTip(0, os.path.join(folder, _file)) subfolder.setIcon(0, QIcon(resources.IMAGES['tree-folder'])) self._load_folder(folderStructure, os.path.join(folder, _file), subfolder)
class PymetricsViewer(QWidget): " Pymetrics tab widget " # Limits to colorize the McCabe score LittleRiskLimit = 10 ModerateRiskLimit = 20 HighRiskLimit = 50 # Options of providing a report SingleFile = 0 DirectoryFiles = 1 ProjectFiles = 2 SingleBuffer = 3 def __init__(self, parent=None): QWidget.__init__(self, parent) self.__reportUUID = "" self.__reportFileName = "" self.__reportOption = -1 self.__reportShown = False self.__report = None # Prepare members for reuse self.__noneLabel = QLabel("\nNo results available") self.__noneLabel.setFrameShape(QFrame.StyledPanel) self.__noneLabel.setAlignment(Qt.AlignHCenter) self.__headerFont = self.__noneLabel.font() self.__headerFont.setPointSize(self.__headerFont.pointSize() + 4) self.__noneLabel.setFont(self.__headerFont) self.__noneLabel.setAutoFillBackground(True) noneLabelPalette = self.__noneLabel.palette() noneLabelPalette.setColor(QPalette.Background, GlobalData().skin.nolexerPaper) self.__noneLabel.setPalette(noneLabelPalette) self.__createLayout(parent) self.__updateButtonsStatus() return def __createLayout(self, parent): " Creates the toolbar and layout " # Buttons self.__mcCabeButton = QAction(PixmapCache().getIcon('tableview.png'), 'Switch to McCabe only table view', self) self.__mcCabeButton.setCheckable(True) self.connect(self.__mcCabeButton, SIGNAL('toggled(bool)'), self.__onMcCabe) self.printButton = QAction(PixmapCache().getIcon('printer.png'), 'Print', self) #printButton.setShortcut( 'Ctrl+' ) self.connect(self.printButton, SIGNAL('triggered()'), self.__onPrint) self.printButton.setVisible(False) self.printPreviewButton = QAction( PixmapCache().getIcon('printpreview.png'), 'Print preview', self) #printPreviewButton.setShortcut( 'Ctrl+' ) self.connect(self.printPreviewButton, SIGNAL('triggered()'), self.__onPrintPreview) self.printPreviewButton.setVisible(False) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.clearButton = QAction(PixmapCache().getIcon('trash.png'), 'Clear', self) self.connect(self.clearButton, SIGNAL('triggered()'), self.__clear) # The toolbar self.toolbar = QToolBar(self) self.toolbar.setOrientation(Qt.Vertical) self.toolbar.setMovable(False) self.toolbar.setAllowedAreas(Qt.RightToolBarArea) self.toolbar.setIconSize(QSize(16, 16)) self.toolbar.setFixedWidth(28) self.toolbar.setContentsMargins(0, 0, 0, 0) self.toolbar.addAction(self.__mcCabeButton) self.toolbar.addAction(self.printPreviewButton) self.toolbar.addAction(self.printButton) self.toolbar.addWidget(spacer) self.toolbar.addAction(self.clearButton) self.__totalResultsTree = QTreeWidget() self.__totalResultsTree.setAlternatingRowColors(True) self.__totalResultsTree.setRootIsDecorated(True) self.__totalResultsTree.setItemsExpandable(True) self.__totalResultsTree.setUniformRowHeights(True) self.__totalResultsTree.setItemDelegate(NoOutlineHeightDelegate(4)) headerLabels = ["Path / name", "Value", ""] self.__totalResultsTree.setHeaderLabels(headerLabels) self.connect(self.__totalResultsTree, SIGNAL("itemActivated(QTreeWidgetItem *, int)"), self.__allItemActivated) self.connect(self.__totalResultsTree, SIGNAL("itemExpanded(QTreeWidgetItem *)"), self.__onResultsExpanded) self.__totalResultsTree.setColumnHidden(2, True) self.__totalResultsTree.hide() self.__mcCabeTable = QTreeWidget() self.__mcCabeTable.setAlternatingRowColors(True) self.__mcCabeTable.setRootIsDecorated(False) self.__mcCabeTable.setItemsExpandable(False) self.__mcCabeTable.setSortingEnabled(True) self.__mcCabeTable.setItemDelegate(NoOutlineHeightDelegate(4)) self.__mcCabeTable.setUniformRowHeights(True) headerLabels = ["", "File name", "Object", "McCabe Complexity"] self.__mcCabeTable.setHeaderLabels(headerLabels) self.connect(self.__mcCabeTable, SIGNAL("itemActivated(QTreeWidgetItem *, int)"), self.__mcCabeActivated) self.__mcCabeTable.hide() self.__hLayout = QHBoxLayout() self.__hLayout.setContentsMargins(0, 0, 0, 0) self.__hLayout.setSpacing(0) self.__hLayout.addWidget(self.toolbar) self.__hLayout.addWidget(self.__noneLabel) self.__hLayout.addWidget(self.__totalResultsTree) self.__hLayout.addWidget(self.__mcCabeTable) self.setLayout(self.__hLayout) return def getTotalResultsWidget(self): " Provides a reference to the total results widget " return self.__totalResultsTree def getMcCabeResultsWidget(self): " Provides a reference to the McCabe results widget " return self.__mcCabeTable def __updateButtonsStatus(self): " Updates the buttons status " self.__mcCabeButton.setEnabled(self.__reportShown) self.printButton.setEnabled(self.__reportShown) self.printPreviewButton.setEnabled(self.__reportShown) self.clearButton.setEnabled(self.__reportShown) return def __onResultsExpanded(self, item): " An item has been expanded, so the column width should be adjusted " self.__totalResultsTree.header().resizeSections( QHeaderView.ResizeToContents) return def __onPrint(self): " Triggered when the print button is pressed " pass def __onPrintPreview(self): " triggered when the print preview button is pressed " pass def __onMcCabe(self, state): " Triggered when the metrics view is switched " if not self.__reportShown: return if state: self.__totalResultsTree.hide() self.__mcCabeTable.show() self.__mcCabeButton.setIcon(PixmapCache().getIcon('treeview.png')) self.__mcCabeButton.setToolTip("Switch to complete " "results tree view") else: self.__mcCabeTable.hide() self.__totalResultsTree.show() self.__mcCabeButton.setIcon(PixmapCache().getIcon('tableview.png')) self.__mcCabeButton.setToolTip("Switch to McCabe only table view") return def setFocus(self): " Overridden setFocus " self.__hLayout.setFocus() return def __clear(self): " Clears the content of the vertical layout " if not self.__reportShown: return self.__totalResultsTree.clear() self.__totalResultsTree.hide() self.__mcCabeTable.clear() self.__mcCabeTable.hide() self.__noneLabel.show() self.__report = None self.__reportShown = False self.__updateButtonsStatus() # self.resizeEvent() self.__mcCabeButton.setIcon(PixmapCache().getIcon('tableview.png')) self.__mcCabeButton.setToolTip("Switch to McCabe only table view") self.__mcCabeButton.setChecked(False) self.__updateTooltip() return def __updateTooltip(self): " Generates a signal with appropriate string message " if not self.__reportShown: tooltip = "No metrics available" elif self.__reportOption == self.DirectoryFiles: tooltip = "Metrics generated for directory: " + \ self.__reportFileName elif self.__reportOption == self.ProjectFiles: tooltip = "Metrics generated for the whole project" elif self.__reportOption == self.SingleFile: tooltip = "Metrics generated for file: " + self.__reportFileName elif self.__reportOption == self.SingleBuffer: tooltip = "Metrics generated for unsaved file: " + \ self.__reportFileName else: tooltip = "" self.emit(SIGNAL('updatePymetricsTooltip'), tooltip) return @staticmethod def __shouldShowFileName(table, column): " Checks if the file name is the same " size = table.topLevelItemCount() if size == 0: return False index = size - 1 firstName = table.topLevelItem(index).text(column) index -= 1 while index >= 0: if table.topLevelItem(index).text(column) != firstName: return True index -= 1 return False def showReport(self, metrics, reportOption, fileName, uuid): " Shows the pymetrics results " self.__clear() self.__noneLabel.hide() self.__report = metrics self.__reportUUID = uuid self.__reportFileName = fileName self.__reportOption = reportOption if len(metrics.report) > 1: accumulatedBasic = self.__accumulateBasicMetrics() accItem = QTreeWidgetItem(["Cumulative basic metrics"]) self.__totalResultsTree.addTopLevelItem(accItem) for key in accumulatedBasic: bmItem = [ BasicMetrics.metricsOfInterest[key], splitThousands(str(accumulatedBasic[key])) ] basicMetric = QTreeWidgetItem(bmItem) accItem.addChild(basicMetric) # Add the complete information for fileName in metrics.report: if reportOption == self.SingleBuffer: fileItem = QTreeWidgetItem(["Editor buffer"]) else: fileItem = QTreeWidgetItem([fileName]) info = GlobalData().briefModinfoCache.get(fileName) if info.docstring is not None: fileItem.setToolTip(0, info.docstring.text) else: fileItem.setToolTip(0, "") self.__totalResultsTree.addTopLevelItem(fileItem) # Messages part messages = metrics.report[fileName].messages if len(messages) > 0: messagesItem = QTreeWidgetItem(["Messages"]) fileItem.addChild(messagesItem) for message in messages: mItem = [message, "", "E"] messagesItem.addChild(QTreeWidgetItem(mItem)) # Basic metrics part basicItem = QTreeWidgetItem(["Basic metrics"]) fileItem.addChild(basicItem) basic = metrics.report[fileName].basicMetrics for key in basic.metrics: bmItem = [ BasicMetrics.metricsOfInterest[key], str(basic.metrics[key]) ] basicMetric = QTreeWidgetItem(bmItem) basicItem.addChild(basicMetric) # McCabe part mccabeItem = QTreeWidgetItem(["McCabe metrics"]) fileItem.addChild(mccabeItem) mccabe = metrics.report[fileName].mcCabeMetrics.metrics for objName in mccabe: objItem = [objName, str(mccabe[objName]), "M"] mccabeMetric = QTreeWidgetItem(objItem) mccabeItem.addChild(mccabeMetric) # COCOMO 2 part cocomo = [ "COCOMO 2", str(metrics.report[fileName].cocomo2Metrics.value) ] cocomoItem = QTreeWidgetItem(cocomo) fileItem.addChild(cocomoItem) # Resizing the table self.__totalResultsTree.header().resizeSections( QHeaderView.ResizeToContents) # Add McCabe complexity information for fileName in metrics.report: mccabe = metrics.report[fileName].mcCabeMetrics.metrics for objName in mccabe: values = ["", fileName, objName, str(mccabe[objName])] self.__mcCabeTable.addTopLevelItem(McCabeTableItem(values)) if not self.__shouldShowFileName(self.__mcCabeTable, 1): self.__mcCabeTable.setColumnHidden(1, True) # Resizing and sorting the table self.__mcCabeTable.header().setSortIndicator(3, Qt.DescendingOrder) self.__mcCabeTable.sortItems( 3, self.__mcCabeTable.header().sortIndicatorOrder()) self.__mcCabeTable.header().resizeSections( QHeaderView.ResizeToContents) # Show the complete information self.__mcCabeTable.hide() self.__totalResultsTree.show() self.__reportShown = True self.__updateButtonsStatus() self.__updateTooltip() # It helps, but why do I have flickering? QApplication.processEvents() return def __accumulateBasicMetrics(self): " Accumulates basic metrics for all the processed files " basic = {} for fileName in self.__report.report: singleBasic = self.__report.report[fileName].basicMetrics.metrics for key in singleBasic: if not key.startswith('num'): continue if key in basic: basic[key] += int(singleBasic[key]) else: basic[key] = int(singleBasic[key]) return basic def __mcCabeActivated(self, item, column): " Handles the double click (or Enter) on the mccabe table item " objName = str(item.text(2)) if self.__reportOption == self.SingleBuffer: if os.path.isabs(self.__reportFileName): fileName = self.__reportFileName else: fileName = "" else: fileName = str(item.text(1)) self.__onMcCabeObject(objName, fileName) return def __allItemActivated(self, item, column): " Handles the double click (or Enter) in the total results tree " # We process only the error messages and McCabe items hiddenColumnText = str(item.text(2)) if not hiddenColumnText in ["M", "E"]: return fileName = self.__getTreeItemFileName(item) lineNumber = 0 if hiddenColumnText == "M": # This is McCabe item objName = str(item.text(0)) self.__onMcCabeObject(objName, fileName) return elif hiddenColumnText == "E": # This is an error message message = str(item.text(0)) pos = message.find("at line") if pos == -1: logging.error("Unknown format of the message. " "Please inform the developers.") return parts = message[pos:].split() try: lineNumber = int(parts[2].replace(',', '')) except: logging.error("Unknown format of the message. " "Please inform the developers.") return if fileName == "": # This is an unsaved buffer, try to find the editor by UUID mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetByUUID(self.__reportUUID) if widget is None: logging.error("The unsaved buffer has been closed") return # The widget was found, so jump to the required editor = widget.getEditor() editor.gotoLine(lineNumber) editor.setFocus() return GlobalData().mainWindow.openFile(fileName, lineNumber) return def __getTreeItemFileName(self, item): " Identifies the tree view item file name " if self.__reportOption == self.SingleBuffer: if os.path.isabs(self.__reportFileName): return self.__reportFileName return "" # The file name is always two levels up fileItem = item.parent().parent() return str(fileItem.text(0)) def __onMcCabeObject(self, objName, fileName): " Called when the user activated McCabe item " info = None mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetByUUID(self.__reportUUID) if widget is None: if fileName == "": logging.error("The unsaved buffer has been closed") return # No widget, but we know the file name info = getBriefModuleInfoFromFile(fileName) else: # The widget was found editor = widget.getEditor() # The editor content has been modified, so re-parse the buffer info = getBriefModuleInfoFromMemory(editor.text()) parts = objName.split('.') currentIndex = 0 functionsContainer = info.functions classesContainer = info.classes line = -1 if objName == "__main__" and len(parts) == 1: # Special case - global file scope line = 1 currentIndex = 1 while currentIndex < len(parts): found = False for func in functionsContainer: if func.name == parts[currentIndex]: if currentIndex == len(parts) - 1: # Found, jump to the line line = func.line break functionsContainer = func.functions classesContainer = func.classes found = True break if line != -1: break if found: currentIndex += 1 continue for klass in classesContainer: if klass.name == parts[currentIndex]: if currentIndex == len(parts) - 1: # Found, jump to the line line = klass.line break functionsContainer = klass.functions classesContainer = klass.classes found = True if line != -1: break if found: currentIndex += 1 continue # Not found logging.error("Cannot find the " + objName) return # Here we have the line number if widget is None: GlobalData().mainWindow.openFile(fileName, line) else: editor = widget.getEditor() editor.gotoLine(line) editor.setFocus() return def onFileUpdated(self, fileName, uuid): " Called when a buffer is saved or saved as " if not self.__reportShown: return if self.__reportUUID != uuid: return # Currently shown report is for the saved buffer # File name is expected being absolute self.__reportFileName = fileName self.emit(SIGNAL('updatePymetricsTooltip'), "Metrics generated for buffer saved as " + fileName) return
class ThreadsViewer( QWidget ): " Implements the threads viewer for a debugger " def __init__( self, debugger, parent = None ): QWidget.__init__( self, parent ) self.__debugger = debugger self.__createLayout() if Settings().showThreadViewer == False: self.__onShowHide( True ) 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.__threadsLabel = QLabel( "Threads" ) 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 threads list" ) self.__showHideButton.setFocusPolicy( Qt.NoFocus ) self.__showHideButton.clicked.connect( self.__onShowHide ) headerLayout = QHBoxLayout() headerLayout.setContentsMargins( 0, 0, 0, 0 ) headerLayout.addSpacerItem( fixedSpacer ) headerLayout.addWidget( self.__threadsLabel ) headerLayout.addSpacerItem( expandingSpacer ) headerLayout.addWidget( self.__showHideButton ) self.headerFrame.setLayout( headerLayout ) self.__threadsList = QTreeWidget() self.__threadsList.setSortingEnabled( False ) # I might not need that because of two reasons: # - the window has no focus # - the window has custom current indicator # self.__threadsList.setAlternatingRowColors( True ) self.__threadsList.setRootIsDecorated( False ) self.__threadsList.setItemsExpandable( False ) self.__threadsList.setUniformRowHeights( True ) self.__threadsList.setSelectionMode( QAbstractItemView.NoSelection ) self.__threadsList.setSelectionBehavior( QAbstractItemView.SelectRows ) self.__threadsList.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) self.__threadsList.setFocusPolicy( Qt.NoFocus ) self.__threadsList.itemClicked.connect( self.__onThreadClicked ) self.__threadsList.setHeaderLabels( [ "", "Name", "State", "TID" ] ) verticalLayout.addWidget( self.headerFrame ) verticalLayout.addWidget( self.__threadsList ) return def __onShowHide( self, startup = False ): " Triggered when show/hide button is clicked " if startup or self.__threadsList.isVisible(): self.__threadsList.setVisible( False ) self.__showHideButton.setIcon( PixmapCache().getIcon( 'more.png' ) ) self.__showHideButton.setToolTip( "Show threads list" ) self.__minH = self.minimumHeight() self.__maxH = self.maximumHeight() self.setMinimumHeight( self.headerFrame.height() ) self.setMaximumHeight( self.headerFrame.height() ) Settings().showThreadViewer = False else: self.__threadsList.setVisible( True ) self.__showHideButton.setIcon( PixmapCache().getIcon( 'less.png' ) ) self.__showHideButton.setToolTip( "Hide threads list" ) self.setMinimumHeight( self.__minH ) self.setMaximumHeight( self.__maxH ) Settings().showThreadViewer = True return def __resizeColumns( self ): " Resize the files list columns " self.__threadsList.header().setStretchLastSection( True ) self.__threadsList.header().resizeSections( QHeaderView.ResizeToContents ) self.__threadsList.header().resizeSection( 0, 22 ) self.__threadsList.header().setResizeMode( 0, QHeaderView.Fixed ) return def clear( self ): " Clears the content " self.__threadsList.clear() self.__threadsLabel.setText( "Threads" ) return def populate( self, currentThreadID, threadList ): " Populates the thread list from the client " self.clear() for thread in threadList: if thread[ 'broken' ]: state = "Waiting at breakpoint" else: state = "Running" item = ThreadItem( thread[ 'id' ], thread[ 'name' ], state ) if thread[ 'id' ] == currentThreadID: item.setCurrent( True ) self.__threadsList.addTopLevelItem( item ) self.__resizeColumns() self.__threadsLabel.setText( "Threads (total: " + str( len( threadList ) ) + ")" ) return def switchControl( self, isInIDE ): " Switches the UI depending where the control flow is " self.__threadsList.setEnabled( isInIDE ) return def __onThreadClicked( self, item, column ): " Triggered when a thread is clicked " if item.isCurrent(): return for index in xrange( self.__threadsList.topLevelItemCount() ): listItem = self.__threadsList.topLevelItem( index ) if listItem.isCurrent(): listItem.setCurrent( False ) break item.setCurrent( True ) self.__debugger.remoteSetThread( item.getTID() ) return
class OWItemsets(widget.OWWidget): name = 'Frequent Itemsets' description = 'Explore sets of items that frequently appear together.' icon = 'icons/FrequentItemsets.svg' priority = 10 inputs = [("Data", Table, 'set_data')] outputs = [(Output.DATA, Table)] minSupport = settings.Setting(30) maxItemsets = settings.Setting(10000) filterSearch = settings.Setting(True) autoFind = settings.Setting(False) autoSend = settings.Setting(True) filterKeywords = settings.Setting('') filterMinItems = settings.Setting(1) filterMaxItems = settings.Setting(10000) UserAdviceMessages = [ widget.Message( 'Itemset are listed in item-sorted order, i.e. ' 'an itemset containing A and B is only listed once, as ' 'A > B (and not also B > A).', 'itemsets-order', widget.Message.Warning), widget.Message( 'To select all the itemsets that are descendants of ' '(include) some item X (i.e. the whole subtree), you ' 'can fold the subtree at that item and then select it.', 'itemsets-order', widget.Message.Information) ] def __init__(self): self._is_running = False self.isRegexMatch = lambda x: True self.tree = QTreeWidget(self.mainArea, columnCount=2, allColumnsShowFocus=True, alternatingRowColors=True, selectionMode=QTreeWidget.ExtendedSelection, uniformRowHeights=True) self.tree.setHeaderLabels(["Itemsets", "Support", "%"]) self.tree.header().setStretchLastSection(True) self.tree.itemSelectionChanged.connect(self.selectionChanged) self.mainArea.layout().addWidget(self.tree) box = gui.widgetBox(self.controlArea, "Info") self.nItemsets = self.nSelectedExamples = self.nSelectedItemsets = '' gui.label(box, self, "Number of itemsets: %(nItemsets)s") gui.label(box, self, "Selected itemsets: %(nSelectedItemsets)s") gui.label(box, self, "Selected examples: %(nSelectedExamples)s") hbox = gui.widgetBox(box, orientation='horizontal') gui.button(hbox, self, "Expand all", callback=self.tree.expandAll) gui.button(hbox, self, "Collapse all", callback=self.tree.collapseAll) box = gui.widgetBox(self.controlArea, 'Find itemsets') gui.valueSlider(box, self, 'minSupport', values=[.0001, .0005, .001, .005, .01, .05, .1, .5] + list(range(1, 101)), label='Minimal support:', labelFormat="%g%%", callback=lambda: self.find_itemsets()) gui.hSlider(box, self, 'maxItemsets', minValue=10000, maxValue=100000, step=10000, label='Max. number of itemsets:', labelFormat="%d", callback=lambda: self.find_itemsets()) self.button = gui.auto_commit(box, self, 'autoFind', 'Find itemsets', commit=self.find_itemsets) box = gui.widgetBox(self.controlArea, 'Filter itemsets') gui.lineEdit(box, self, 'filterKeywords', 'Contains:', callback=self.filter_change, orientation='horizontal', tooltip='A comma or space-separated list of regular ' 'expressions.') hbox = gui.widgetBox(box, orientation='horizontal') gui.spin(hbox, self, 'filterMinItems', 1, 998, label='Min. items:', callback=self.filter_change) gui.spin(hbox, self, 'filterMaxItems', 2, 999, label='Max. items:', callback=self.filter_change) gui.checkBox(box, self, 'filterSearch', label='Apply these filters in search', tooltip='If checked, the itemsets are filtered according ' 'to these filter conditions already in the search ' 'phase. \nIf unchecked, the only filters applied ' 'during search are the ones above, ' 'and the itemsets are \nfiltered afterwards only for ' 'display, i.e. only the matching itemsets are shown.') gui.rubber(hbox) gui.rubber(self.controlArea) gui.auto_commit(self.controlArea, self, 'autoSend', 'Send selection') self.filter_change() ITEM_DATA_ROLE = Qt.UserRole + 1 def selectionChanged(self): X = self.X mapping = self.onehot_mapping instances = set() where = np.where def whole_subtree(node): yield node for i in range(node.childCount()): yield from whole_subtree(node.child(i)) def itemset(node): while node: yield node.data(0, self.ITEM_DATA_ROLE) node = node.parent() def selection_ranges(node): n_children = node.childCount() if n_children: yield (self.tree.indexFromItem(node.child(0)), self.tree.indexFromItem(node.child(n_children - 1))) for i in range(n_children): yield from selection_ranges(node.child(i)) nSelectedItemsets = 0 item_selection = QItemSelection() for node in self.tree.selectedItems(): nodes = (node, ) if node.isExpanded() else whole_subtree(node) if not node.isExpanded(): for srange in selection_ranges(node): item_selection.select(*srange) for node in nodes: nSelectedItemsets += 1 cols, vals = zip(*(mapping[i] for i in itemset(node))) if issparse(X): rows = (len(cols) == np.bincount( (X[:, cols] != 0).indices, minlength=X.shape[0])).nonzero()[0] else: rows = where((X[:, cols] == vals).all(axis=1))[0] instances.update(rows) self.tree.itemSelectionChanged.disconnect(self.selectionChanged) self.tree.selectionModel().select( item_selection, QItemSelectionModel.Select | QItemSelectionModel.Rows) self.tree.itemSelectionChanged.connect(self.selectionChanged) self.nSelectedExamples = len(instances) self.nSelectedItemsets = nSelectedItemsets self.output = self.data[sorted(instances)] or None self.commit() def commit(self): self.send(Output.DATA, self.output) def filter_change(self): self.warning(9) try: isRegexMatch = self.isRegexMatch = re.compile( '|'.join( i.strip() for i in re.split('(,|\s)+', self.filterKeywords.strip()) if i.strip()), re.IGNORECASE).search except Exception as e: self.warning(9, 'Error in regular expression: {}'.format(e.args[0])) isRegexMatch = self.isRegexMatch = lambda x: True def hide(node, depth, has_kw): if not has_kw: has_kw = isRegexMatch(node.text(0)) hidden = ( sum( hide(node.child(i), depth + 1, has_kw) for i in range(node.childCount())) == node.childCount() if node.childCount() else (not has_kw or not self.filterMinItems <= depth <= self.filterMaxItems)) node.setHidden(hidden) return hidden hide(self.tree.invisibleRootItem(), 0, False) class TreeWidgetItem(QTreeWidgetItem): def data(self, column, role): """Construct lazy tooltips""" if role != Qt.ToolTipRole: return super().data(column, role) tooltip = [] while self: tooltip.append(self.text(0)) self = self.parent() return ' '.join(reversed(tooltip)) def find_itemsets(self): if self.data is None: return if self._is_running: return self._is_running = True data = self.data self.tree.clear() self.tree.setUpdatesEnabled(False) self.tree.blockSignals(True) class ItemDict(dict): def __init__(self, item): self.item = item top = ItemDict(self.tree.invisibleRootItem()) X, mapping = OneHot.encode(data) self.onehot_mapping = mapping ITEM_FMT = '{}' if issparse(data.X) else '{}={}' names = { item: ITEM_FMT.format(var.name, val) for item, var, val in OneHot.decode(mapping.keys(), data, mapping) } nItemsets = 0 filterSearch = self.filterSearch filterMinItems, filterMaxItems = self.filterMinItems, self.filterMaxItems isRegexMatch = self.isRegexMatch # Find itemsets and populate the TreeView with self.progressBar(self.maxItemsets + 1) as progress: for itemset, support in frequent_itemsets(X, self.minSupport / 100): if filterSearch and not filterMinItems <= len( itemset) <= filterMaxItems: continue parent = top first_new_item = None itemset_matches_filter = False for item in sorted(itemset): name = names[item] if filterSearch and not itemset_matches_filter: itemset_matches_filter = isRegexMatch(name) child = parent.get(name) if child is None: try: wi = self.TreeWidgetItem(parent.item, [ name, str(support), '{:.4g}'.format( 100 * support / len(data)) ]) except RuntimeError: # FIXME: When autoFind was in effect and the support # slider was moved, this line excepted with: # RuntimeError: wrapped C/C++ object of type # TreeWidgetItem has been deleted return wi.setData(0, self.ITEM_DATA_ROLE, item) child = parent[name] = ItemDict(wi) if first_new_item is None: first_new_item = (parent, name) parent = child if filterSearch and not itemset_matches_filter: parent, name = first_new_item parent.item.removeChild(parent[name].item) del parent[name].item del parent[name] else: nItemsets += 1 progress.advance() if nItemsets >= self.maxItemsets: break if not filterSearch: self.filter_change() self.nItemsets = nItemsets self.nSelectedItemsets = 0 self.nSelectedExamples = 0 self.tree.expandAll() for i in range(self.tree.columnCount()): self.tree.resizeColumnToContents(i) self.tree.setUpdatesEnabled(True) self.tree.blockSignals(False) self._is_running = False def set_data(self, data): self.data = data is_error = False if data is not None: self.warning(0) self.error(1) self.button.setDisabled(False) self.X = data.X if issparse(data.X): self.X = data.X.tocsc() else: if not data.domain.has_discrete_attributes(): self.error( 1, 'Discrete features required but data has none.') is_error = True self.button.setDisabled(True) elif data.domain.has_continuous_attributes(): self.warning( 0, 'Data has continuous attributes which will be skipped.' ) else: self.output = None self.commit() if self.autoFind and not is_error: self.find_itemsets()
class SVNPluginLogDialog(QDialog): " SVN plugin log dialog " NODIFF = '<html><body bgcolor="#ffffe6"></body></html>' def __init__(self, plugin, client, path, logInfo, parent=None): QDialog.__init__(self, parent) self.__plugin = plugin self.__client = client self.__path = path self.__logInfo = logInfo self.__lhsSelected = None self.__rhsSelected = None self.__createLayout() self.setWindowTitle("SVN Log") lastIndex = len(self.__logInfo) - 1 index = 0 for log in self.__logInfo: newItem = LogItem(log) self.__logView.addTopLevelItem(newItem) if index != lastIndex: rev = log.revision.number nextRev = self.__logInfo[index + 1].revision.number diffButton = self.__createDiffButton( log.revision, self.__logInfo[index + 1].revision) if rev is not None and nextRev is not None: diffButton.setToolTip( "Click to see diff to the older revision (r." + str(rev) + " to r." + str(nextRev) + ")") else: diffButton.setEnabled(False) diffButton.setToolTip( "Could not determine current or previous revision") else: diffButton = self.__createDiffButton(None, None) diffButton.setEnabled(False) diffButton.setToolTip( "Diff to previous revision is not avalable for the first revision" ) self.__logView.setItemWidget(newItem, DIFFTONEXT_COL, diffButton) index += 1 self.__resizeLogView() self.__sortLogView() self.__logView.setFocus() return def __createDiffButton(self, rev, prevRev): " Creates a diff button for a path " button = DiffButton() button.rev = rev button.prevRev = prevRev self.connect(button, SIGNAL('CustomClick'), self.onDiffBetween) return button def __resizeLogView(self): " Resizes the plugins table " self.__logView.header().setStretchLastSection(True) self.__logView.header().resizeSections(QHeaderView.ResizeToContents) self.__logView.header().resizeSection(SELECT_COL, 28) self.__logView.header().setResizeMode(SELECT_COL, QHeaderView.Fixed) self.__logView.header().resizeSection(DIFFTONEXT_COL, 24) self.__logView.header().setResizeMode(DIFFTONEXT_COL, QHeaderView.Fixed) return def __sortLogView(self): " Sorts the log table " self.__logView.sortItems(self.__logView.sortColumn(), self.__logView.header().sortIndicatorOrder()) return def __createLayout(self): " Creates the dialog layout " self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) # Revisions to compare compareGroupbox = QGroupBox(self) compareGroupbox.setTitle("Revisions to compare") sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( compareGroupbox.sizePolicy().hasHeightForWidth()) compareGroupbox.setSizePolicy(sizePolicy) revisionLayout = QHBoxLayout(compareGroupbox) self.__lhsRevisionLabel = QLabel() self.__lhsRevisionLabel.setFrameStyle(QFrame.StyledPanel) self.__lhsResetButton = QToolButton() self.__lhsResetButton.setIcon(PixmapCache().getIcon(pluginHomeDir + 'svnclearrev.png')) self.__lhsResetButton.setFocusPolicy(Qt.NoFocus) self.__lhsResetButton.setEnabled(False) self.__lhsResetButton.setToolTip("Reset revision to compare") self.__lhsResetButton.clicked.connect(self.__onLHSReset) self.__rhsRevisionLabel = QLabel() self.__rhsRevisionLabel.setFrameStyle(QFrame.StyledPanel) self.__rhsResetButton = QToolButton() self.__rhsResetButton.setIcon(PixmapCache().getIcon(pluginHomeDir + 'svnclearrev.png')) self.__rhsResetButton.setFocusPolicy(Qt.NoFocus) self.__rhsResetButton.setEnabled(False) self.__rhsResetButton.setToolTip("Reset revision to compare") self.__rhsResetButton.clicked.connect(self.__onRHSReset) lhsLayout = QHBoxLayout() lhsLayout.addWidget(self.__lhsRevisionLabel) lhsLayout.addWidget(self.__lhsResetButton) rhsLayout = QHBoxLayout() rhsLayout.addWidget(self.__rhsRevisionLabel) rhsLayout.addWidget(self.__rhsResetButton) bothLayout = QVBoxLayout() bothLayout.addLayout(lhsLayout) bothLayout.addLayout(rhsLayout) revisionLayout.addLayout(bothLayout) self.__diffButton = QToolButton() self.__diffButton.setText("Diff") self.__diffButton.setFocusPolicy(Qt.NoFocus) self.__diffButton.setEnabled(False) self.__diffButton.clicked.connect(self.__onDiff) revisionLayout.addWidget(self.__diffButton) vboxLayout.addWidget(compareGroupbox) # Log table logHeaderFrame = QFrame() logHeaderFrame.setFrameStyle(QFrame.StyledPanel) logHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(logHeaderFrame) logHeaderFrame.setFixedHeight(24) logHeaderLayout = QHBoxLayout() logHeaderLayout.setContentsMargins(3, 0, 0, 0) logHeaderLayout.addWidget(QLabel("Subversion log of " + self.__path)) logHeaderFrame.setLayout(logHeaderLayout) vboxLayout.addWidget(logHeaderFrame) self.__logView = QTreeWidget() self.__logView.setAlternatingRowColors(True) self.__logView.setRootIsDecorated(False) self.__logView.setItemsExpandable(False) self.__logView.setSortingEnabled(True) self.__logView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__logViewHeader = QTreeWidgetItem( ["", "", "Revision", "Date", "Author", "Message"]) self.__logView.setHeaderItem(self.__logViewHeader) self.__logView.header().setSortIndicator(REVISION_COL, Qt.AscendingOrder) self.__logView.itemChanged.connect(self.__onLogViewChanged) vboxLayout.addWidget(self.__logView) # Diff part diffHeaderFrame = QFrame() diffHeaderFrame.setFrameStyle(QFrame.StyledPanel) diffHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(diffHeaderFrame) diffHeaderFrame.setFixedHeight(24) diffLabel = QLabel("Diff") diffExpandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideDiffButton = QToolButton() self.__showHideDiffButton.setAutoRaise(True) self.__showHideDiffButton.setIcon(PixmapCache().getIcon('less.png')) self.__showHideDiffButton.setFixedSize(20, 20) self.__showHideDiffButton.setToolTip("Show diff") self.__showHideDiffButton.setFocusPolicy(Qt.NoFocus) self.__showHideDiffButton.clicked.connect(self.__onShowHideDiff) diffLayout = QHBoxLayout() diffLayout.setContentsMargins(3, 0, 0, 0) diffLayout.addWidget(diffLabel) diffLayout.addSpacerItem(diffExpandingSpacer) diffLayout.addWidget(self.__showHideDiffButton) diffHeaderFrame.setLayout(diffLayout) self.__diffViewer = DiffTabWidget() self.__diffViewer.setHTML(self.NODIFF) self.__diffViewer.setVisible(False) vboxLayout.addWidget(diffHeaderFrame) vboxLayout.addWidget(self.__diffViewer) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) buttonBox.button(QDialogButtonBox.Ok).setDefault(True) buttonBox.accepted.connect(self.close) vboxLayout.addWidget(buttonBox) return @staticmethod def __setLightPalette(frame): " Creates a lighter paletter for the widget background " palette = frame.palette() background = palette.color(QPalette.Background) background.setRgb(min(background.red() + 30, 255), min(background.green() + 30, 255), min(background.blue() + 30, 255)) palette.setColor(QPalette.Background, background) frame.setPalette(palette) return def __onShowHideDiff(self): " On/off the diff section " if self.__diffViewer.isVisible(): self.__diffViewer.setVisible(False) self.__showHideDiffButton.setIcon( PixmapCache().getIcon('less.png')) self.__showHideDiffButton.setToolTip("Show diff") else: self.__diffViewer.setVisible(True) self.__showHideDiffButton.setIcon( PixmapCache().getIcon('more.png')) self.__showHideDiffButton.setToolTip("Hide diff") return def onDiffBetween(self, rev, prevRev): " Called when diff is requested between revisions " if not rev or not prevRev: return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) try: lhsContent = self.__client.cat(self.__path, prevRev) rhsContent = self.__client.cat(self.__path, rev) except Exception, exc: QApplication.restoreOverrideCursor() logging.error(str(exc)) return except:
class Preferences(QDialog): configuration = {} weight = 0 def __init__(self, parent=None): super(Preferences, self).__init__(parent, Qt.Dialog) self.setWindowTitle(translations.TR_PREFERENCES_TITLE) self.setMinimumSize(QSize(800, 600)) self.setMaximumSize(QSize(0, 0)) vbox = QVBoxLayout(self) hbox = QHBoxLayout() vbox.setContentsMargins(0, 0, 5, 5) hbox.setContentsMargins(0, 0, 0, 0) self.tree = QTreeWidget() self.tree.header().setHidden(True) self.tree.setSelectionMode(QTreeWidget.SingleSelection) self.tree.setAnimated(True) self.tree.header().setHorizontalScrollMode( QAbstractItemView.ScrollPerPixel) self.tree.header().setResizeMode(0, QHeaderView.ResizeToContents) self.tree.header().setStretchLastSection(False) self.tree.setFixedWidth(200) self.stacked = QStackedLayout() hbox.addWidget(self.tree) hbox.addLayout(self.stacked) vbox.addLayout(hbox) hbox_footer = QHBoxLayout() self._btnSave = QPushButton(translations.TR_SAVE) self._btnCancel = QPushButton(translations.TR_CANCEL) hbox_footer.addSpacerItem(QSpacerItem(1, 0, QSizePolicy.Expanding)) hbox_footer.addWidget(self._btnCancel) hbox_footer.addWidget(self._btnSave) vbox.addLayout(hbox_footer) self.connect(self.tree, SIGNAL("itemSelectionChanged()"), self._change_current) self.connect(self._btnCancel, SIGNAL("clicked()"), self.close) self.connect(self._btnSave, SIGNAL("clicked()"), self._save_preferences) self.load_ui() self.tree.setCurrentItem(self.tree.topLevelItem(0)) def _save_preferences(self): self.emit(SIGNAL("savePreferences()")) self.close() def load_ui(self): sections = sorted( list(Preferences.configuration.keys()), key=lambda item: Preferences.configuration[item]['weight']) for section in sections: text = Preferences.configuration[section]['text'] Widget = Preferences.configuration[section]['widget'] widget = Widget(self) area = QScrollArea() area.setWidgetResizable(True) area.setWidget(widget) index = self.stacked.addWidget(area) item = QTreeWidgetItem([text]) item.setData(0, Qt.UserRole, index) self.tree.addTopLevelItem(item) #Sort Item Children subcontent = Preferences.configuration[section].get( 'subsections', {}) subsections = sorted(list(subcontent.keys()), key=lambda item: subcontent[item]['weight']) for sub in subsections: text = subcontent[sub]['text'] Widget = subcontent[sub]['widget'] widget = Widget(self) area = QScrollArea() area.setWidgetResizable(True) area.setWidget(widget) index = self.stacked.addWidget(area) subitem = QTreeWidgetItem([text]) subitem.setData(0, Qt.UserRole, index) item.addChild(subitem) self.tree.expandAll() def _change_current(self): item = self.tree.currentItem() index = item.data(0, Qt.UserRole) self.stacked.setCurrentIndex(index) @classmethod def register_configuration(cls, section, widget, text, weight=None, subsection=None): if weight is None: Preferences.weight += 1 weight = Preferences.weight if not subsection: Preferences.configuration[section] = { 'widget': widget, 'weight': weight, 'text': text } else: config = Preferences.configuration.get(section, {}) if not config: config[section] = {'widget': None, 'weight': 100} subconfig = config.get('subsections', {}) subconfig[subsection] = { 'widget': widget, 'weight': weight, 'text': text } config['subsections'] = subconfig Preferences.configuration[section] = config
class OWGenExpress(widget.OWWidget): name = "GenExpress" description = "Expression data from GenExpress." icon = "../widgets/icons/GenCloud.svg" priority = 36 inputs = [] outputs = [("Data", Orange.data.Table)] username = settings.Setting("anonymous") password = settings.Setting("") log2 = settings.Setting(False) transpose = settings.Setting(False) rtypei = settings.Setting(0) projecti = settings.Setting(0) serveri = settings.Setting(0) exnamei = settings.Setting(6) excludeconstant = settings.Setting(False) joinreplicates = settings.Setting(False) currentSelection = settings.Setting(None) experimentsHeaderState = settings.Setting( {name: False for _, name in HEADER[:ID_INDEX + 1]}) storedSortOrder = settings.Setting([]) storedSelections = settings.Setting([]) def __init__(self, parent=None): super().__init__(parent) self.servers = [ ('https://dictyexpress.research.bcm.edu/', 'dictyExpress'), ('https://cloud.genialis.com/', 'Genialis'), ] self.selectedExperiments = [] self.buffer = dicty.CacheSQLite(bufferfile) self.searchString = "" self.items = [] self.result_types = [] self.controlArea.setMaximumWidth(250) self.controlArea.setMinimumWidth(250) box = gui.widgetBox(self.controlArea, 'Project') self.projectCB = gui.comboBox(box, self, "projecti", items=[], callback=self.ProjectChosen) self.projects = [] b = gui.widgetBox(self.controlArea, "Selection bookmarks") self.selectionSetsWidget = SelectionSetsWidget(self) self.selectionSetsWidget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) def store_selections(modified): if not modified: self.storedSelections = self.selectionSetsWidget.selections self.selectionSetsWidget.selectionModified.connect(store_selections) b.layout().addWidget(self.selectionSetsWidget) gui.separator(self.controlArea) b = gui.widgetBox(self.controlArea, "Sort output columns") self.columnsSortingWidget = SortedListWidget(self) self.columnsSortingWidget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) box = gui.widgetBox(self.controlArea, 'Experiment name') self.experimentNameCB = gui.comboBox(box, self, "exnamei", items=SORTING_MODEL_LIST) b.layout().addWidget(self.columnsSortingWidget) sorting_model = QStringListModel(SORTING_MODEL_LIST) self.columnsSortingWidget.setModel(sorting_model) self.columnsSortingWidget.sortingOrder = self.storedSortOrder def store_sort_order(): self.storedSortOrder = self.columnsSortingWidget.sortingOrder self.columnsSortingWidget.sortingOrderChanged.connect(store_sort_order) gui.separator(self.controlArea) box = gui.widgetBox(self.controlArea, 'Expression Type') self.expressionTypesCB = gui.comboBox(box, self, "rtypei", items=[], callback=self.UpdateResultsList) gui.checkBox(self.controlArea, self, "excludeconstant", "Exclude labels with constant values") gui.checkBox(self.controlArea, self, "joinreplicates", "Average replicates (use median)") gui.checkBox(self.controlArea, self, "log2", "Logarithmic (base 2) transformation") gui.checkBox(self.controlArea, self, "transpose", "Genes as columns") self.commit_button = gui.button(self.controlArea, self, "&Commit", callback=self.Commit) self.commit_button.setDisabled(True) gui.rubber(self.controlArea) box = gui.widgetBox(self.controlArea, 'Server') gui.comboBox(box, self, "serveri", items=[title for url, title in self.servers], callback=self.ServerChosen) gui.lineEdit(box, self, "username", "Username:"******"password", "Password:"******"Clear cache", callback=self.clear_cache) gui.lineEdit(self.mainArea, self, "searchString", "Search", callbackOnType=True, callback=self.SearchUpdate) self.headerLabels = [t[1] for t in HEADER] self.experimentsWidget = QTreeWidget() self.experimentsWidget.setHeaderLabels(self.headerLabels) self.experimentsWidget.setSelectionMode(QTreeWidget.ExtendedSelection) self.experimentsWidget.setRootIsDecorated(False) self.experimentsWidget.setSortingEnabled(True) contextEventFilter = gui.VisibleHeaderSectionContextEventFilter( self.experimentsWidget, self.experimentsWidget) self.experimentsWidget.header().installEventFilter(contextEventFilter) self.experimentsWidget.setItemDelegateForColumn( 0, gui.IndicatorItemDelegate(self, role=Qt.DisplayRole)) self.experimentsWidget.setAlternatingRowColors(True) self.experimentsWidget.selectionModel().selectionChanged.connect( self.onSelectionChanged) self.selectionSetsWidget.setSelectionModel( self.experimentsWidget.selectionModel()) self.selectionSetsWidget.setSelections(self.storedSelections) self.mainArea.layout().addWidget(self.experimentsWidget) self.restoreHeaderState() self.experimentsWidget.header().geometriesChanged.connect( self.saveHeaderState) self.dbc = None self.AuthSet() QTimer.singleShot(100, self.ConnectAndUpdate) def sizeHint(self): return QSize(800, 600) def AuthSet(self): if len(self.username): self.passf.setDisabled(False) else: self.passf.setDisabled(True) def AuthChanged(self): self.AuthSet() self.ConnectAndUpdate() def ConnectAndUpdate(self): self.Connect() if self.dbc: def get_data_count(project_id): # XXX: is there a better way? # Note: limit 0 would return all objects return self.dbc.gen.api.data.get( case_ids__contains=project_id, type__startswith='data:expression:', limit=1)['meta']['total_count'] self.projects = sorted([ p for p in self.dbc.projects().items() if get_data_count(p[0]) > 0 ], key=lambda x: x[1]) self.UpdateProjects() self.ProjectChosen() self.UpdateExperimentTypes() def Connect(self): self.error(1) self.warning(1) username = '******' password = '******' url = self.servers[self.serveri][0] if self.username: username = self.username password = self.password if username.lower() in ['*****@*****.**', 'anonymous']: username = '******' password = '******' self.dbc = None self.projects = [] self.result_types = [] try: self.dbc = Genesis(address=url, username=username, password=password, cache=self.buffer) except requests.exceptions.ConnectionError: self.dbc = Genesis(address=url, username=username, password=password, connect=False, cache=self.buffer) self.warning(1, "Could not connect to server, working from cache.") except Exception: self.error(1, "Wrong username or password.") self.UpdateProjects() self.UpdateExperimentTypes() # clear lists def Reload(self): self.UpdateExperiments(reload=True) def clear_cache(self): self.buffer.clear() self.Reload() def rtype(self): """Return selected result template type """ if self.result_types: return self.result_types[self.rtypei] else: return None def UpdateExperimentTypes(self): self.expressionTypesCB.clear() items = [self.result_types_labels[desc] for desc in self.result_types] self.expressionTypesCB.addItems(items) #do not update anything if the list is empty if len(self.result_types): self.rtypei = max(0, min(self.rtypei, len(self.result_types) - 1)) def UpdateProjects(self): self.projectCB.clear() items = [desc for pid, desc in self.projects] self.projectCB.addItems(items) #do not update anything if the list if empty if len(self.projects) > 0: self.projecti = max(0, min(self.projecti, len(self.projects) - 1)) def UpdateExperiments(self, reload=False): self.experimentsWidget.clear() if not self.dbc or not self.dbc.projectid: # the connection did not succeed return self.items = [] self.progressBarInit() result_types = [] result_types_labels = [] sucind = False # success indicator for database index try: result_types, result_types_labels = self.dbc.result_types( reload=reload) sucind = True except Exception: try: result_types, result_types_labels = self.dbc.result_types() self.warning(0, "Can not access database - using cached data.") sucind = True except Exception: self.error(0, "Can not access database.") if sucind: self.warning(0) self.error(0) self.result_types = result_types self.result_types_labels = result_types_labels self.UpdateExperimentTypes() self.UpdateResultsList(reload=reload) self.progressBarFinished() if self.currentSelection: self.currentSelection.select( self.experimentsWidget.selectionModel()) self.handle_commit_button() def ProjectChosen(self, reload=False): if self.projects: self.dbc.projectid = self.projects[self.projecti][0] else: self.dbc.projectid = None self.UpdateExperiments(reload=reload) def ServerChosen(self): self.ConnectAndUpdate() def UpdateResultsList(self, reload=False): results_list = self.dbc.results_list(self.rtype(), reload=reload) try: results_list = self.dbc.results_list(self.rtype(), reload=reload) except Exception: try: results_list = self.dbc.results_list(self.rtype()) except Exception: self.error(0, "Can not access database.") self.results_list = results_list #softly change the view so that the selection stays the same items_shown = {} for i, item in enumerate(self.items): c = str(item.text(ID_INDEX)) items_shown[c] = i items_to_show = set(id_ for id_ in self.results_list) add_items = set(items_to_show) - set(items_shown) delete_items = set(items_shown) - set(items_to_show) i = 0 while i < self.experimentsWidget.topLevelItemCount(): it = self.experimentsWidget.topLevelItem(i) if str(it.text(ID_INDEX)) in delete_items: self.experimentsWidget.takeTopLevelItem(i) else: i += 1 delete_ind = set([items_shown[i] for i in delete_items]) self.items = [ it for i, it in enumerate(self.items) if i not in delete_ind ] for r_annot in add_items: d = defaultdict(lambda: "?", self.results_list[r_annot]) row_items = [""] + [ to_text(d.get(key, "?")) for key, _ in HEADER[1:] ] row_items[ID_INDEX] = r_annot ci = MyTreeWidgetItem(self.experimentsWidget, row_items) self.items.append(ci) for i in range(len(self.headerLabels)): self.experimentsWidget.resizeColumnToContents(i) self.wantbufver = lambda x: self.results_list[x]["date_modified"] self.UpdateCached() def UpdateCached(self): if self.wantbufver and self.dbc: for item in self.items: id = str(item.text(ID_INDEX)) version = self.dbc._in_buffer(id + "|||" + self.rtype()) value = " " if version == self.wantbufver(id) else "" item.setData(0, Qt.DisplayRole, value) def SearchUpdate(self, string=""): for item in self.items: item.setHidden(not all(s in item for s in self.searchString.split())) def Commit(self): pb = gui.ProgressBar(self, iterations=100) table = None ids = [] for item in self.experimentsWidget.selectedItems(): unique_id = str(item.text(ID_INDEX)) ids.append(unique_id) transfn = None if self.log2: transfn = lambda x: math.log(x + 1.0, 2) reverse_header_dict = {name: name for key, name in HEADER} reverse_header_dict["ID"] = "id" allowed_labels = None def namefn(a): name = SORTING_MODEL_LIST[self.exnamei] name = reverse_header_dict.get(name, "id") return dict(a)[name] if len(ids): table = self.dbc.get_data( ids=ids, result_type=self.rtype(), callback=pb.advance, exclude_constant_labels=self.excludeconstant, bufver=self.wantbufver, transform=transfn, allowed_labels=allowed_labels, namefn=namefn) if self.joinreplicates: table = dicty.join_replicates( table, ignorenames=self.dbc.IGNORE_REPLICATE, namefn="name", avg=dicty.median, fnshow=lambda x: " | ".join(map(str, x))) # Sort attributes sortOrder = self.columnsSortingWidget.sortingOrder all_values = defaultdict(set) for at in table.domain.attributes: atts = at.attributes for name in sortOrder: all_values[name].add( atts.get(reverse_header_dict[name], "")) isnum = {} for at, vals in all_values.items(): vals = filter(None, vals) try: for a in vals: float(a) isnum[at] = True except ValueError: isnum[at] = False def optfloat(x, at): if x == "": return "" else: return float(x) if isnum[at] else x def sorting_key(attr): atts = attr.attributes return tuple([ optfloat(atts.get(reverse_header_dict[name], ""), name) for name in sortOrder ]) attributes = sorted(table.domain.attributes, key=sorting_key) domain = Orange.data.Domain(attributes, table.domain.class_vars, table.domain.metas) table = Orange.data.Table.from_table(domain, table) table = Orange.data.Table(domain, table) if self.transpose: experiments = [at for at in table.domain.variables] attr = [ compat.ContinuousVariable.make(ex['DDB'].value) for ex in table ] metavars = sorted(table.domain.variables[0].attributes.keys()) metavars = [ compat.StringVariable.make(name) for name in metavars ] domain = compat.create_domain(attr, None, metavars) metavars = compat.get_metas(domain) metas = [[exp.attributes[var.name] for var in metavars] for exp in experiments] table = compat.create_table(domain, table.X.transpose(), None, metas) data_hints.set_hint(table, "taxid", "352472") data_hints.set_hint(table, "genesinrows", False) self.send("Data", table) self.UpdateCached() pb.finish() def onSelectionChanged(self, selected, deselected): self.handle_commit_button() def handle_commit_button(self): self.currentSelection = \ SelectionByKey(self.experimentsWidget.selectionModel().selection(), key=(ID_INDEX,)) self.commit_button.setDisabled(not len(self.currentSelection)) def saveHeaderState(self): hview = self.experimentsWidget.header() for i, label in enumerate(self.headerLabels): self.experimentsHeaderState[label] = hview.isSectionHidden(i) def restoreHeaderState(self): hview = self.experimentsWidget.header() state = self.experimentsHeaderState for i, label in enumerate(self.headerLabels): hview.setSectionHidden(i, state.get(label, True)) self.experimentsWidget.resizeColumnToContents(i)
class ArbolDeSimbolos(custom_dock.CustomDock): _ir_a_linea = pyqtSignal(int, name='irALinea') iconos = { 'clase': paths.ICONOS['class'], 'funcion': paths.ICONOS['funcion'], 'struct': paths.ICONOS['struct'], 'miembro': paths.ICONOS['miembro'], 'global': paths.ICONOS['variable'], 'enumerator': paths.ICONOS['enumerator'], 'enums': paths.ICONOS['enums'] } def __init__(self): custom_dock.CustomDock.__init__(self) self.tree = QTreeWidget() self.setWidget(self.tree) self.tree.setObjectName("simbolos") self.tree.header().setHidden(True) self.tree.setSelectionMode(self.tree.SingleSelection) self.tree.setAnimated(True) self.tree.header().setStretchLastSection(False) self.tree.header().setHorizontalScrollMode( QAbstractItemView.ScrollPerPixel) self.tree.header().setResizeMode(0, QHeaderView.ResizeToContents) # Conexión self.tree.itemClicked[QTreeWidgetItem, int].connect(self.ir_a_linea) self.tree.itemActivated[QTreeWidgetItem, int].connect(self.ir_a_linea) EDIS.cargar_lateral("simbolos", self) def actualizar_simbolos(self, archivo): #FIXME: mover esto self.ctags = ectags.Ctags() tag = self.ctags.run_ctags(archivo) simbolos = self.ctags.parser(tag) self._actualizar_simbolos(simbolos) def _actualizar_simbolos(self, simbolos): #FIXME: # Limpiar self.tree.clear() if simbolos is None: no_ctags = Item(self.tree, [self.tr('Ctags no está instalado.')]) no_ctags.clickeable = False return if 'variable' in simbolos: variables = Item(self.tree, [self.tr('Variables')]) variables.clickeable = False for v in simbolos['variable']: variable = Item(variables, [v.get('nombre')]) linea = v['linea'] variable.linea = linea variable.setIcon(0, QIcon(self.iconos['global'])) variables.setExpanded(True) if 'function' in simbolos: funciones = Item(self.tree, [self.tr('Funciones')]) funciones.clickeable = False for f in simbolos['function']: funcion = Item(funciones, [f.get('nombre')]) linea = f['linea'] funcion.linea = linea funcion.setIcon(0, QIcon(self.iconos['funcion'])) funciones.setExpanded(True) if 'struct' in simbolos: structs = Item(self.tree, [self.tr('Estructuras')]) structs.clickeable = False for s in simbolos['struct']: struct = Item(structs, [s.get('nombre')]) linea = s['linea'] struct.linea = linea struct.setIcon(0, QIcon(self.iconos['struct'])) structs.setExpanded(True) if 'member' in simbolos: miembros = Item(self.tree, [self.tr('Miembros')]) miembros.clickeable = False for m in simbolos['member']: nombre = m['nombre'] + ' [' + m['padre'] + ']' miembro = Item(miembros, [nombre]) miembro.setIcon(0, QIcon(self.iconos['miembro'])) linea = m['linea'] miembro.linea = linea miembros.setExpanded(True) def ir_a_linea(self, item): if item.clickeable: self._ir_a_linea.emit(int(item.linea) - 1)
class RunsDialog(QtHelper.EnhancedQDialog): """ Runs several dialog """ RefreshRepository = pyqtSignal(str) def __init__(self, dialogName, parent = None, iRepo=None, lRepo=None, rRepo=None): """ Constructor """ QtHelper.EnhancedQDialog.__init__(self, parent) self.name = self.tr("Prepare a group of runs") self.projectReady = False self.iRepo = iRepo self.lRepo = lRepo self.rRepo = rRepo self.createDialog() self.createConnections() def createDialog(self): """ Create qt dialog """ self.setWindowTitle( self.name ) mainLayout = QHBoxLayout() layoutTests = QHBoxLayout() layoutRepoTest = QVBoxLayout() self.prjCombo = QComboBox(self) self.prjCombo.setEnabled(False) self.repoTests = QTreeWidget(self) self.repoTests.setFrameShape(QFrame.NoFrame) if USE_PYQT5: self.repoTests.header().setSectionResizeMode(QHeaderView.Stretch) else: self.repoTests.header().setResizeMode(QHeaderView.Stretch) self.repoTests.setHeaderHidden(True) self.repoTests.setContextMenuPolicy(Qt.CustomContextMenu) self.repoTests.setIndentation(10) layoutRepoTest.addWidget(self.prjCombo) layoutRepoTest.addWidget(self.repoTests) self.testsList = QListWidget(self) layoutTests.addLayout( layoutRepoTest ) layoutTests.addWidget( self.testsList ) mainLayout.addLayout( layoutTests ) buttonLayout = QVBoxLayout() self.okButton = QPushButton(self.tr("Execute All"), self) self.okButton.setEnabled(False) self.cancelButton = QPushButton(self.tr("Cancel"), self) self.upButton = QPushButton(self.tr("UP"), self) self.upButton.setEnabled(False) self.downButton = QPushButton(self.tr("DOWN"), self) self.downButton.setEnabled(False) self.clearButton = QPushButton(self.tr("Remove All"), self) self.delButton = QPushButton(self.tr("Remove"), self) self.delButton.setEnabled(False) self.runSimultaneous = QCheckBox(self.tr("Simultaneous Run")) self.schedImmed = QRadioButton(self.tr("Run Immediately")) self.schedImmed.setChecked(True) self.schedAt = QRadioButton(self.tr("Run At:")) self.schedAtDateTimeEdit = QDateTimeEdit(QDateTime.currentDateTime()) self.schedAtDateTimeEdit.setEnabled(False) buttonLayout.addWidget(self.okButton) buttonLayout.addWidget(self.runSimultaneous) buttonLayout.addWidget(self.schedImmed) buttonLayout.addWidget(self.schedAt) buttonLayout.addWidget(self.schedAtDateTimeEdit) buttonLayout.addWidget( self.upButton ) buttonLayout.addWidget( self.downButton ) buttonLayout.addWidget( self.delButton ) buttonLayout.addWidget( self.clearButton ) buttonLayout.addWidget(self.cancelButton) mainLayout.addLayout(buttonLayout) self.setMinimumHeight(400) self.setMinimumWidth(750) self.setLayout(mainLayout) def initProjects(self, projects=[], defaultProject=1): """ Initialize projects """ # init date and time self.schedAtDateTimeEdit.setDateTime(QDateTime.currentDateTime()) self.projectReady = False self.repoTests.clear() self.prjCombo.clear() self.testsList.clear() self.prjCombo.setEnabled(True) # insert data pname = '' for p in projects: self.prjCombo.addItem ( p['name'] ) if defaultProject == p['project_id']: pname = p['name'] for i in xrange(self.prjCombo.count()): item_text = self.prjCombo.itemText(i) if str(pname) == str(item_text): self.prjCombo.setCurrentIndex(i) self.projectReady = True self.RefreshRepository.emit(pname) def initializeTests(self, listing): """ Initialize tests """ self.repoTests.clear() self.testRoot = self.rRepo.Item(repo = self.iRepo.remote(), parent = self.repoTests, txt = "Root", type = QTreeWidgetItem.UserType+10, isRoot = True ) self.testRoot.setSelected(True) self.createRepository(listing=listing, parent=self.testRoot,fileincluded=True) self.repoTests.sortItems(0, Qt.AscendingOrder) self.hideItems(hideTsx=False, hideTpx=False, hideTcx=True, hideTdx=True, hideTxt=True, hidePy=True, hideTux=False, hidePng=True, hideTgx=False, hideTax=False) def createRepository(self, listing, parent, fileincluded=True): """ Create repository @param listing: @type listing: list @param parent: @type parent: @param fileincluded: @type fileincluded: boolean """ try: for dct in listing: if dct["type"] == "folder": item = self.rRepo.Item(repo = self.iRepo.remote(), parent = parent, txt = dct["name"], propertiesFile=dct ) self.createRepository( dct["content"] , item, fileincluded ) else: if fileincluded: if dct["type"] == "file": pname = self.iRepo.remote().getProjectName(dct["project"]) # {'modification': 1342259500, 'type': 'file', 'name': '__init__.py', 'size': '562 } item = self.rRepo.Item(repo = self.iRepo.remote(), parent = parent, txt = dct["name"] , propertiesFile=dct, type = QTreeWidgetItem.UserType+0, projectId=dct["project"], projectName=pname ) except Exception as e: self.error( "unable to create tree for runs: %s" % e ) def onProjectChanged(self, projectItem): """ Called when the project changed on the combo box """ if self.projectReady: item_text = self.prjCombo.itemText(projectItem) self.RefreshRepository.emit(item_text) def createConnections (self): """ create qt connections * ok * cancel """ self.prjCombo.currentIndexChanged.connect(self.onProjectChanged) self.okButton.clicked.connect( self.acceptClicked ) self.cancelButton.clicked.connect( self.reject ) self.upButton.clicked.connect(self.upTest) self.downButton.clicked.connect(self.downTest) self.clearButton.clicked.connect(self.clearList) self.delButton.clicked.connect(self.delTest) self.testsList.itemClicked.connect(self.onItemSelected) self.testsList.itemSelectionChanged.connect(self.onItemSelectionChanged) self.schedAt.toggled.connect(self.onSchedAtActivated) self.repoTests.itemDoubleClicked.connect( self.onTestDoucleClicked ) def onSchedAtActivated(self, toggled): """ On sched at button activated """ if toggled: self.schedAtDateTimeEdit.setEnabled(True) else: self.schedAtDateTimeEdit.setEnabled(False) def onItemSelectionChanged(self): """ Called on item selection changed """ self.onItemSelected(itm=None) def onItemSelected(self, itm): """ Call on item selected """ selectedItems = self.testsList.selectedItems() if len(selectedItems): self.delButton.setEnabled(True) self.upButton.setEnabled(True) self.downButton.setEnabled(True) else: self.delButton.setEnabled(False) self.upButton.setEnabled(False) self.downButton.setEnabled(False) if not self.testsList.count(): self.okButton.setEnabled(False) def upTest(self): """ Up test """ currentRow = self.testsList.currentRow() currentItem = self.testsList.takeItem(currentRow) self.testsList.insertItem(currentRow - 1, currentItem) def downTest(self): """ Down test """ currentRow = self.testsList.currentRow() currentItem = self.testsList.takeItem(currentRow) self.testsList.insertItem(currentRow + 1, currentItem) def delTest(self): """ Del test """ currentRow = self.testsList.currentRow() currentItem = self.testsList.takeItem(currentRow) def clearList(self): """ Clear test """ self.testsList.clear() self.delButton.setEnabled(False) self.upButton.setEnabled(False) self.downButton.setEnabled(False) self.okButton.setEnabled(False) def iterateTree(self, item, hideTsx, hideTpx, hideTcx, hideTdx, hideTxt, hidePy, hideTux, hidePng, hideTgx, hideTax): """ Iterate tree """ child_count = item.childCount() for i in range(child_count): subitem = item.child(i) subchild_count = subitem.childCount() if subchild_count > 0: self.iterateTree(item=subitem, hideTsx=hideTsx, hideTpx=hideTpx, hideTcx=hideTcx, hideTdx=hideTdx, hideTxt=hideTxt, hidePy=hidePy, hideTux=hideTux, hidePng=hidePng, hideTgx=hideTgx, hideTax=hideTax) else: if hideTux and subitem.getExtension() == self.rRepo.EXTENSION_TUX: subitem.setHidden (True) elif hideTpx and subitem.getExtension() == self.rRepo.EXTENSION_TPX: subitem.setHidden (True) elif hideTgx and subitem.getExtension() == self.rRepo.EXTENSION_TGX: subitem.setHidden (True) elif hideTcx and subitem.getExtension() == self.rRepo.EXTENSION_TCX: subitem.setHidden (True) elif hideTsx and subitem.getExtension() == self.rRepo.EXTENSION_TSX: subitem.setHidden (True) elif hideTdx and subitem.getExtension() == self.rRepo.EXTENSION_TDX: subitem.setHidden (True) elif hideTxt and subitem.getExtension() == self.rRepo.EXTENSION_TXT: subitem.setHidden (True) elif hidePy and subitem.getExtension() == self.rRepo.EXTENSION_PY: subitem.setHidden (True) elif hidePng and subitem.getExtension() == self.rRepo.EXTENSION_PNG: subitem.setHidden (True) elif hideTax and subitem.getExtension() == self.rRepo.EXTENSION_TAx: subitem.setHidden (True) else: subitem.setHidden(False) def hideItems(self, hideTsx=False, hideTpx=False, hideTcx=False, hideTdx=False, hideTxt=False, hidePy=False, hideTux=False, hidePng=False, hideTgx=False, hideTax=False): """ Hide items """ root = self.repoTests.invisibleRootItem() self.iterateTree(item=root, hideTsx=hideTsx, hideTpx=hideTpx, hideTcx=hideTcx, hideTdx=hideTdx, hideTxt=hideTxt, hidePy=hidePy, hideTux=hideTux, hidePng=hidePng, hideTgx=hideTgx, hideTax=hideTax) def onTestDoucleClicked(self, testItem): """ On tests double clicked """ if testItem.type() != QTreeWidgetItem.UserType+0: return self.okButton.setEnabled(True) currentProject = self.prjCombo.currentText() testName = "%s:%s" % (str(currentProject),testItem.getPath(withFileName = True)) testItem = QListWidgetItem(testName ) if testName.endswith(self.rRepo.EXTENSION_TUX): testItem.setIcon(QIcon(":/tux.png")) if testName.endswith(self.rRepo.EXTENSION_TSX): testItem.setIcon(QIcon(":/tsx.png")) if testName.endswith(self.rRepo.EXTENSION_TPX): testItem.setIcon(QIcon(":/tpx.png")) if testName.endswith(self.rRepo.EXTENSION_TGX): testItem.setIcon(QIcon(":/tgx.png")) if testName.endswith(self.rRepo.EXTENSION_TAX): testItem.setIcon(QIcon(":/tax.png")) self.testsList.addItem( testItem ) def acceptClicked (self): """ Called on accept button """ self.accept() def getTests(self): """ Returns all tests in the list """ tests = [] for i in xrange(self.testsList.count()): testItem = self.testsList.item(i) tests.append( str(testItem.text()) ) runSimultaneous = False if self.runSimultaneous.isChecked(): runSimultaneous = True if self.schedImmed.isChecked(): runAt = (0,0,0,0,0,0) return (tests, False, runAt, runSimultaneous) else: pydt = self.schedAtDateTimeEdit.dateTime().toPyDateTime() runAt = (pydt.year, pydt.month, pydt.day, pydt.hour, pydt.minute, pydt.second) return (tests, True, runAt, runSimultaneous)
class ThreadsViewer(QWidget): " Implements the threads viewer for a debugger " def __init__(self, debugger, parent=None): QWidget.__init__(self, parent) self.__debugger = debugger self.__createLayout() if Settings().showThreadViewer == False: self.__onShowHide(True) 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.__threadsLabel = QLabel("Threads") 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 threads list") self.__showHideButton.setFocusPolicy(Qt.NoFocus) self.__showHideButton.clicked.connect(self.__onShowHide) headerLayout = QHBoxLayout() headerLayout.setContentsMargins(0, 0, 0, 0) headerLayout.addSpacerItem(fixedSpacer) headerLayout.addWidget(self.__threadsLabel) headerLayout.addSpacerItem(expandingSpacer) headerLayout.addWidget(self.__showHideButton) self.headerFrame.setLayout(headerLayout) self.__threadsList = QTreeWidget() self.__threadsList.setSortingEnabled(False) # I might not need that because of two reasons: # - the window has no focus # - the window has custom current indicator # self.__threadsList.setAlternatingRowColors( True ) self.__threadsList.setRootIsDecorated(False) self.__threadsList.setItemsExpandable(False) self.__threadsList.setUniformRowHeights(True) self.__threadsList.setSelectionMode(QAbstractItemView.NoSelection) self.__threadsList.setSelectionBehavior(QAbstractItemView.SelectRows) self.__threadsList.setItemDelegate(NoOutlineHeightDelegate(4)) self.__threadsList.setFocusPolicy(Qt.NoFocus) self.__threadsList.itemClicked.connect(self.__onThreadClicked) self.__threadsList.setHeaderLabels(["", "Name", "State", "TID"]) verticalLayout.addWidget(self.headerFrame) verticalLayout.addWidget(self.__threadsList) return def __onShowHide(self, startup=False): " Triggered when show/hide button is clicked " if startup or self.__threadsList.isVisible(): self.__threadsList.setVisible(False) self.__showHideButton.setIcon(PixmapCache().getIcon('more.png')) self.__showHideButton.setToolTip("Show threads list") self.__minH = self.minimumHeight() self.__maxH = self.maximumHeight() self.setMinimumHeight(self.headerFrame.height()) self.setMaximumHeight(self.headerFrame.height()) Settings().showThreadViewer = False else: self.__threadsList.setVisible(True) self.__showHideButton.setIcon(PixmapCache().getIcon('less.png')) self.__showHideButton.setToolTip("Hide threads list") self.setMinimumHeight(self.__minH) self.setMaximumHeight(self.__maxH) Settings().showThreadViewer = True return def __resizeColumns(self): " Resize the files list columns " self.__threadsList.header().setStretchLastSection(True) self.__threadsList.header().resizeSections( QHeaderView.ResizeToContents) self.__threadsList.header().resizeSection(0, 22) self.__threadsList.header().setResizeMode(0, QHeaderView.Fixed) return def clear(self): " Clears the content " self.__threadsList.clear() self.__threadsLabel.setText("Threads") return def populate(self, currentThreadID, threadList): " Populates the thread list from the client " self.clear() for thread in threadList: if thread['broken']: state = "Waiting at breakpoint" else: state = "Running" item = ThreadItem(thread['id'], thread['name'], state) if thread['id'] == currentThreadID: item.setCurrent(True) self.__threadsList.addTopLevelItem(item) self.__resizeColumns() self.__threadsLabel.setText("Threads (total: " + str(len(threadList)) + ")") return def switchControl(self, isInIDE): " Switches the UI depending where the control flow is " self.__threadsList.setEnabled(isInIDE) return def __onThreadClicked(self, item, column): " Triggered when a thread is clicked " if item.isCurrent(): return for index in xrange(self.__threadsList.topLevelItemCount()): listItem = self.__threadsList.topLevelItem(index) if listItem.isCurrent(): listItem.setCurrent(False) break item.setCurrent(True) self.__debugger.remoteSetThread(item.getTID()) return
class OWDatabasesUpdate(OWWidget): name = "Databases Update" description = "Update local systems biology databases." icon = "../widgets/icons/Databases.svg" priority = 10 inputs = [] outputs = [] want_main_area = False def __init__(self, parent=None, signalManager=None, name="Databases update", domains=None): OWWidget.__init__(self, parent, signalManager, name, wantMainArea=False) self.searchString = "" self.accessCode = "" self.domains = domains or DOMAINS self.serverFiles = serverfiles.ServerFiles() fbox = gui.widgetBox(self.controlArea, "Filter") self.completer = TokenListCompleter( self, caseSensitivity=Qt.CaseInsensitive) self.lineEditFilter = QLineEdit(textChanged=self.SearchUpdate) self.lineEditFilter.setCompleter(self.completer) fbox.layout().addWidget(self.lineEditFilter) box = gui.widgetBox(self.controlArea, "Files") self.filesView = QTreeWidget(self) self.filesView.setHeaderLabels( ["", "Data Source", "Update", "Last Updated", "Size"]) self.filesView.setRootIsDecorated(False) self.filesView.setUniformRowHeights(True) self.filesView.setSelectionMode(QAbstractItemView.NoSelection) self.filesView.setSortingEnabled(True) self.filesView.sortItems(1, Qt.AscendingOrder) self.filesView.setItemDelegateForColumn( 0, UpdateOptionsItemDelegate(self.filesView)) self.filesView.model().layoutChanged.connect(self.SearchUpdate) box.layout().addWidget(self.filesView) box = gui.widgetBox(self.controlArea, orientation="horizontal") self.updateButton = gui.button( box, self, "Update all", callback=self.UpdateAll, tooltip="Update all updatable files", ) self.downloadButton = gui.button( box, self, "Download all", callback=self.DownloadFiltered, tooltip="Download all filtered files shown" ) self.cancelButton = gui.button( box, self, "Cancel", callback=self.Cancel, tooltip="Cancel scheduled downloads/updates." ) self.retryButton = gui.button( box, self, "Reconnect", callback=self.RetrieveFilesList ) self.retryButton.hide() gui.rubber(box) gui.lineEdit(box, self, "accessCode", "Access Code", orientation="horizontal", callback=self.RetrieveFilesList) self.warning(0) box = gui.widgetBox(self.controlArea, orientation="horizontal") gui.rubber(box) self.infoLabel = QLabel() self.infoLabel.setAlignment(Qt.AlignCenter) self.controlArea.layout().addWidget(self.infoLabel) self.infoLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.updateItems = [] self.resize(800, 600) self.progress = ProgressState(self, maximum=3) self.progress.valueChanged.connect(self._updateProgress) self.progress.rangeChanged.connect(self._updateProgress) self.executor = ThreadExecutor( threadPool=QThreadPool(maxThreadCount=2) ) task = Task(self, function=self.RetrieveFilesList) task.exceptionReady.connect(self.HandleError) task.start() self._tasks = [] self._haveProgress = False def RetrieveFilesList(self): self.retryButton.hide() self.warning(0) self.progress.setRange(0, 3) self.serverFiles = serverfiles.ServerFiles(access_code=self.accessCode) task = Task(function=partial(retrieveFilesList, self.serverFiles, self.domains, methodinvoke(self.progress, "advance"))) task.resultReady.connect(self.SetFilesList) task.exceptionReady.connect(self.HandleError) self.executor.submit(task) self.setEnabled(False) def SetFilesList(self, serverInfo): """ Set the files to show. """ self.setEnabled(True) domains = serverInfo.keys() if not domains: if self.domains: domains = self.domains else: domains = serverfiles.listdomains() localInfo = dict([(dom, serverfiles.allinfo(dom)) for dom in domains]) all_tags = set() self.filesView.clear() self.updateItems = [] for item in join_info_dict(localInfo, serverInfo): tree_item = UpdateTreeWidgetItem(item) options_widget = UpdateOptionsWidget(item.state) options_widget.item = item options_widget.installClicked.connect( partial(self.SubmitDownloadTask, item.domain, item.filename) ) options_widget.removeClicked.connect( partial(self.SubmitRemoveTask, item.domain, item.filename) ) self.updateItems.append((item, tree_item, options_widget)) all_tags.update(item.tags) self.filesView.addTopLevelItems( [tree_item for _, tree_item, _ in self.updateItems] ) for item, tree_item, options_widget in self.updateItems: self.filesView.setItemWidget(tree_item, 0, options_widget) # Add an update button if the file is updateable if item.state == OUTDATED: button = QToolButton( None, text="Update", maximumWidth=120, minimumHeight=20, maximumHeight=20 ) if sys.platform == "darwin": button.setAttribute(Qt.WA_MacSmallSize) button.clicked.connect( partial(self.SubmitDownloadTask, item.domain, item.filename) ) self.filesView.setItemWidget(tree_item, 2, button) self.progress.advance() self.filesView.setColumnWidth(0, self.filesView.sizeHintForColumn(0)) for column in range(1, 4): contents_hint = self.filesView.sizeHintForColumn(column) header_hint = self.filesView.header().sectionSizeHint(column) width = max(min(contents_hint, 400), header_hint) self.filesView.setColumnWidth(column, width) hints = [hint for hint in sorted(all_tags) if not hint.startswith("#")] self.completer.setTokenList(hints) self.SearchUpdate() self.UpdateInfoLabel() self.toggleButtons() self.cancelButton.setEnabled(False) self.progress.setRange(0, 0) def buttonCheck(self, selected_items, state, button): for item in selected_items: if item.state != state: button.setEnabled(False) else: button.setEnabled(True) break def toggleButtons(self): selected_items = [item for item, tree_item, _ in self.updateItems if not tree_item.isHidden()] self.buttonCheck(selected_items, OUTDATED, self.updateButton) self.buttonCheck(selected_items, AVAILABLE, self.downloadButton) def HandleError(self, exception): if isinstance(exception, ConnectionError): self.warning(0, "Could not connect to server! Check your connection " "and try to reconnect.") self.SetFilesList({}) self.retryButton.show() else: sys.excepthook(type(exception), exception.args, None) self.progress.setRange(0, 0) self.setEnabled(True) def UpdateInfoLabel(self): local = [item for item, tree_item, _ in self.updateItems if item.state != AVAILABLE and not tree_item.isHidden()] size = sum(float(item.size) for item in local) onServer = [item for item, tree_item, _ in self.updateItems if not tree_item.isHidden()] sizeOnServer = sum(float(item.size) for item in onServer) text = ("%i items, %s (on server: %i items, %s)" % (len(local), sizeof_fmt(size), len(onServer), sizeof_fmt(sizeOnServer))) self.infoLabel.setText(text) def UpdateAll(self): self.warning(0) for item, tree_item, _ in self.updateItems: if item.state == OUTDATED and not tree_item.isHidden(): self.SubmitDownloadTask(item.domain, item.filename) def DownloadFiltered(self): # TODO: submit items in the order shown. for item, tree_item, _ in self.updateItems: if not tree_item.isHidden() and item.state in \ [AVAILABLE, OUTDATED]: self.SubmitDownloadTask(item.domain, item.filename) def SearchUpdate(self, searchString=None): strings = str(self.lineEditFilter.text()).split() for item, tree_item, _ in self.updateItems: hide = not all(UpdateItem_match(item, string) for string in strings) tree_item.setHidden(hide) self.UpdateInfoLabel() self.toggleButtons() def SubmitDownloadTask(self, domain, filename): """ Submit the (domain, filename) to be downloaded/updated. """ self.cancelButton.setEnabled(True) index = self.updateItemIndex(domain, filename) _, tree_item, opt_widget = self.updateItems[index] if self.accessCode: sf = serverfiles.ServerFiles(access_code=self.accessCode) else: sf = serverfiles.ServerFiles() task = DownloadTask(domain, filename, sf) self.progress.adjustRange(0, 100) pb = ItemProgressBar(self.filesView) pb.setRange(0, 100) pb.setTextVisible(False) task.advanced.connect(pb.advance) task.advanced.connect(self.progress.advance) task.finished.connect(pb.hide) task.finished.connect(self.onDownloadFinished, Qt.QueuedConnection) task.exception.connect(self.onDownloadError, Qt.QueuedConnection) self.filesView.setItemWidget(tree_item, 2, pb) # Clear the text so it does not show behind the progress bar. tree_item.setData(2, Qt.DisplayRole, "") pb.show() # Disable the options widget opt_widget.setEnabled(False) self._tasks.append(task) self.executor.submit(task) def EndDownloadTask(self, task): future = task.future() index = self.updateItemIndex(task.domain, task.filename) item, tree_item, opt_widget = self.updateItems[index] self.filesView.removeItemWidget(tree_item, 2) opt_widget.setEnabled(True) if future.cancelled(): # Restore the previous state tree_item.setUpdateItem(item) opt_widget.setState(item.state) elif future.exception(): tree_item.setUpdateItem(item) opt_widget.setState(item.state) # Show the exception string in the size column. self.warning(0, "Error while downloading. Check your connection " "and retry.") # recreate button for download button = QToolButton( None, text="Retry", maximumWidth=120, minimumHeight=20, maximumHeight=20 ) if sys.platform == "darwin": button.setAttribute(Qt.WA_MacSmallSize) button.clicked.connect( partial(self.SubmitDownloadTask, item.domain, item.filename) ) self.filesView.setItemWidget(tree_item, 2, button) else: # get the new updated info dict and replace the the old item self.warning(0) info = serverfiles.info(item.domain, item.filename) new_item = update_item_from_info(item.domain, item.filename, info, info) self.updateItems[index] = (new_item, tree_item, opt_widget) tree_item.setUpdateItem(new_item) opt_widget.setState(new_item.state) self.UpdateInfoLabel() def SubmitRemoveTask(self, domain, filename): serverfiles.remove(domain, filename) index = self.updateItemIndex(domain, filename) item, tree_item, opt_widget = self.updateItems[index] if item.info_server: new_item = item._replace(state=AVAILABLE, local=None, info_local=None) else: new_item = item._replace(local=None, info_local=None) # Disable the options widget. No more actions can be performed # for the item. opt_widget.setEnabled(False) tree_item.setUpdateItem(new_item) opt_widget.setState(new_item.state) self.updateItems[index] = (new_item, tree_item, opt_widget) self.UpdateInfoLabel() def Cancel(self): """ Cancel all pending update/download tasks (that have not yet started). """ for task in self._tasks: task.future().cancel() def onDeleteWidget(self): self.Cancel() self.executor.shutdown(wait=False) OWWidget.onDeleteWidget(self) def onDownloadFinished(self): # on download completed/canceled/error assert QThread.currentThread() is self.thread() for task in list(self._tasks): future = task.future() if future.done(): self.EndDownloadTask(task) self._tasks.remove(task) if not self._tasks: # Clear/reset the overall progress self.progress.setRange(0, 0) self.cancelButton.setEnabled(False) def onDownloadError(self, exc_info): sys.excepthook(*exc_info) self.warning(0, "Error while downloading. Check your connection and " "retry.") def updateItemIndex(self, domain, filename): for i, (item, _, _) in enumerate(self.updateItems): if item.domain == domain and item.filename == filename: return i raise ValueError("%r, %r not in update list" % (domain, filename)) def _updateProgress(self, *args): rmin, rmax = self.progress.range() if rmin != rmax: if not self._haveProgress: self._haveProgress = True self.progressBarInit() self.progressBarSet(self.progress.ratioCompleted() * 100, processEvents=None) if rmin == rmax: self._haveProgress = False self.progressBarFinished()
class SVNPluginPropsDialog( QDialog ): " SVN plugin properties dialog " def __init__( self, plugin, client, path, parent = None ): QDialog.__init__( self, parent ) self.__plugin = plugin self.__client = client self.__path = path self.__createLayout() self.setWindowTitle( "SVN Properties of " + path ) self.__populate() self.__propsView.setFocus() return def __populate( self ): " Populate the properties list " # Get the currently selected name selectedName = None selected = list( self.__propsView.selectedItems() ) if selected: selectedName = str( selected[ 0 ].text( 0 ) ) self.__propsView.clear() properties = readProperties( self.__client, self.__path ) if properties: for itemPath, itemProps in properties: if self.__path == itemPath or \ self.__path == itemPath + os.path.sep: for name, value in itemProps.iteritems(): name = str( name ).strip() value = str( value ).strip() newItem = QTreeWidgetItem( [ name, value ] ) self.__propsView.addTopLevelItem( newItem ) self.__resizePropsView() self.__sortPropsView() if selectedName: index = 0 for index in xrange( 0, self.__propsView.topLevelItemCount() ): item = self.__propsView.topLevelItem( index ) if selectedName == item.text( 0 ): item.setSelected( True ) return def __resizePropsView( self ): " Resizes the properties table " self.__propsView.header().setStretchLastSection( True ) self.__propsView.header().resizeSections( QHeaderView.ResizeToContents ) return def __sortPropsView( self ): " Sorts the properties table " self.__propsView.sortItems( self.__propsView.sortColumn(), self.__propsView.header().sortIndicatorOrder() ) return def __createLayout( self ): " Creates the dialog layout " self.resize( 640, 480 ) self.setSizeGripEnabled( True ) vboxLayout = QVBoxLayout( self ) hLayout = QHBoxLayout() self.__propsView = QTreeWidget() self.__propsView.setAlternatingRowColors( True ) self.__propsView.setRootIsDecorated( False ) self.__propsView.setItemsExpandable( False ) self.__propsView.setSortingEnabled( True ) self.__propsView.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) self.__propsView.itemSelectionChanged.connect( self.__propsSelectionChanged ) propsViewHeader = QTreeWidgetItem( [ "Property Name", "Property Value" ] ) self.__propsView.setHeaderItem( propsViewHeader ) self.__propsView.header().setSortIndicator( 0, Qt.DescendingOrder ) hLayout.addWidget( self.__propsView ) self.__delButton = QToolButton() self.__delButton.setText( "Delete" ) self.__delButton.setFocusPolicy( Qt.NoFocus ) self.__delButton.setEnabled( False ) self.__delButton.clicked.connect( self.__onDel ) hLayout.addWidget( self.__delButton, 0, Qt.AlignBottom ) vboxLayout.addLayout( hLayout ) # Set property part setGroupbox = QGroupBox( self ) setGroupbox.setTitle( "Set Property" ) setLayout = QGridLayout( setGroupbox ) setLayout.addWidget( QLabel( "Name" ), 0, 0, Qt.AlignTop | Qt.AlignRight ) setLayout.addWidget( QLabel( "Value" ), 1, 0, Qt.AlignTop | Qt.AlignRight ) self.__nameEdit = QLineEdit() self.__nameEdit.textChanged.connect( self.__nameChanged ) setLayout.addWidget( self.__nameEdit, 0, 1 ) self.__valueEdit = QTextEdit() self.__valueEdit.setAcceptRichText( False ) self.__valueEdit.textChanged.connect( self.__valueChanged ) metrics = QFontMetrics( self.__valueEdit.font() ) rect = metrics.boundingRect( "X" ) self.__valueEdit.setFixedHeight( rect.height() * 4 + 5 ) setLayout.addWidget( self.__valueEdit, 1, 1 ) self.__setButton = QToolButton() self.__setButton.setText( "Set" ) self.__setButton.setFocusPolicy( Qt.NoFocus ) self.__setButton.setEnabled( False ) self.__setButton.clicked.connect( self.__onSet ) setLayout.addWidget( self.__setButton, 1, 2, Qt.AlignBottom | Qt.AlignHCenter ) sizePolicy = QSizePolicy( QSizePolicy.Expanding, QSizePolicy.Maximum ) sizePolicy.setHorizontalStretch( 0 ) sizePolicy.setVerticalStretch( 0 ) sizePolicy.setHeightForWidth( setGroupbox.sizePolicy().hasHeightForWidth() ) setGroupbox.setSizePolicy( sizePolicy ) vboxLayout.addWidget( setGroupbox ) # Buttons at the bottom buttonBox = QDialogButtonBox( self ) buttonBox.setOrientation( Qt.Horizontal ) buttonBox.setStandardButtons( QDialogButtonBox.Ok ) buttonBox.button( QDialogButtonBox.Ok ).setDefault( True ) buttonBox.accepted.connect( self.close ) vboxLayout.addWidget( buttonBox ) return def __onSet( self ): " Triggered when propery set is clicked " name = self.__nameEdit.text().strip() value = self.__valueEdit.toPlainText().strip() try: commitInfo = self.__client.propset( name, value, self.__path ) if commitInfo: logging.info( str( commitInfo ) ) self.__populate() self.__plugin.notifyPathChanged( self.__path ) self.__nameEdit.clear() self.__valueEdit.clear() self.__propsView.setFocus() except pysvn.ClientError, exc: message = exc.args[ 0 ] logging.error( message ) return except Exception, exc: logging.error( str( exc ) ) return
class Preferences(QDialog): configuration = {} weight = 0 def __init__(self, parent=None): super(Preferences, self).__init__(parent, Qt.Dialog) self.setWindowTitle(translations.TR_PREFERENCES_TITLE) self.setMinimumSize(QSize(800, 600)) self.setMaximumSize(QSize(0, 0)) vbox = QVBoxLayout(self) hbox = QHBoxLayout() vbox.setContentsMargins(0, 0, 5, 5) hbox.setContentsMargins(0, 0, 0, 0) self.tree = QTreeWidget() self.tree.header().setHidden(True) self.tree.setSelectionMode(QTreeWidget.SingleSelection) self.tree.setAnimated(True) self.tree.header().setHorizontalScrollMode( QAbstractItemView.ScrollPerPixel) self.tree.header().setResizeMode(0, QHeaderView.ResizeToContents) self.tree.header().setStretchLastSection(False) self.tree.setFixedWidth(200) self.stacked = QStackedLayout() hbox.addWidget(self.tree) hbox.addLayout(self.stacked) vbox.addLayout(hbox) hbox_footer = QHBoxLayout() self._btnSave = QPushButton(translations.TR_SAVE) self._btnCancel = QPushButton(translations.TR_CANCEL) hbox_footer.addSpacerItem(QSpacerItem(1, 0, QSizePolicy.Expanding)) hbox_footer.addWidget(self._btnCancel) hbox_footer.addWidget(self._btnSave) vbox.addLayout(hbox_footer) self.connect(self.tree, SIGNAL("itemSelectionChanged()"), self._change_current) self.connect(self._btnCancel, SIGNAL("clicked()"), self.close) self.connect(self._btnSave, SIGNAL("clicked()"), self._save_preferences) self.load_ui() self.tree.setCurrentItem(self.tree.topLevelItem(0)) def _save_preferences(self): self.emit(SIGNAL("savePreferences()")) self.close() def load_ui(self): sections = sorted(list(Preferences.configuration.keys()), key=lambda item: Preferences.configuration[item]['weight']) for section in sections: text = Preferences.configuration[section]['text'] Widget = Preferences.configuration[section]['widget'] widget = Widget(self) area = QScrollArea() area.setWidgetResizable(True) area.setWidget(widget) index = self.stacked.addWidget(area) item = QTreeWidgetItem([text]) item.setData(0, Qt.UserRole, index) self.tree.addTopLevelItem(item) #Sort Item Children subcontent = Preferences.configuration[section].get( 'subsections', {}) subsections = sorted(list(subcontent.keys()), key=lambda item: subcontent[item]['weight']) for sub in subsections: text = subcontent[sub]['text'] Widget = subcontent[sub]['widget'] widget = Widget(self) area = QScrollArea() area.setWidgetResizable(True) area.setWidget(widget) index = self.stacked.addWidget(area) subitem = QTreeWidgetItem([text]) subitem.setData(0, Qt.UserRole, index) item.addChild(subitem) self.tree.expandAll() def _change_current(self): item = self.tree.currentItem() index = item.data(0, Qt.UserRole) self.stacked.setCurrentIndex(index) @classmethod def register_configuration(cls, section, widget, text, weight=None, subsection=None): if weight is None: Preferences.weight += 1 weight = Preferences.weight if not subsection: Preferences.configuration[section] = {'widget': widget, 'weight': weight, 'text': text} else: config = Preferences.configuration.get(section, {}) if not config: config[section] = {'widget': None, 'weight': 100} subconfig = config.get('subsections', {}) subconfig[subsection] = {'widget': widget, 'weight': weight, 'text': text} config['subsections'] = subconfig Preferences.configuration[section] = config
class SVNPluginStatusDialog(QDialog): " SVN Plugin status dialog " def __init__(self, statusList, parent=None): QDialog.__init__(self, parent) # Split statuses paths = [] ignoredPaths = [] for status in statusList: if status[1] == IND_IGNORED: ignoredPaths.append(status) else: paths.append(status) self.__createLayout(paths, ignoredPaths) self.setWindowTitle("SVN status") # Fill the lists for item in paths: message = "" if item[2]: message = item[2] newItem = QTreeWidgetItem(["", item[0], STATUS[item[1]], message]) pixmap = getIndicatorPixmap(item[1]) if pixmap: newItem.setIcon(0, QIcon(pixmap)) newItem.setToolTip(1, item[0]) newItem.setToolTip(2, STATUS[item[1]]) if message: newItem.setToolTip(3, message) self.__pathView.addTopLevelItem(newItem) self.__pathView.header().resizeSections(QHeaderView.ResizeToContents) self.__pathView.header().resizeSection(0, 20) self.__pathView.header().setResizeMode(QHeaderView.Fixed) for item in ignoredPaths: newItem = QTreeWidgetItem([item[0], STATUS[item[1]]]) newItem.setToolTip(0, item[0]) newItem.setToolTip(1, STATUS[item[1]]) self.__ignoredPathView.addTopLevelItem(newItem) self.__ignoredPathView.header().resizeSections( QHeaderView.ResizeToContents) return def __createLayout(self, paths, ignoredPaths): " Creates the dialog layout " self.resize(640, 420) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) # Paths to commit part vboxLayout.addWidget(QLabel("Paths (total: " + str(len(paths)) + ")")) self.__pathView = QTreeWidget() self.__pathView.setAlternatingRowColors(True) self.__pathView.setRootIsDecorated(False) self.__pathView.setItemsExpandable(False) self.__pathView.setSortingEnabled(True) self.__pathView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__pathView.setUniformRowHeights(True) self.__pathHeader = QTreeWidgetItem(["", "Path", "Status", "Message"]) self.__pathView.setHeaderItem(self.__pathHeader) self.__pathView.header().setSortIndicator(1, Qt.AscendingOrder) vboxLayout.addWidget(self.__pathView) # Paths to ignore part vboxLayout.addWidget( QLabel("Ignored paths (total: " + str(len(ignoredPaths)) + ")")) self.__ignoredPathView = QTreeWidget() self.__ignoredPathView.setAlternatingRowColors(True) self.__ignoredPathView.setRootIsDecorated(False) self.__ignoredPathView.setItemsExpandable(False) self.__ignoredPathView.setSortingEnabled(True) self.__ignoredPathView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__ignoredPathView.setUniformRowHeights(True) pathToIgnoreHeader = QTreeWidgetItem(["Path", "Status"]) self.__ignoredPathView.setHeaderItem(pathToIgnoreHeader) self.__ignoredPathView.header().setSortIndicator(0, Qt.AscendingOrder) vboxLayout.addWidget(self.__ignoredPathView) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) buttonBox.button(QDialogButtonBox.Ok).setDefault(True) buttonBox.accepted.connect(self.accept) vboxLayout.addWidget(buttonBox) return
class StackViewer( QWidget ): " Implements the stack viewer for a debugger " def __init__( self, debugger, parent = None ): QWidget.__init__( self, parent ) self.__debugger = debugger self.currentStack = None self.currentFrame = 0 self.__createPopupMenu() self.__createLayout() if Settings().showStackViewer == False: self.__onShowHide( True ) return def __createPopupMenu( self ): " Creates the popup menu " self.__framesMenu = QMenu() self.__setCurrentMenuItem = self.__framesMenu.addAction( "Set current (single click)", self.__onSetCurrent ) self.__jumpMenuItem = self.__framesMenu.addAction( "Set current and jump to the source (double click)", self.__onSetCurrentAndJump ) 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.__stackLabel = QLabel( "Stack" ) 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 frames list" ) self.__showHideButton.setFocusPolicy( Qt.NoFocus ) self.__showHideButton.clicked.connect( self.__onShowHide ) headerLayout = QHBoxLayout() headerLayout.setContentsMargins( 0, 0, 0, 0 ) headerLayout.addSpacerItem( fixedSpacer ) headerLayout.addWidget( self.__stackLabel ) headerLayout.addSpacerItem( expandingSpacer ) headerLayout.addWidget( self.__showHideButton ) self.headerFrame.setLayout( headerLayout ) self.__framesList = QTreeWidget( self ) self.__framesList.setSortingEnabled( False ) # I might not need that because of two reasons: # - the window has no focus # - the window has custom current indicator # self.__framesList.setAlternatingRowColors( True ) self.__framesList.setRootIsDecorated( False ) self.__framesList.setItemsExpandable( False ) self.__framesList.setUniformRowHeights( True ) self.__framesList.setSelectionMode( QAbstractItemView.NoSelection ) self.__framesList.setSelectionBehavior( QAbstractItemView.SelectRows ) self.__framesList.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) self.__framesList.setFocusPolicy( Qt.NoFocus ) self.__framesList.setContextMenuPolicy( Qt.CustomContextMenu ) self.__framesList.itemClicked.connect( self.__onFrameClicked ) self.__framesList.itemDoubleClicked.connect( self.__onFrameDoubleClicked ) self.__framesList.customContextMenuRequested.connect( self.__showContextMenu ) self.__framesList.setHeaderLabels( [ "", "File:line", "Function", "Full path" ] ) verticalLayout.addWidget( self.headerFrame ) verticalLayout.addWidget( self.__framesList ) return def __onShowHide( self, startup = False ): " Triggered when show/hide button is clicked " if startup or self.__framesList.isVisible(): self.__framesList.setVisible( False ) self.__showHideButton.setIcon( PixmapCache().getIcon( 'more.png' ) ) self.__showHideButton.setToolTip( "Show frames list" ) self.__minH = self.minimumHeight() self.__maxH = self.maximumHeight() self.setMinimumHeight( self.headerFrame.height() ) self.setMaximumHeight( self.headerFrame.height() ) Settings().showStackViewer = False else: self.__framesList.setVisible( True ) self.__showHideButton.setIcon( PixmapCache().getIcon( 'less.png' ) ) self.__showHideButton.setToolTip( "Hide frames list" ) self.setMinimumHeight( self.__minH ) self.setMaximumHeight( self.__maxH ) Settings().showStackViewer = True return def clear( self ): " Clears the content " self.__framesList.clear() self.currentStack = None self.__stackLabel.setText( "Stack" ) return def __resizeColumns( self ): " Resize the files list columns " self.__framesList.header().setStretchLastSection( True ) self.__framesList.header().resizeSections( QHeaderView.ResizeToContents ) self.__framesList.header().resizeSection( 0, 22 ) self.__framesList.header().setResizeMode( 0, QHeaderView.Fixed ) return def populate( self, stack ): " Sets the new call stack and selects the first item in it " self.clear() self.currentStack = stack self.currentFrame = 0 frameNumber = 0 for s in stack: if len( s ) == 2: # This is when an exception comes funcName = "" else: funcName = s[ 2 ] item = StackFrameItem( s[ 0 ], s[ 1 ], funcName, frameNumber ) self.__framesList.addTopLevelItem( item ) frameNumber += 1 self.__resizeColumns() self.__framesList.topLevelItem( 0 ).setCurrent( True ) self.__stackLabel.setText( "Stack (total: " + str( len( stack ) ) + ")" ) return def getFrameNumber( self ): " Provides the current frame number " return self.currentFrame def __onFrameClicked( self, item, column ): " Triggered when a frame is clicked " if item.isCurrent(): return # Hide the current indicator self.__framesList.topLevelItem( self.currentFrame ).setCurrent( False ) # Show the new indicator self.currentFrame = item.getFrameNumber() for index in xrange( self.__framesList.topLevelItemCount() ): item = self.__framesList.topLevelItem( index ) if item.getFrameNumber() == self.currentFrame: item.setCurrent( True ) self.__debugger.remoteClientVariables( 1, self.currentFrame ) # globals self.__debugger.remoteClientVariables( 0, self.currentFrame ) # locals return def __onFrameDoubleClicked( self, item, column ): " Triggered when a frame is double clicked " # The frame has been switched already because the double click # signal always comes after the single click one fileName = item.getFilename() lineNumber = item.getLineNumber() editorsManager = GlobalData().mainWindow.editorsManager() editorsManager.openFile( fileName, lineNumber ) editor = editorsManager.currentWidget().getEditor() editor.gotoLine( lineNumber ) editorsManager.currentWidget().setFocus() return def __showContextMenu( self, coord ): " Shows the frames list context menu " self.__contextItem = self.__framesList.itemAt( coord ) if self.__contextItem is not None: self.__setCurrentMenuItem.setEnabled( not self.__contextItem.isCurrent() ) self.__framesMenu.popup( QCursor.pos() ) return def __onSetCurrent( self ): " Context menu item handler " self.__onFrameClicked( self.__contextItem, 0 ) return def __onSetCurrentAndJump( self ): " Context menu item handler " self.__onFrameClicked( self.__contextItem, 0 ) self.__onFrameDoubleClicked( self.__contextItem, 0 ) return def switchControl( self, isInIDE ): " Switches the UI depending where the control flow is " self.__framesList.setEnabled( isInIDE ) return
class OWItemsets(widget.OWWidget): name = "Frequent Itemsets" description = "Explore sets of items that frequently appear together." icon = "icons/FrequentItemsets.svg" priority = 10 inputs = [("Data", Table, "set_data")] outputs = [(Output.DATA, Table)] minSupport = settings.Setting(30) maxItemsets = settings.Setting(10000) filterSearch = settings.Setting(True) autoFind = settings.Setting(False) autoSend = settings.Setting(True) filterKeywords = settings.Setting("") filterMinItems = settings.Setting(1) filterMaxItems = settings.Setting(10000) UserAdviceMessages = [ widget.Message( "Itemset are listed in item-sorted order, i.e. " "an itemset containing A and B is only listed once, as " "A > B (and not also B > A).", "itemsets-order", widget.Message.Warning, ), widget.Message( "To select all the itemsets that are descendants of " "(include) some item X (i.e. the whole subtree), you " "can fold the subtree at that item and then select it.", "itemsets-order", widget.Message.Information, ), ] def __init__(self): self._is_running = False self.isRegexMatch = lambda x: True self.tree = QTreeWidget( self.mainArea, columnCount=2, allColumnsShowFocus=True, alternatingRowColors=True, selectionMode=QTreeWidget.ExtendedSelection, uniformRowHeights=True, ) self.tree.setHeaderLabels(["Itemsets", "Support", "%"]) self.tree.header().setStretchLastSection(True) self.tree.itemSelectionChanged.connect(self.selectionChanged) self.mainArea.layout().addWidget(self.tree) box = gui.widgetBox(self.controlArea, "Info") self.nItemsets = self.nSelectedExamples = self.nSelectedItemsets = "" gui.label(box, self, "Number of itemsets: %(nItemsets)s") gui.label(box, self, "Selected itemsets: %(nSelectedItemsets)s") gui.label(box, self, "Selected examples: %(nSelectedExamples)s") hbox = gui.widgetBox(box, orientation="horizontal") gui.button(hbox, self, "Expand all", callback=self.tree.expandAll) gui.button(hbox, self, "Collapse all", callback=self.tree.collapseAll) box = gui.widgetBox(self.controlArea, "Find itemsets") gui.valueSlider( box, self, "minSupport", values=[0.0001, 0.0005, 0.001, 0.005, 0.01, 0.05, 0.1, 0.5] + list(range(1, 101)), label="Minimal support:", labelFormat="%g%%", callback=lambda: self.find_itemsets(), ) gui.hSlider( box, self, "maxItemsets", minValue=10000, maxValue=100000, step=10000, label="Max. number of itemsets:", labelFormat="%d", callback=lambda: self.find_itemsets(), ) self.button = gui.auto_commit(box, self, "autoFind", "Find itemsets", commit=self.find_itemsets) box = gui.widgetBox(self.controlArea, "Filter itemsets") gui.lineEdit( box, self, "filterKeywords", "Contains:", callback=self.filter_change, orientation="horizontal", tooltip="A comma or space-separated list of regular " "expressions.", ) hbox = gui.widgetBox(box, orientation="horizontal") gui.spin(hbox, self, "filterMinItems", 1, 998, label="Min. items:", callback=self.filter_change) gui.spin(hbox, self, "filterMaxItems", 2, 999, label="Max. items:", callback=self.filter_change) gui.checkBox( box, self, "filterSearch", label="Apply these filters in search", tooltip="If checked, the itemsets are filtered according " "to these filter conditions already in the search " "phase. \nIf unchecked, the only filters applied " "during search are the ones above, " "and the itemsets are \nfiltered afterwards only for " "display, i.e. only the matching itemsets are shown.", ) gui.rubber(hbox) gui.rubber(self.controlArea) gui.auto_commit(self.controlArea, self, "autoSend", "Send selection") self.filter_change() ITEM_DATA_ROLE = Qt.UserRole + 1 def selectionChanged(self): X = self.X mapping = self.onehot_mapping instances = set() where = np.where def whole_subtree(node): yield node for i in range(node.childCount()): yield from whole_subtree(node.child(i)) def itemset(node): while node: yield node.data(0, self.ITEM_DATA_ROLE) node = node.parent() def selection_ranges(node): n_children = node.childCount() if n_children: yield (self.tree.indexFromItem(node.child(0)), self.tree.indexFromItem(node.child(n_children - 1))) for i in range(n_children): yield from selection_ranges(node.child(i)) nSelectedItemsets = 0 item_selection = QItemSelection() for node in self.tree.selectedItems(): nodes = (node,) if node.isExpanded() else whole_subtree(node) if not node.isExpanded(): for srange in selection_ranges(node): item_selection.select(*srange) for node in nodes: nSelectedItemsets += 1 cols, vals = zip(*(mapping[i] for i in itemset(node))) if issparse(X): rows = (len(cols) == np.bincount((X[:, cols] != 0).indices, minlength=X.shape[0])).nonzero()[0] else: rows = where((X[:, cols] == vals).all(axis=1))[0] instances.update(rows) self.tree.itemSelectionChanged.disconnect(self.selectionChanged) self.tree.selectionModel().select(item_selection, QItemSelectionModel.Select | QItemSelectionModel.Rows) self.tree.itemSelectionChanged.connect(self.selectionChanged) self.nSelectedExamples = len(instances) self.nSelectedItemsets = nSelectedItemsets self.output = self.data[sorted(instances)] or None self.commit() def commit(self): self.send(Output.DATA, self.output) def filter_change(self): self.warning(9) try: isRegexMatch = self.isRegexMatch = re.compile( "|".join(i.strip() for i in re.split("(,|\s)+", self.filterKeywords.strip()) if i.strip()), re.IGNORECASE, ).search except Exception as e: self.warning(9, "Error in regular expression: {}".format(e.args[0])) isRegexMatch = self.isRegexMatch = lambda x: True def hide(node, depth, has_kw): if not has_kw: has_kw = isRegexMatch(node.text(0)) hidden = ( sum(hide(node.child(i), depth + 1, has_kw) for i in range(node.childCount())) == node.childCount() if node.childCount() else (not has_kw or not self.filterMinItems <= depth <= self.filterMaxItems) ) node.setHidden(hidden) return hidden hide(self.tree.invisibleRootItem(), 0, False) class TreeWidgetItem(QTreeWidgetItem): def data(self, column, role): """Construct lazy tooltips""" if role != Qt.ToolTipRole: return super().data(column, role) tooltip = [] while self: tooltip.append(self.text(0)) self = self.parent() return " ".join(reversed(tooltip)) def find_itemsets(self): if self.data is None: return if self._is_running: return self._is_running = True data = self.data self.tree.clear() self.tree.setUpdatesEnabled(False) self.tree.blockSignals(True) class ItemDict(dict): def __init__(self, item): self.item = item top = ItemDict(self.tree.invisibleRootItem()) X, mapping = OneHot.encode(data) self.onehot_mapping = mapping ITEM_FMT = "{}" if issparse(data.X) else "{}={}" names = { item: ITEM_FMT.format(var.name, val) for item, var, val in OneHot.decode(mapping.keys(), data, mapping) } nItemsets = 0 filterSearch = self.filterSearch filterMinItems, filterMaxItems = self.filterMinItems, self.filterMaxItems isRegexMatch = self.isRegexMatch # Find itemsets and populate the TreeView with self.progressBar(self.maxItemsets + 1) as progress: for itemset, support in frequent_itemsets(X, self.minSupport / 100): if filterSearch and not filterMinItems <= len(itemset) <= filterMaxItems: continue parent = top first_new_item = None itemset_matches_filter = False for item in sorted(itemset): name = names[item] if filterSearch and not itemset_matches_filter: itemset_matches_filter = isRegexMatch(name) child = parent.get(name) if child is None: try: wi = self.TreeWidgetItem( parent.item, [name, str(support), "{:.4g}".format(100 * support / len(data))] ) except RuntimeError: # FIXME: When autoFind was in effect and the support # slider was moved, this line excepted with: # RuntimeError: wrapped C/C++ object of type # TreeWidgetItem has been deleted return wi.setData(0, self.ITEM_DATA_ROLE, item) child = parent[name] = ItemDict(wi) if first_new_item is None: first_new_item = (parent, name) parent = child if filterSearch and not itemset_matches_filter: parent, name = first_new_item parent.item.removeChild(parent[name].item) del parent[name].item del parent[name] else: nItemsets += 1 progress.advance() if nItemsets >= self.maxItemsets: break if not filterSearch: self.filter_change() self.nItemsets = nItemsets self.nSelectedItemsets = 0 self.nSelectedExamples = 0 self.tree.expandAll() for i in range(self.tree.columnCount()): self.tree.resizeColumnToContents(i) self.tree.setUpdatesEnabled(True) self.tree.blockSignals(False) self._is_running = False def set_data(self, data): self.data = data is_error = False if data is not None: self.warning(0) self.error(1) self.button.setDisabled(False) self.X = data.X if issparse(data.X): self.X = data.X.tocsc() else: if not data.domain.has_discrete_attributes(): self.error(1, "Discrete features required but data has none.") is_error = True self.button.setDisabled(True) elif data.domain.has_continuous_attributes(): self.warning(0, "Data has continuous attributes which will be skipped.") else: self.output = None self.commit() if self.autoFind and not is_error: self.find_itemsets()
def __addSimilarity( self, similarity, titleText ): " Adds a similarity " # Label title = QLabel( titleText ) title.setFont( self.__headerFont ) self.__vLayout.addWidget( title ) self.__widgets.append( title ) # List of files simTable = QTreeWidget( self.bodyWidget ) simTable.setAlternatingRowColors( True ) simTable.setRootIsDecorated( False ) simTable.setItemsExpandable( False ) simTable.setSortingEnabled( False ) simTable.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) simTable.setUniformRowHeights( True ) simTable.itemActivated.connect( self.__similarityActivated ) simTable.setHeaderLabels( [ "File name", "Line" ] ) for item in similarity.files: values = [ item[ 0 ], str( item[ 1 ] ) ] simTable.addTopLevelItem( QTreeWidgetItem( values ) ) # Resizing simTable.header().resizeSections( QHeaderView.ResizeToContents ) simTable.header().setStretchLastSection( True ) # Height self.__setTableHeight( simTable ) self.__vLayout.addWidget( simTable ) self.__widgets.append( simTable ) # The fragment itself if len( similarity.fragment ) > 10: # Take first 9 lines text = "\n".join( similarity.fragment[ : 9 ] ) + "\n ..." toolTip = "\n".join( similarity.fragment ) else: text = "\n".join( similarity.fragment ) toolTip = "" fragmentLabel = QLabel( "<pre>" + self.__htmlEncode( text ) + "</pre>" ) if toolTip != "": fragmentLabel.setToolTip( "<pre>" + self.__htmlEncode( toolTip ) + "</pre>" ) palette = fragmentLabel.palette() palette.setColor( QPalette.Background, QColor( 250, 250, 175 ) ) palette.setColor( QPalette.Foreground, QColor( 0, 0, 0 ) ) fragmentLabel.setPalette( palette ) fragmentLabel.setFrameShape( QFrame.StyledPanel ) fragmentLabel.setAutoFillBackground( True ) labelFont = fragmentLabel.font() labelFont.setFamily( GlobalData().skin.baseMonoFontFace ) fragmentLabel.setFont( labelFont ) self.__vLayout.addWidget( fragmentLabel ) self.__widgets.append( fragmentLabel ) return
class OWDatabasesUpdate(OWWidget): name = "Databases update" description = "Update local system biology databases." icon = "../widgets/icons/Databases.svg" priority = 10 inputs = [] outputs = [] want_main_area = False def __init__(self, parent=None, signalManager=None, name="Databases update", domains=None): OWWidget.__init__(self, parent, signalManager, name, wantMainArea=False) self.searchString = "" self.accessCode = "" self.domains = domains or DOMAINS self.serverFiles = serverfiles.ServerFiles() self.__in_progress_update = False fbox = gui.widgetBox(self.controlArea, "Filter") # The completer model token strings self.completertokens = [] # A 'dynamic' completer item model will be updated with # 'prefix {token}' where prefix is current 'active' filter list # (the QCompleter only completes on one item in the model) self.completermodel = QStringListModel(self) self.completer = QCompleter( self.completermodel, self, caseSensitivity=Qt.CaseInsensitive ) self.lineEditFilter = QLineEdit(textChanged=self.SearchUpdate) self.lineEditFilter.setCompleter(self.completer) fbox.layout().addWidget(self.lineEditFilter) box = gui.widgetBox(self.controlArea, "Files") self.filesView = QTreeWidget(self) self.filesView.setHeaderLabels( ["", "Data Source", "Update", "Last Updated", "Size"]) self.filesView.setRootIsDecorated(False) self.filesView.setUniformRowHeights(True) self.filesView.setSelectionMode(QAbstractItemView.NoSelection) self.filesView.setSortingEnabled(True) self.filesView.sortItems(1, Qt.AscendingOrder) self.filesView.setItemDelegateForColumn( 0, UpdateOptionsItemDelegate(self.filesView)) self.filesView.model().layoutChanged.connect(self.SearchUpdate) box.layout().addWidget(self.filesView) box = gui.widgetBox(self.controlArea, orientation="horizontal") self.updateButton = gui.button( box, self, "Update all", callback=self.UpdateAll, tooltip="Update all updatable files", ) self.downloadButton = gui.button( box, self, "Download all", callback=self.DownloadFiltered, tooltip="Download all filtered files shown" ) self.cancelButton = gui.button( box, self, "Cancel", callback=self.Cancel, tooltip="Cancel scheduled downloads/updates." ) gui.rubber(box) gui.lineEdit(box, self, "accessCode", "Access Code", orientation="horizontal", callback=self.RetrieveFilesList) self.retryButton = gui.button( box, self, "Retry", callback=self.RetrieveFilesList ) self.retryButton.hide() box = gui.widgetBox(self.controlArea, orientation="horizontal") gui.rubber(box) self.infoLabel = QLabel() self.infoLabel.setAlignment(Qt.AlignCenter) self.controlArea.layout().addWidget(self.infoLabel) self.infoLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.updateItems = [] self.resize(800, 600) self.progress = ProgressState(self, maximum=3) self.progress.valueChanged.connect(self._updateProgress) self.progress.rangeChanged.connect(self._updateProgress) self.executor = ThreadExecutor( threadPool=QThreadPool(maxThreadCount=2) ) task = Task(self, function=self.RetrieveFilesList) task.exceptionReady.connect(self.HandleError) task.start() self._tasks = [] self._haveProgress = False def RetrieveFilesList(self): self.progress.setRange(0, 3) self.serverFiles = serverfiles.ServerFiles(access_code=self.accessCode) task = Task(function=partial(retrieveFilesList, self.serverFiles, self.domains, methodinvoke(self.progress, "advance"))) task.resultReady.connect(self.SetFilesList) task.exceptionReady.connect(self.HandleError) self.executor.submit(task) self.setEnabled(False) def SetFilesList(self, serverInfo): """ Set the files to show. """ self.setEnabled(True) domains = serverInfo.keys() if not domains: if self.domains: domains = self.domains else: domains = serverfiles.listdomains() localInfo = dict([(dom, serverfiles.allinfo(dom)) for dom in domains]) all_tags = set() self.filesView.clear() self.updateItems = [] for item in join_info_dict(localInfo, serverInfo): tree_item = UpdateTreeWidgetItem(item) options_widget = UpdateOptionsWidget(item.state) options_widget.item = item options_widget.installClicked.connect( partial(self.SubmitDownloadTask, item.domain, item.filename) ) options_widget.removeClicked.connect( partial(self.SubmitRemoveTask, item.domain, item.filename) ) self.updateItems.append((item, tree_item, options_widget)) all_tags.update(item.tags) self.filesView.addTopLevelItems( [tree_item for _, tree_item, _ in self.updateItems] ) for item, tree_item, options_widget in self.updateItems: self.filesView.setItemWidget(tree_item, 0, options_widget) # Add an update button if the file is updateable if item.state == OUTDATED: button = QToolButton( None, text="Update", maximumWidth=120, maximumHeight=30 ) if sys.platform == "darwin": button.setAttribute(Qt.WA_MacSmallSize) button.clicked.connect( partial(self.SubmitDownloadTask, item.domain, item.filename) ) self.filesView.setItemWidget(tree_item, 2, button) self.progress.advance() self.filesView.setColumnWidth(0, self.filesView.sizeHintForColumn(0)) for column in range(1, 4): contents_hint = self.filesView.sizeHintForColumn(column) header_hint = self.filesView.header().sectionSizeHint(column) width = max(min(contents_hint, 400), header_hint) self.filesView.setColumnWidth(column, width) hints = [hint for hint in sorted(all_tags) if not hint.startswith("#")] self.completertokens = hints self.completermodel.setStringList(hints) self.SearchUpdate() self.UpdateInfoLabel() self.toggleButtons() self.cancelButton.setEnabled(False) self.progress.setRange(0, 0) def buttonCheck(self, selected_items, state, button): for item in selected_items: if item.state != state: button.setEnabled(False) else: button.setEnabled(True) break def toggleButtons(self): selected_items = [item for item, tree_item, _ in self.updateItems if not tree_item.isHidden()] self.buttonCheck(selected_items, OUTDATED, self.updateButton) self.buttonCheck(selected_items, AVAILABLE, self.downloadButton) def HandleError(self, exception): if isinstance(exception, IOError): self.error(0, "Could not connect to server! Press the Retry " "button to try again.") self.SetFilesList({}) else: sys.excepthook(type(exception), exception.args, None) self.progress.setRange(0, 0) self.setEnabled(True) def UpdateInfoLabel(self): local = [item for item, tree_item, _ in self.updateItems if item.state != AVAILABLE and not tree_item.isHidden()] size = sum(float(item.size) for item in local) onServer = [item for item, tree_item, _ in self.updateItems if not tree_item.isHidden()] sizeOnServer = sum(float(item.size) for item in onServer) text = ("%i items, %s (on server: %i items, %s)" % (len(local), sizeof_fmt(size), len(onServer), sizeof_fmt(sizeOnServer))) self.infoLabel.setText(text) def UpdateAll(self): for item, tree_item, _ in self.updateItems: if item.state == OUTDATED and not tree_item.isHidden(): self.SubmitDownloadTask(item.domain, item.filename) def DownloadFiltered(self): # TODO: submit items in the order shown. for item, tree_item, _ in self.updateItems: if not tree_item.isHidden() and item.state in \ [AVAILABLE, OUTDATED]: self.SubmitDownloadTask(item.domain, item.filename) def _updateCompleterPrefix(self, prefix, seperator=" "): prefix = str(self.completer.completionPrefix()) tokens = self.completertokens model = self.completer.model() if not prefix.endswith(seperator) and seperator in prefix: prefix, _ = prefix.rsplit(seperator, 1) items = [prefix + seperator + item for item in tokens] else: items = tokens old = set(str(item) for item in model.stringList()) if old != set(items): model.setStringList(items) def SearchUpdate(self, searchString=None): self._updateCompleterPrefix(searchString) strings = str(self.lineEditFilter.text()).split() for item, tree_item, _ in self.updateItems: hide = not all(UpdateItem_match(item, string) for string in strings) tree_item.setHidden(hide) self.UpdateInfoLabel() self.toggleButtons() def SubmitDownloadTask(self, domain, filename): """ Submit the (domain, filename) to be downloaded/updated. """ self.cancelButton.setEnabled(True) index = self.updateItemIndex(domain, filename) _, tree_item, opt_widget = self.updateItems[index] if self.accessCode: sf = serverfiles.ServerFiles(access_code=self.accessCode) else: sf = serverfiles.ServerFiles() task = DownloadTask(domain, filename, sf) self.executor.submit(task) self.progress.adjustRange(0, 100) pb = ItemProgressBar(self.filesView) pb.setRange(0, 100) pb.setTextVisible(False) task.advanced.connect(pb.advance) task.advanced.connect(self.progress.advance) task.finished.connect(pb.hide) task.finished.connect(self.onDownloadFinished, Qt.QueuedConnection) task.exception.connect(self.onDownloadError, Qt.QueuedConnection) self.filesView.setItemWidget(tree_item, 2, pb) # Clear the text so it does not show behind the progress bar. tree_item.setData(2, Qt.DisplayRole, "") pb.show() # Disable the options widget opt_widget.setEnabled(False) self._tasks.append(task) def EndDownloadTask(self, task): future = task.future() index = self.updateItemIndex(task.domain, task.filename) item, tree_item, opt_widget = self.updateItems[index] self.filesView.removeItemWidget(tree_item, 2) opt_widget.setEnabled(True) if future.cancelled(): # Restore the previous state tree_item.setUpdateItem(item) opt_widget.setState(item.state) elif future.exception(): tree_item.setUpdateItem(item) opt_widget.setState(item.state) # Show the exception string in the size column. tree_item.setData( 2, Qt.DisplayRole, "Error occurred while downloading:" + str(future.exception()) ) else: # get the new updated info dict and replace the the old item info = serverfiles.info(item.domain, item.filename) new_item = update_item_from_info(item.domain, item.filename, info, info) self.updateItems[index] = (new_item, tree_item, opt_widget) tree_item.setUpdateItem(new_item) opt_widget.setState(new_item.state) self.UpdateInfoLabel() def SubmitRemoveTask(self, domain, filename): serverfiles.remove(domain, filename) index = self.updateItemIndex(domain, filename) item, tree_item, opt_widget = self.updateItems[index] if item.info_server: new_item = item._replace(state=AVAILABLE, local=None, info_local=None) else: new_item = item._replace(local=None, info_local=None) # Disable the options widget. No more actions can be performed # for the item. opt_widget.setEnabled(False) tree_item.setUpdateItem(new_item) opt_widget.setState(new_item.state) self.updateItems[index] = (new_item, tree_item, opt_widget) self.UpdateInfoLabel() def Cancel(self): """ Cancel all pending update/download tasks (that have not yet started). """ for task in self._tasks: task.future().cancel() def onDeleteWidget(self): self.Cancel() self.executor.shutdown(wait=False) OWWidget.onDeleteWidget(self) def onDownloadFinished(self): # on download completed/canceled/error assert QThread.currentThread() is self.thread() for task in list(self._tasks): future = task.future() if future.done(): self.EndDownloadTask(task) self._tasks.remove(task) if not self._tasks: # Clear/reset the overall progress self.progress.setRange(0, 0) self.cancelButton.setEnabled(False) def onDownloadError(self, exc_info): sys.excepthook(*exc_info) def updateItemIndex(self, domain, filename): for i, (item, _, _) in enumerate(self.updateItems): if item.domain == domain and item.filename == filename: return i raise ValueError("%r, %r not in update list" % (domain, filename)) def _updateProgress(self, *args): rmin, rmax = self.progress.range() if rmin != rmax: if not self._haveProgress: self._haveProgress = True self.progressBarInit() self.progressBarSet(self.progress.ratioCompleted() * 100) # self.progressBarSet(self.progress.ratioCompleted() * 100, # processEventsFlags=None) if rmin == rmax: self._haveProgress = False self.progressBarFinished() def progressBarSet(self, value): if not self.__in_progress_update: self.__in_progress_update = True try: OWWidget.progressBarSet(self, value) finally: self.__in_progress_update = False
class DBServersWidget(QWidget): """Displays a list of servers""" def __init__(self, parent=None): QWidget.__init__(self, parent) self.debug = False self.connections = {} self.setWindowTitle("Servers") #s#elf.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) self.mainLayout = QVBoxLayout() self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.setSpacing(0) self.setLayout(self.mainLayout) #============================================= ## Top Toolbar topBar = QToolBar() topBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.mainLayout.addWidget(topBar) ## Add the action buttons topBar.addAction(Ico.icon(Ico.ServerAdd), "Add", self.on_server_add) self.actionServerEdit = topBar.addAction(Ico.icon(Ico.ServerEdit), "Edit", self.on_server_edit) self.actionServerDelete = topBar.addAction(Ico.icon(Ico.ServerDelete), "Delete", self.on_server_delete) #============================================= ## Tree self.tree = QTreeWidget() self.mainLayout.addWidget(self.tree) self.tree.setUniformRowHeights(True) self.tree.setRootIsDecorated(True) self.tree.setHeaderLabels(["Server", "Butt"]) # set header, but hide anyway self.tree.header().hide() self.tree.header().setResizeMode(C.node, QHeaderView.Stretch) self.tree.setColumnWidth(C.butt, 20) self.connect(self.tree, SIGNAL('itemSelectionChanged()'), self.on_tree_selection_changed) self.connect(self.tree, SIGNAL('itemDoubleClicked (QTreeWidgetItem *,int)'), self.on_tree_double_clicked) self.buttGroup = QButtonGroup(self) self.connect(self.buttGroup, SIGNAL("buttonClicked(QAbstractButton*)"), self.on_open_server) self.on_tree_selection_changed() self.load_servers() #======================================= ##== Tree Events def on_tree_selection_changed(self): disabled = self.tree.selectionModel().hasSelection() == False self.actionServerEdit.setDisabled(disabled) self.actionServerDelete.setDisabled(disabled) def on_tree_double_clicked(self): self.actionServerEdit.trigger() #======================================= ## Server Actions def on_server_add(self): self.show_server_dialog(None) def on_server_edit(self): item = self.tree.currentItem() if item == None: return server = str(item.text(C.server)) self.show_server_dialog(server) def show_server_dialog(self, server=None): d = DBServerDialog.DBServerDialog(self, server) if d.exec_(): self.load_servers() def load_servers(self): """Load servers from :py:meth:`pyqtdb.XSettings.XSettings.get_servers` """ self.tree.clear() for butt in self.buttGroup.buttons(): self.buttGroup.removeButton(butt) for srv in G.settings.get_servers_list(): item = QTreeWidgetItem() item.setText(C.node, srv['server']) #item.setText(C.user, srv['user']) self.tree.addTopLevelItem(item) butt = QToolButton() butt.setIcon(Ico.icon(Ico.Connect)) butt.setProperty("server", srv['server']) self.tree.setItemWidget(item, C.butt, butt) self.buttGroup.addButton(butt) def on_server_delete(self): item = self.tree.currentItem() if item == None: return srv = str(item.text(C.server)) G.settings.delete_server(srv) self.load_servers() def on_open_server(self, butt): # self.emit(SIGNAL("open_server"), butt.property("server").toString()) srv_ki = str(butt.property("server").toString()) server = G.settings.get_server(srv_ki) db = QSqlDatabase.addDatabase("QMYSQL", srv_ki) db.setHostName(server['server']) db.setUserName(server['user']) db.setPassword(server['passwd']) ok = db.open() if ok: #self.connections[srv_ki] = self.load_databases(srv_ki) print "open", ok def load_databases(self, srv_ki): """Load databases into tree node for server; executes 'show databases;' or aslike """ sql = "show databases;" query = QSqlQuery(QSqlDatabase.database(srv_ki)) ok = query.exec_(sql) print ok, sql, query.result() # Get the parent node, ie the server node pItem = self.tree.findItems(srv_ki, Qt.MatchExactly, C.node)[0] ## Assumed value(0) is the table.. we need the defs (ie mysql case) while query.next(): table_name = query.value(0).toString() nuItem = QTreeWidgetItem(pItem) nuItem.setText(C.node, table_name) #print table_name self.tree.setItemExpanded(pItem, True)
class VersionSelectDialog( QDialog ): def __init__( self, parent ): # initialize the super class super( VersionSelectDialog, self ).__init__( parent ) # create the tree self.uiVersionsTREE = QTreeWidget(self) self.uiVersionsTREE.setAlternatingRowColors(True) self.uiVersionsTREE.setRootIsDecorated(False) self.uiVersionsTREE.setSelectionMode( self.uiVersionsTREE.NoSelection ) header = self.uiVersionsTREE.header() header.setVisible(False) # create the layout layout = QVBoxLayout() layout.addWidget(self.uiVersionsTREE) layout.setContentsMargins(0,0,0,0) # inherit the highlight palette palette = self.palette() palette.setColor(palette.Highlight,parent.palette().color(palette.Highlight)) self.setPalette(palette) # set dialog information self.setLayout(layout) self.setWindowFlags( Qt.Popup ) self.resize(500,250) # create connections self.uiVersionsTREE.itemClicked.connect( self.acceptItem ) def closeEvent( self, event ): # update all the items for this for i in range( self.uiVersionsTREE.topLevelItemCount() ): item = self.uiVersionsTREE.topLevelItem(i) widget = item.versionWidget() version = widget.version() # match the active state version.setActive(widget.isActive()) super(VersionSelectDialog,self).closeEvent(event) def acceptItem( self, item ): # handle version change information widget = item.versionWidget() widget.toggleActive() # accept the dialog self.close() def popup( self, versions ): self.uiVersionsTREE.setUpdatesEnabled(False) self.uiVersionsTREE.blockSignals(True) self.uiVersionsTREE.clear() for version in versions: item = VersionItem(self.uiVersionsTREE, version) self.uiVersionsTREE.addTopLevelItem( item ) self.uiVersionsTREE.setItemWidget( item, 0, item.versionWidget() ) # reset the scrolling self.uiVersionsTREE.verticalScrollBar().setValue(0) self.uiVersionsTREE.setUpdatesEnabled(True) self.uiVersionsTREE.blockSignals(False) return self.exec_()
def __init__(self, callback): super().__init__() self.callback = callback self.setMinimumSize(QSize(210, 200)) self.setMaximumSize(QSize(210, 16777215)) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) self.lockresource = False numbervalidator = QIntValidator(0, 999) #Rom info and emulator emulator = QPushButton("Start Emulator", self) #Map/bank select buttons column_left_layout = QVBoxLayout(self) column_left_layout.setContentsMargins(0, 0, 0, 0); column_left_layout.setSpacing(2) mapinput_l = QLabel('Map:', self) mapinput_f = QLineEdit(self) mapinput_f.setValidator(numbervalidator) bankinput_l = QLabel('Bank:', self) bankinput_f = QLineEdit(self) bankinput_f.setValidator(numbervalidator) button_load = QPushButton(self) button_load.setText("Load scripts") #Select element on the map view select_script = QTreeWidget(self) select_script.setColumnCount(2) select_script.setHeaderHidden(True) select_script.header().resizeSection(0, 160) select_script.header().resizeSection(1, 20) select_script.setStyleSheet("outline: 0;") select_script.setFocusPolicy(Qt.NoFocus) select_script.setSelectionMode(QAbstractItemView.ExtendedSelection) resources_l = QLabel("Script resources:", self) resourceselector = QListWidget(self) resourceselector.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) column_left_layout.addWidget(emulator) column_left_layout.addWidget(bankinput_l) column_left_layout.addWidget(bankinput_f) column_left_layout.addWidget(mapinput_l) column_left_layout.addWidget(mapinput_f) column_left_layout.addWidget(button_load) column_left_layout.addWidget(select_script) column_left_layout.addWidget(resources_l) column_left_layout.addWidget(resourceselector) #Finally connect proper signals button_load.clicked.connect(self.maploadclick) select_script.itemSelectionChanged.connect(self.itemselected) resourceselector.itemSelectionChanged.connect(self.resourceselected) emulator.clicked.connect(self.emulate) #Keep some elements for local thingy self.mapinput = mapinput_f self.bankinput = bankinput_f self.scriptselect = select_script self.resourceselector = resourceselector
class StackViewer(QWidget): " Implements the stack viewer for a debugger " def __init__(self, debugger, parent=None): QWidget.__init__(self, parent) self.__debugger = debugger self.currentStack = None self.currentFrame = 0 self.__createPopupMenu() self.__createLayout() if Settings().showStackViewer == False: self.__onShowHide(True) return def __createPopupMenu(self): " Creates the popup menu " self.__framesMenu = QMenu() self.__setCurrentMenuItem = self.__framesMenu.addAction( "Set current (single click)", self.__onSetCurrent) self.__jumpMenuItem = self.__framesMenu.addAction( "Set current and jump to the source (double click)", self.__onSetCurrentAndJump) 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.__stackLabel = QLabel("Stack") 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 frames list") self.__showHideButton.setFocusPolicy(Qt.NoFocus) self.__showHideButton.clicked.connect(self.__onShowHide) headerLayout = QHBoxLayout() headerLayout.setContentsMargins(0, 0, 0, 0) headerLayout.addSpacerItem(fixedSpacer) headerLayout.addWidget(self.__stackLabel) headerLayout.addSpacerItem(expandingSpacer) headerLayout.addWidget(self.__showHideButton) self.headerFrame.setLayout(headerLayout) self.__framesList = QTreeWidget(self) self.__framesList.setSortingEnabled(False) # I might not need that because of two reasons: # - the window has no focus # - the window has custom current indicator # self.__framesList.setAlternatingRowColors( True ) self.__framesList.setRootIsDecorated(False) self.__framesList.setItemsExpandable(False) self.__framesList.setUniformRowHeights(True) self.__framesList.setSelectionMode(QAbstractItemView.NoSelection) self.__framesList.setSelectionBehavior(QAbstractItemView.SelectRows) self.__framesList.setItemDelegate(NoOutlineHeightDelegate(4)) self.__framesList.setFocusPolicy(Qt.NoFocus) self.__framesList.setContextMenuPolicy(Qt.CustomContextMenu) self.__framesList.itemClicked.connect(self.__onFrameClicked) self.__framesList.itemDoubleClicked.connect( self.__onFrameDoubleClicked) self.__framesList.customContextMenuRequested.connect( self.__showContextMenu) self.__framesList.setHeaderLabels( ["", "File:line", "Function", "Full path"]) verticalLayout.addWidget(self.headerFrame) verticalLayout.addWidget(self.__framesList) return def __onShowHide(self, startup=False): " Triggered when show/hide button is clicked " if startup or self.__framesList.isVisible(): self.__framesList.setVisible(False) self.__showHideButton.setIcon(PixmapCache().getIcon('more.png')) self.__showHideButton.setToolTip("Show frames list") self.__minH = self.minimumHeight() self.__maxH = self.maximumHeight() self.setMinimumHeight(self.headerFrame.height()) self.setMaximumHeight(self.headerFrame.height()) Settings().showStackViewer = False else: self.__framesList.setVisible(True) self.__showHideButton.setIcon(PixmapCache().getIcon('less.png')) self.__showHideButton.setToolTip("Hide frames list") self.setMinimumHeight(self.__minH) self.setMaximumHeight(self.__maxH) Settings().showStackViewer = True return def clear(self): " Clears the content " self.__framesList.clear() self.currentStack = None self.__stackLabel.setText("Stack") return def __resizeColumns(self): " Resize the files list columns " self.__framesList.header().setStretchLastSection(True) self.__framesList.header().resizeSections(QHeaderView.ResizeToContents) self.__framesList.header().resizeSection(0, 22) self.__framesList.header().setResizeMode(0, QHeaderView.Fixed) return def populate(self, stack): " Sets the new call stack and selects the first item in it " self.clear() self.currentStack = stack self.currentFrame = 0 frameNumber = 0 for s in stack: if len(s) == 2: # This is when an exception comes funcName = "" else: funcName = s[2] item = StackFrameItem(s[0], s[1], funcName, frameNumber) self.__framesList.addTopLevelItem(item) frameNumber += 1 self.__resizeColumns() self.__framesList.topLevelItem(0).setCurrent(True) self.__stackLabel.setText("Stack (total: " + str(len(stack)) + ")") return def getFrameNumber(self): " Provides the current frame number " return self.currentFrame def __onFrameClicked(self, item, column): " Triggered when a frame is clicked " if item.isCurrent(): return # Hide the current indicator self.__framesList.topLevelItem(self.currentFrame).setCurrent(False) # Show the new indicator self.currentFrame = item.getFrameNumber() for index in xrange(self.__framesList.topLevelItemCount()): item = self.__framesList.topLevelItem(index) if item.getFrameNumber() == self.currentFrame: item.setCurrent(True) self.__debugger.remoteClientVariables(1, self.currentFrame) # globals self.__debugger.remoteClientVariables(0, self.currentFrame) # locals return def __onFrameDoubleClicked(self, item, column): " Triggered when a frame is double clicked " # The frame has been switched already because the double click # signal always comes after the single click one fileName = item.getFilename() lineNumber = item.getLineNumber() editorsManager = GlobalData().mainWindow.editorsManager() editorsManager.openFile(fileName, lineNumber) editor = editorsManager.currentWidget().getEditor() editor.gotoLine(lineNumber) editorsManager.currentWidget().setFocus() return def __showContextMenu(self, coord): " Shows the frames list context menu " self.__contextItem = self.__framesList.itemAt(coord) if self.__contextItem is not None: self.__setCurrentMenuItem.setEnabled( not self.__contextItem.isCurrent()) self.__framesMenu.popup(QCursor.pos()) return def __onSetCurrent(self): " Context menu item handler " self.__onFrameClicked(self.__contextItem, 0) return def __onSetCurrentAndJump(self): " Context menu item handler " self.__onFrameClicked(self.__contextItem, 0) self.__onFrameDoubleClicked(self.__contextItem, 0) return def switchControl(self, isInIDE): " Switches the UI depending where the control flow is " self.__framesList.setEnabled(isInIDE) return