def on_copy(self): select_group_dialog = QDialog(self) select_group_dialog.setWindowTitle(self.tr("Choose source group")) layout = QVBoxLayout(select_group_dialog) select_group_dialog.setLayout(layout) groups_list_view = QTableView(self) layout.addWidget(groups_list_view) groups_list_view.setModel(self.ds_model) groups_list_view.setColumnHidden(DSManagerModel.COLUMN_VISIBILITY, True) groups_list_view.horizontalHeader().setResizeMode(DSManagerModel.COLUMN_GROUP_DS, QHeaderView.Stretch) groups_list_view.setSelectionMode(QTableView.NoSelection) groups_list_view.setAlternatingRowColors(True) groups_list_view.setShowGrid(False) groups_list_view.verticalHeader().setResizeMode(QHeaderView.ResizeToContents) groups_list_view.verticalHeader().hide() groups_list_view.clicked.connect( lambda index: select_group_dialog.accept() \ if self.ds_model.isGroup(index) and \ index.column() == DSManagerModel.COLUMN_GROUP_DS \ else None ) if select_group_dialog.exec_() == QDialog.Accepted: group_info = self.ds_model.data(groups_list_view.currentIndex(), Qt.UserRole) group_info.id += "_copy" edit_dialog = GroupEditDialog() edit_dialog.setWindowTitle(self.tr('Create group from existing')) edit_dialog.fill_group_info(group_info) if edit_dialog.exec_() == QDialog.Accepted: self.feel_list() self.ds_model.resetModel()
class DataFrameWidget(QWidget): ''' a simple widget for using DataFrames in a gui ''' def __init__(self, name='DataFrameTable1', parent=None): super(DataFrameWidget, self).__init__(parent) self.name = name self.dataModel = DataFrameModel() self.dataModel.setDataFrame(DataFrame()) self.dataTable = QTableView() self.dataTable.setSelectionBehavior(QAbstractItemView.SelectRows) self.dataTable.setSortingEnabled(True) self.dataTable.setModel(self.dataModel) self.dataModel.signalUpdate() #self.dataTable.setFont(QFont("Courier New", 8)) layout = QVBoxLayout() layout.addWidget(self.dataTable) self.setLayout(layout) def setFormat(self, fmt): """ set non-default string formatting for a column """ for colName, f in fmt.iteritems(): self.dataModel.columnFormat[colName] = f def fitColumns(self): self.dataTable.horizontalHeader().setResizeMode(QHeaderView.Stretch) def setDataFrame(self, df): self.dataModel.setDataFrame(df) def resizeColumnsToContents(self): self.dataTable.resizeColumnsToContents()
def showPeakTable(self): """ TODO: write little function to check if sample is None or good or write exception with good code """ if not self.view.sampleTableView.selectedIndexes():#not self.acTree.selectedIndexes(): s, b = QInputDialog.getItem(self.view, "Select one sample", "Select one sample :", [spl.shortName() for spl in self.model]) if not b: return sample = self.model.sample(str(s), fullNameEntry=False) else: idx = self.view.sampleTableView.selectedIndexes()[0] sample = self.model.sample(idx.data().toString(), fullNameEntry=False) if sample is None: print ("sample not found...") return if not sample.rawPeaks: self.view.showErrorMessage("No peaks found", "This sample does not have peaks, please do peak picking before") view=QTableView() view.horizontalHeader().setStretchLastSection(True) view.setSortingEnabled(True) model=MSDialogController.getSampleModel(sample, flags='peak') view.setModel(model) self.view.addMdiSubWindow(view, " ".join(["PeakList of", str(sample.shortName())]))
def showPeakTable(self): """ TODO: write little function to check if sample is None or good or write exception with good code """ if not self.view.sampleTableView.selectedIndexes( ): #not self.acTree.selectedIndexes(): s, b = QInputDialog.getItem( self.view, "Select one sample", "Select one sample :", [spl.shortName() for spl in self.model]) if not b: return sample = self.model.sample(str(s), fullNameEntry=False) else: idx = self.view.sampleTableView.selectedIndexes()[0] sample = self.model.sample(idx.data().toString(), fullNameEntry=False) if sample is None: print("sample not found...") return if not sample.rawPeaks: self.view.showErrorMessage( "No peaks found", "This sample does not have peaks, please do peak picking before" ) view = QTableView() view.horizontalHeader().setStretchLastSection(True) view.setSortingEnabled(True) model = MSDialogController.getSampleModel(sample, flags='peak') view.setModel(model) self.view.addMdiSubWindow( view, " ".join(["PeakList of", str(sample.shortName())]))
class ConfSettingsWidget ( QWidget ): def __init__ ( self, conf, parent=None ): QWidget.__init__( self, parent ) self._rowHeight = 20 self._view = QTableView() self._view.setShowGrid ( False ) self._view.setAlternatingRowColors( True ) self._view.setSelectionBehavior ( QAbstractItemView.SelectRows ) #self._view.setSortingEnabled ( True ) #self._view.installEventFilter ( self ) horizontalHeader = self._view.horizontalHeader () horizontalHeader.setStretchLastSection ( True ) horizontalHeader.setMinimumSectionSize ( 150 ) horizontalHeader.setResizeMode ( QHeaderView.ResizeToContents ) horizontalHeader.setDefaultSectionSize ( 150 ) verticalHeader = self._view.verticalHeader (); verticalHeader.setVisible ( False ); verticalHeader.setDefaultSectionSize ( self._rowHeight ); self._baseModel = ConfSettingsModel( conf ) self._view.setModel( self._baseModel ); self._view.horizontalHeader().setStretchLastSection( True ); self._view.resizeColumnToContents( 0 ); peanoDataLayout = QGridLayout(); peanoDataLayout.addWidget( self._view, 0, 0, 1, 1 ); self.setLayout ( peanoDataLayout ); return
def showClusterTable(self): if not self.view.sampleTableView.selectedIndexes( ): #not self.acTree.selectedIndexes(): s, b = QInputDialog.getItem( self.view, "Select one sample", "Select one sample :", [spl.shortName() for spl in self.model]) if not b: return sample = self.model.sample(str(s), fullNameEntry=False) else: idx = self.view.sampleTableView.selectedIndexes()[0] sample = self.model.sample(idx.data().toString(), fullNameEntry=False) if sample is None: print("sample not found...") return if not sample.mappedPeaks: self.view.showErrorMessage( "No peaks found", "This sample does not have peaks, please do peak picking before" ) view = QTableView() view.setSortingEnabled(True) view.horizontalHeader().setStretchLastSection(True) view.setModel( MSDialogController.getSampleModel(sample, flags='cluster')) self.view.addMdiSubWindow(view, "ClusterList of%s" % str(sample.shortName()))
def __init__(self, parent=None): super(TableWidget, self).__init__(parent) # Create a simple model for storing data. model = CustomTableModel() # Create the table view and add the model to it. tableView = QTableView() tableView.setModel(model) tableView.horizontalHeader().setResizeMode(QHeaderView.Stretch) tableView.verticalHeader().setResizeMode(QHeaderView.Stretch) chart = QChart() chart.setAnimationOptions(QChart.AllAnimations) # Series 1. series = QLineSeries() series.setName("Line 1") mapper = QVXYModelMapper(self) mapper.setXColumn(0) mapper.setYColumn(1) mapper.setSeries(series) mapper.setModel(model) chart.addSeries(series) # Get the color of the series and use it for showing the mapped area. seriesColorHex = '#' + hex(series.pen().color().rgb()).upper()[-6:] model.addMapping(seriesColorHex, QRect(0, 0, 2, model.rowCount())) # Series 2. series = QLineSeries() series.setName("Line 2") mapper = QVXYModelMapper(self) mapper.setXColumn(2) mapper.setYColumn(3) mapper.setSeries(series) mapper.setModel(model) chart.addSeries(series) # Get the color of the series and use it for showing the mapped area. seriesColorHex = '#' + hex(series.pen().color().rgb()).upper()[-6:] model.addMapping(seriesColorHex, QRect(2, 0, 2, model.rowCount())) chart.createDefaultAxes() chartView = QChartView(chart) chartView.setRenderHint(QPainter.Antialiasing) chartView.setMinimumSize(640, 480) # Create the main layout. mainLayout = QGridLayout() mainLayout.addWidget(tableView, 1, 0) mainLayout.addWidget(chartView, 1, 1) mainLayout.setColumnStretch(1, 1) mainLayout.setColumnStretch(0, 0) self.setLayout(mainLayout)
def __init__(self, parent=None): super(TableWidget, self).__init__(parent) # Create a simple model for storing data. model = CustomTableModel() # Create the table view and add the model to it. tableView = QTableView() tableView.setModel(model) tableView.setMinimumWidth(300) tableView.horizontalHeader().setResizeMode(QHeaderView.Stretch) tableView.verticalHeader().setResizeMode(QHeaderView.Stretch) chart = QChart() chart.setAnimationOptions(QChart.AllAnimations) # Series 1. series = QBarSeries() first = 3 count = 5 mapper = QVBarModelMapper(self) mapper.setFirstBarSetColumn(1) mapper.setLastBarSetColumn(4) mapper.setFirstRow(first) mapper.setRowCount(count) mapper.setSeries(series) mapper.setModel(model) chart.addSeries(series) # Get the color of the series and use it for showing the mapped area. for i, barset in enumerate(series.barSets()): seriesColorHex = '#' + hex( barset.brush().color().rgb()).upper()[-6:] model.addMapping(seriesColorHex, QRect(1 + i, first, 1, barset.count())) categories = ["April", "May", "June", "July", "August"] axis = QBarCategoriesAxis(chart) axis.append(categories) chart.createDefaultAxes() chart.setAxisX(axis, series) chartView = QChartView(chart) chartView.setRenderHint(QPainter.Antialiasing) chartView.setMinimumSize(640, 480) # Create the main layout. mainLayout = QGridLayout() mainLayout.addWidget(tableView, 1, 0) mainLayout.addWidget(chartView, 1, 1) mainLayout.setColumnStretch(1, 1) mainLayout.setColumnStretch(0, 0) self.setLayout(mainLayout)
def createTable(self): # create the view tv = QTableView() self.param = self.createParam() # set the delegate to allow editing table entries self.td = SpinBoxDelegate(self.param.traits.xslot) tv.setItemDelegate(self.td) tm = ParamTableModel(self.createParam(), self) tv.setModel(tm) # set the minimum size tv.setMinimumSize(400, 300) # hide grid tv.setShowGrid(False) # set the font font = QFont("Courier New", 8) tv.setFont(font) # hide horizontal header hh = tv.horizontalHeader() hh.setVisible(False) # set vertical header properties vh = tv.verticalHeader() #vh.setStretchLastSection(True) # set column width to fit contents tv.resizeColumnsToContents() return tv
class Window(QWidget): def __init__(self, parent = None): QWidget.__init__(self, parent) self.table = QTableView() self.imageTable = QTableView() delegate = PixelDelegate(self) self.imageTable.setItemDelegate(delegate) self.imageTable.horizontalHeader().hide() self.imageTable.verticalHeader().hide() self.imageTable.setShowGrid(False) self.imageCombo = QComboBox() self.imageCombo.addItem("Dream", QVariant(":/Pictures/dream.png")) self.imageCombo.addItem("Teapot", QVariant(":/Pictures/teapot.png")) gridCheckBox = QCheckBox(self.tr("Show grid:")) gridCheckBox.setCheckState(Qt.Unchecked) self.connect(self.imageCombo, SIGNAL("currentIndexChanged(int)"), self.setModel) self.connect(gridCheckBox, SIGNAL("toggled(bool)"), self.imageTable, SLOT("setShowGrid(bool)")) self.imageCombo.setCurrentIndex(1) layout = QGridLayout() layout.addWidget(self.imageTable, 0, 0, 1, 2) layout.addWidget(self.table, 0, 2, 1, 2) layout.addWidget(gridCheckBox, 1, 0) layout.addWidget(self.imageCombo, 1, 1) self.setLayout(layout) def setModel(self, row): image = QImage(self.imageCombo.itemData(row).toString()) model = ImageModel(image, self) self.table.setModel(model) self.imageTable.setModel(model) for row in range(model.rowCount(QModelIndex())): self.imageTable.resizeRowToContents(row) for column in range(model.columnCount(QModelIndex())): self.imageTable.resizeColumnToContents(column)
class ProblemDialog(QDialog): def __init__(self, parent, model): flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint QDialog.__init__(self, parent, flags) self._setupUi() self.model = model self.model.view = self self.table = ProblemTable(self.model.problem_table, view=self.tableView) self.revealButton.clicked.connect(self.model.reveal_selected_dupe) self.closeButton.clicked.connect(self.accept) def _setupUi(self): self.setWindowTitle(tr("Problems!")) self.resize(413, 323) self.verticalLayout = QVBoxLayout(self) self.label = QLabel(self) msg = tr("There were problems processing some (or all) of the files. The cause of " "these problems are described in the table below. Those files were not " "removed from your results.") self.label.setText(msg) self.label.setWordWrap(True) self.verticalLayout.addWidget(self.label) self.tableView = QTableView(self) self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tableView.setSelectionMode(QAbstractItemView.SingleSelection) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.setShowGrid(False) self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.verticalHeader().setDefaultSectionSize(18) self.tableView.verticalHeader().setHighlightSections(False) self.verticalLayout.addWidget(self.tableView) self.horizontalLayout = QHBoxLayout() self.revealButton = QPushButton(self) self.revealButton.setText(tr("Reveal Selected")) self.horizontalLayout.addWidget(self.revealButton) spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem) self.closeButton = QPushButton(self) self.closeButton.setText(tr("Close")) self.closeButton.setDefault(True) self.horizontalLayout.addWidget(self.closeButton) self.verticalLayout.addLayout(self.horizontalLayout)
class DataFrameWidget(QWidget): ''' a simple widget for using DataFrames in a gui ''' def __init__(self,name='DataFrameTable1', parent=None): super(DataFrameWidget,self).__init__(parent) self.name = name self.dataModel = DataFrameModel() self.dataModel.setDataFrame(DataFrame()) self.dataTable = QTableView() #self.dataTable.setSelectionBehavior(QAbstractItemView.SelectRows) self.dataTable.setSortingEnabled(True) self.dataTable.setModel(self.dataModel) self.dataModel.signalUpdate() #self.dataTable.setFont(QFont("Courier New", 8)) layout = QVBoxLayout() layout.addWidget(self.dataTable) self.setLayout(layout) def setFormat(self,fmt): """ set non-default string formatting for a column """ for colName, f in fmt.iteritems(): self.dataModel.columnFormat[colName]=f def fitColumns(self): self.dataTable.horizontalHeader().setResizeMode(QHeaderView.Stretch) def setDataFrame(self,df): self.dataModel.setDataFrame(df) def resizeColumnsToContents(self): self.dataTable.resizeColumnsToContents() def insertRow(self,index, data=None): self.dataModel.appendRow(index,data)
def showClusterTable(self): if not self.view.sampleTableView.selectedIndexes():#not self.acTree.selectedIndexes(): s, b = QInputDialog.getItem(self.view, "Select one sample", "Select one sample :", [spl.shortName() for spl in self.model]) if not b: return sample = self.model.sample(str(s), fullNameEntry=False) else: idx = self.view.sampleTableView.selectedIndexes()[0] sample = self.model.sample(idx.data().toString(), fullNameEntry=False) if sample is None: print ("sample not found...") return if not sample.mappedPeaks: self.view.showErrorMessage("No peaks found", "This sample does not have peaks, please do peak picking before") view= QTableView() view.setSortingEnabled(True) view.horizontalHeader().setStretchLastSection(True) view.setModel(MSDialogController.getSampleModel(sample, flags='cluster')) self.view.addMdiSubWindow(view, "ClusterList of%s"%str(sample.shortName()))
class IgnoreListDialog(QDialog): def __init__(self, parent, model): flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint QDialog.__init__(self, parent, flags) self._setupUi() self.model = model self.model.view = self self.table = IgnoreListTable(self.model.ignore_list_table, view=self.tableView) self.removeSelectedButton.clicked.connect(self.model.remove_selected) self.clearButton.clicked.connect(self.model.clear) self.closeButton.clicked.connect(self.accept) def _setupUi(self): self.setWindowTitle(tr("Ignore List")) self.resize(540, 330) self.verticalLayout = QVBoxLayout(self) self.tableView = QTableView() self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.setShowGrid(False) self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.verticalHeader().setDefaultSectionSize(18) self.tableView.verticalHeader().setHighlightSections(False) self.tableView.verticalHeader().setVisible(False) self.verticalLayout.addWidget(self.tableView) self.removeSelectedButton = QPushButton(tr("Remove Selected")) self.clearButton = QPushButton(tr("Clear")) self.closeButton = QPushButton(tr("Close")) self.verticalLayout.addLayout( horizontalWrap([ self.removeSelectedButton, self.clearButton, None, self.closeButton ])) #--- model --> view def show(self): QDialog.show(self)
def createTable(self, header, tabledata): """creates a table""" gridlayout2 = QGridLayout(self) gridlayout2.setObjectName("gridlayout2") tableView = QTableView(self) tableView.setObjectName("tableView") gridlayout2.addWidget(tableView, 0, 0, 1, 1) self.__popUp = QMenu(tableView) self.__copyAction = QAction(self.tr("Copy data"), tableView) self.connect(self.__copyAction, SIGNAL("triggered()"), self.copy) self.__popUp.addAction(self.__copyAction) tableView.setContextMenuPolicy(Qt.CustomContextMenu) self.connect(tableView, SIGNAL('customContextMenuRequested(QPoint)'), self.popUpMenu) # set the table model tm = TableModel(tabledata, header, self) tableView.setModel(tm) tableView.setAlternatingRowColors(True) # set the minimum size self.setMinimumSize(400, 300) # hide grid tableView.setShowGrid(True) # set the font #font = QFont("Courier New", 12) #self.tableView.setFont(font) # hide vertical header vh = tableView.verticalHeader() vh.setVisible(True) # set horizontal header properties hh = tableView.horizontalHeader() hh.setStretchLastSection(True) # set column width to fit contents tableView.resizeColumnsToContents() tableView.setSortingEnabled(True) tableView.sortByColumn(0, Qt.AscendingOrder) # set row height nrows = len(tabledata) for row in xrange(nrows): tableView.setRowHeight(row, 18)
class PositionWindow(QMainWindow): WA_Maemo5StackedWindow = 127 WA_Maemo5PortraitOrientation = 128 WA_Maemo5LandscapeOrientation = 129 ''' @param transactionModel - TransactionModel ''' def __init__(self, parent, exchange, ticker, transactionModel): QMainWindow.__init__(self, parent) self.prop = MaeMoneyProperties.instance() self.setupUi(exchange, ticker, transactionModel) def setupUi(self, exchange, ticker, transactionModel): self.setWindowTitle("%s:%s" %(exchange, ticker)) widget = QWidget(self) self.setCentralWidget(widget) self.layout = QVBoxLayout() widget.setLayout(self.layout) self.transactTableView = QTableView(self) self.transactTableView.setSelectionBehavior(QAbstractItemView.SelectRows) header = self.transactTableView.horizontalHeader() header.setResizeMode(QHeaderView.ResizeToContents) self.transactTableView.setHorizontalHeader(header) self.transactTableView.setModel(transactionModel) self.transactTableView.resizeRowsToContents() self.transactTableView.resizeColumnsToContents() header.setStretchLastSection(True) self.layout.addWidget(self.transactTableView) self.setOrientation() self.setAttributeAndCatch(self.WA_Maemo5StackedWindow, True) def setAttributeAndCatch(self, attribute, trueFalse): try: self.setAttribute(attribute, trueFalse) except AttributeError: qDebug("Can't set attribute %d" %(attribute)) def setOrientation(self): if self.prop.isPortraitMode(): self.setAttributeAndCatch(self.WA_Maemo5PortraitOrientation, True) self.setAttributeAndCatch(self.WA_Maemo5LandscapeOrientation, False) else: self.setAttributeAndCatch(self.WA_Maemo5LandscapeOrientation, True) self.setAttributeAndCatch(self.WA_Maemo5PortraitOrientation, False)
def on_copy(self): select_group_dialog = QDialog(self) select_group_dialog.resize(300, 400) select_group_dialog.setWindowTitle(self.tr("Choose source group")) layout = QVBoxLayout(select_group_dialog) select_group_dialog.setLayout(layout) groups_list_view = QTableView(self) layout.addWidget(groups_list_view) groups_list_view.setModel(self.ds_model) groups_list_view.setColumnHidden(DSManagerModel.COLUMN_VISIBILITY, True) groups_list_view.horizontalHeader().setResizeMode( DSManagerModel.COLUMN_GROUP_DS, QHeaderView.Stretch) groups_list_view.setSelectionMode(QTableView.NoSelection) groups_list_view.setAlternatingRowColors(True) groups_list_view.setShowGrid(False) groups_list_view.verticalHeader().setResizeMode( QHeaderView.ResizeToContents) groups_list_view.verticalHeader().hide() groups_list_view.clicked.connect( lambda index: select_group_dialog.accept() \ if self.ds_model.isGroup(index) and \ index.column() == DSManagerModel.COLUMN_GROUP_DS \ else None ) if select_group_dialog.exec_() == QDialog.Accepted: group_info = self.ds_model.data(groups_list_view.currentIndex(), Qt.UserRole) group_info.id += "_copy" edit_dialog = GroupEditDialog() edit_dialog.setWindowTitle(self.tr('Create group from existing')) edit_dialog.fill_group_info(group_info) if edit_dialog.exec_() == QDialog.Accepted: self.feel_list() self.ds_model.resetModel()
class IgnoreListDialog(QDialog): def __init__(self, parent, model): flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint QDialog.__init__(self, parent, flags) self._setupUi() self.model = model self.model.view = self self.table = IgnoreListTable(self.model.ignore_list_table, view=self.tableView) self.removeSelectedButton.clicked.connect(self.model.remove_selected) self.clearButton.clicked.connect(self.model.clear) self.closeButton.clicked.connect(self.accept) def _setupUi(self): self.setWindowTitle(tr("Ignore List")) self.resize(540, 330) self.verticalLayout = QVBoxLayout(self) self.tableView = QTableView() self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.setShowGrid(False) self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.verticalHeader().setDefaultSectionSize(18) self.tableView.verticalHeader().setHighlightSections(False) self.tableView.verticalHeader().setVisible(False) self.verticalLayout.addWidget(self.tableView) self.removeSelectedButton = QPushButton(tr("Remove Selected")) self.clearButton = QPushButton(tr("Clear")) self.closeButton = QPushButton(tr("Close")) self.verticalLayout.addLayout(horizontalWrap([self.removeSelectedButton, self.clearButton, None, self.closeButton])) #--- model --> view def show(self): QDialog.show(self)
def createTable(self): # create the view tableview = QTableView() # set table model tablemodel = ArrayDataTableModel(self.savedValue, self.liveValue, self) tableview.setModel(tablemodel) # hide vertical header vh = tableview.verticalHeader() vh.setVisible(False) # set horizontal header properties hh = tableview.horizontalHeader() hh.setStretchLastSection(True) # set column width to fit contents tableview.resizeColumnsToContents() # enable sorting # does not work # tableview.setSortingEnabled(True) return tableview
class FreezeTableWidget(QTableView): def __init__(self, table_data, headers, parent=None, *args): """ Creates two QTableViews one of which is a frozen table while the other one can scroll behind it. :param table_data: The data that goes into the tables :type table_data: List :param headers: The header data of the tables. :type headers: List :param parent: The parent of the QTableView :type parent: QWidget :param args: :type args: """ QTableView.__init__(self, parent) # set the table model self.table_model = BaseSTDMTableModel(table_data, headers, parent) # set the proxy model proxy_model = QSortFilterProxyModel(self) proxy_model.setSourceModel(self.table_model) # Assign a data model for TableView self.setModel(self.table_model) # frozen_table_view - first column self.frozen_table_view = QTableView(self) # Set the model for the widget, fixed column self.frozen_table_view.setModel(self.table_model) # Hide row headers self.frozen_table_view.verticalHeader().hide() # Widget does not accept focus self.frozen_table_view.setFocusPolicy(Qt.StrongFocus | Qt.TabFocus | Qt.ClickFocus) # The user can not resize columns self.frozen_table_view.horizontalHeader().\ setResizeMode(QHeaderView.Fixed) self.frozen_table_view.setObjectName('frozen_table') self.setSelectionMode(QAbstractItemView.NoSelection) self.set_style() # Remove the scroll bar self.frozen_table_view.setHorizontalScrollBarPolicy( Qt.ScrollBarAlwaysOff) self.frozen_table_view.setVerticalScrollBarPolicy( Qt.ScrollBarAlwaysOff) # Puts more widgets to the foreground self.viewport().stackUnder(self.frozen_table_view) # # Log in to edit mode - even with one click # Set the properties of the column headings hh = self.horizontalHeader() # Text alignment centered hh.setDefaultAlignment(Qt.AlignCenter) self.set_column_width() # Set properties header lines vh = self.verticalHeader() vh.setDefaultSectionSize(25) # height lines # text alignment centered vh.setDefaultAlignment(Qt.AlignCenter) vh.setVisible(True) # Height of rows - as in the main widget self.frozen_table_view.verticalHeader().\ setDefaultSectionSize( vh.defaultSectionSize() ) # Show frozen table view self.frozen_table_view.show() # Set the size of him like the main self.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) self.frozen_table_view.setVerticalScrollMode( QAbstractItemView.ScrollPerPixel) ## select the first column (STR Type) self.frozen_table_view.selectColumn(0) self.frozen_table_view.setEditTriggers( QAbstractItemView.AllEditTriggers) self.set_size() self.signals() def set_size(self): """ Sets the size and size policy of the tables. :return: :rtype: """ size_policy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(size_policy) self.setMinimumSize(QSize(55, 75)) self.setMaximumSize(QSize(5550, 5555)) self.SelectionMode(QAbstractItemView.SelectColumns) # set column width to fit contents self.frozen_table_view.resizeColumnsToContents() # set row height self.frozen_table_view.resizeRowsToContents() def signals(self): """ Connects signals of the tables. """ # Connect the headers and scrollbars of # both tableviews together self.horizontalHeader().sectionResized.connect( self.update_section_width) self.verticalHeader().sectionResized.connect( self.update_section_height) self.frozen_table_view.verticalScrollBar(). \ valueChanged.connect( self.verticalScrollBar().setValue ) self.verticalScrollBar().valueChanged.connect( self.frozen_table_view.verticalScrollBar().setValue) def set_column_width(self): """ Sets the column width of the frozen QTableView. """ # Set the width of columns columns_count = self.table_model.columnCount(self) for col in range(columns_count): if col == 0: # Set the size self.horizontalHeader().resizeSection(col, 60) # Fix width self.horizontalHeader().setResizeMode(col, QHeaderView.Fixed) # Width of a fixed column - as in the main widget self.frozen_table_view.setColumnWidth(col, self.columnWidth(col)) elif col == 1: self.horizontalHeader().resizeSection(col, 150) self.horizontalHeader().setResizeMode(col, QHeaderView.Fixed) self.frozen_table_view.setColumnWidth(col, self.columnWidth(col)) else: self.horizontalHeader().resizeSection(col, 150) # Hide unnecessary columns in the # widget fixed columns self.frozen_table_view.setColumnHidden(col, True) def set_style(self): """ Sets the style of the frozen table. """ # Style frozentable view self.frozen_table_view.setStyleSheet(''' #frozen_table{ border-top:none; } ''') self.shadow = QGraphicsDropShadowEffect(self) self.shadow.setBlurRadius(5) self.shadow.setOffset(2) self.shadow.setYOffset(0) self.frozen_table_view.setGraphicsEffect(self.shadow) def add_widgets(self, str_type_id, insert_row): """ Adds widget delete into the frozen table. :param str_type_id: The STR type id of the tenure type combobox :type str_type_id: Integer :param insert_row: The row number the widgets to be added. :type insert_row: Integer """ delegate = STRTypeDelegate(str_type_id) # Set delegate to add combobox under # social tenure type column self.frozen_table_view.setItemDelegate(delegate) self.frozen_table_view.setItemDelegateForColumn(0, delegate) index = self.frozen_table_view.model().index(insert_row, 0, QModelIndex()) self.frozen_table_view.model().setData(index, '', Qt.EditRole) self.frozen_table_view.openPersistentEditor( self.frozen_table_view.model().index(insert_row, 0)) self.frozen_table_view.openPersistentEditor( self.frozen_table_view.model().index(insert_row, 1)) def update_section_width(self, logicalIndex, oldSize, newSize): """ Updates frozen table column width and geometry. :param logicalIndex: The section's logical number :type logicalIndex: Integer :param oldSize: The old size of the section :type oldSize: Integer :param newSize: The new size of the section :type newSize: Integer """ if logicalIndex == 0 or logicalIndex == 1: self.frozen_table_view.setColumnWidth(logicalIndex, newSize) self.update_frozen_table_geometry() def update_section_height(self, logicalIndex, oldSize, newSize): """ Updates frozen table column height. :param logicalIndex: The section's logical number :type logicalIndex: Integer :param oldSize: The old size of the section :type oldSize: Integer :param newSize: The new size of the section :type newSize: Integer """ self.frozen_table_view.setRowHeight(logicalIndex, newSize) def resizeEvent(self, event): """ Handles the resize event of the frozen table view. It updates the frozen table view geometry on resize of table. :param event: The event :type event: QEvent """ QTableView.resizeEvent(self, event) try: self.update_frozen_table_geometry() except Exception as log: LOGGER.debug(str(log)) def scrollTo(self, index, hint): """ Scrolls the view if necessary to ensure that the item at index is visible. The view will try to position the item according to the given hint. :param index: The scroll index :type index: QModelIndex :param hint: The scroll hint :type hint: Integer """ if index.column() > 1: QTableView.scrollTo(self, index, hint) def update_frozen_table_geometry(self): """ Updates the frozen table view geometry. """ if self.verticalHeader().isVisible(): self.frozen_table_view.setGeometry( self.verticalHeader().width() + self.frameWidth(), self.frameWidth(), self.columnWidth(0) + self.columnWidth(1), self.viewport().height() + self.horizontalHeader().height()) else: self.frozen_table_view.setGeometry( self.frameWidth(), self.frameWidth(), self.columnWidth(0) + self.columnWidth(1), self.viewport().height() + self.horizontalHeader().height()) def move_cursor(self, cursor_action, modifiers): """ Override function for correct left to scroll the keyboard. Returns a QModelIndex object pointing to the next object in the table view, based on the given cursorAction and keyboard modifiers specified by modifiers. :param cursor_action: The cursor action :type cursor_action: Integer :param modifiers: Qt.KeyboardModifier value. :type modifiers: Object :return: The current cursor position. :rtype: QModelIndex """ current = QTableView.move_cursor(self, cursor_action, modifiers) if cursor_action == self.MoveLeft and current.column() > 1 and \ self.visualRect(current).topLeft().x() < \ (self.frozen_table_view.columnWidth(0) + self.frozen_table_view.columnWidth(1)): new_value = self.horizontalScrollBar().value() + \ self.visualRect(current).topLeft().x() - \ (self.frozen_table_view.columnWidth(0) + self.frozen_table_view.columnWidth(1)) self.horizontalScrollBar().setValue(new_value) return current
class I4CheckWindow(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.setup_model() self.tableview = QTableView() self.tableview.setSelectionMode(QAbstractItemView.NoSelection) self.tableview.setEditTriggers(QAbstractItemView.DoubleClicked) self.cbdelegate = CheckBoxDelegate() self.tableview.setItemDelegate(self.cbdelegate) self.tableview.setAutoScroll(False) self.tableview.setModel(self.model) self.tableview.sortByColumn(0, Qt.AscendingOrder) self.adjust_headers() #self.model.setHeaderData(0, Qt.Horizontal, u"") #self.model.setHeaderData(1, Qt.Horizontal, u"Title") self.radio_all = QRadioButton("All") self.radio_all.setChecked(True) self.radio_need = QRadioButton("Need") self.connect(self.radio_all, SIGNAL("toggled(bool)"), self.set_show_all) label = QLabel("DB:") label.setFixedWidth(40) label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.db_combo = QComboBox() self.populate_db_combo() self.connect( self.db_combo, SIGNAL("currentIndexChanged(int)"), self.db_index_changed) self.new_button = QPushButton("New") self.connect(self.new_button, SIGNAL("clicked()"), self.new_item) self.box = QVBoxLayout(self) self.box.addWidget(self.tableview) self.button_box = QHBoxLayout() self.button_box.setSpacing(0) self.button_box.addWidget(self.new_button) self.button_box.addWidget(self.radio_all) self.button_box.addWidget(self.radio_need) self.button_box.addWidget(label) self.button_box.addWidget(self.db_combo) self.box.addLayout(self.button_box) # self.setStyleSheet(""" # QComboBox { # font-size: 16px; # } # """) self.dwim_after_load() def dwim_after_load(self): if self.model.need_anything(): self.radio_need.setChecked(True) return self.radio_all.setChecked(True) if self.model.model.rowCount() == 0: edit_index = self.model.new() self.tableview.setCurrentIndex(edit_index) self.tableview.scrollTo(edit_index) self.tableview.edit(edit_index) def adjust_headers(self): log.debug("adjust_sizes()") self.tableview.horizontalHeader().setResizeMode(0, QHeaderView.Stretch) self.tableview.setColumnWidth(0, 1) self.tableview.verticalHeader().setDefaultSectionSize(ITEM_HEIGHT) self.tableview.verticalHeader().hide() self.tableview.horizontalHeader().hide() def setup_model(self): self.model = CheckListModel() def new_item(self): index = self.model.new() self.tableview.setCurrentIndex(index) self.tableview.resizeRowToContents(index.row()) self.tableview.scrollTo(index) self.tableview.edit(index) def set_show_all(self, show_all): if self.model.show_all == show_all: return self.model.set_show_all(show_all) self.tableview.resizeRowsToContents() def save(self): self.model.save() def checkout(self): if QMessageBox.question( self, "Checkout", "Are you sure you want to check out?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == \ QMessageBox.Yes: self.model.checkout() def reset_items(self): if QMessageBox.question( self, "Checkout", "Are you sure you want to reset the list?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == \ QMessageBox.Yes: self.model.reset_items() self.radio_all.setChecked(True) def delete_database(self): if QMessageBox.question( self, "Delete database", "Are you sure you want to delete the current database?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == \ QMessageBox.Yes: self.model.delete_database() self.populate_db_combo() self.dwim_after_load() _loading_db_combo = False def populate_db_combo(self): self._loading_db_combo = True try: self.db_combo.clear() for db_name in self.model.databases: self.db_combo.addItem(re.sub("\\.org$", "", db_name), db_name) self.db_combo.addItem("New database...", "") self.db_combo.setCurrentIndex( self.model.databases.index(self.model.current_db)) finally: self._loading_db_combo = False def db_index_changed(self, index): if self._loading_db_combo: return db_name = str(self.db_combo.itemData(index).toPyObject()) if db_name == self.model.current_db: return self.model.save() if db_name: self.model.load(db_name) self.dwim_after_load() return db_name, ok = QInputDialog.getText( self, "New Database", "Enter database name") if ok: if not re.match(r"^[\w-]+$", db_name): QMessageBox.critical( self, "Error", "Database name must contain only the following chars: " "A-Z a-z 0-9 _ -") ok = False elif db_name in self.model.databases: QMessageBox.critical( self, "Error", "Database '%s' already exists" % db_name) ok = False if not ok: self.db_combo.setCurrentIndex( self.model.databases.index(self.model.current_db)) return db_name = str(db_name) + ".org" self.model.load(db_name) self.populate_db_combo() self.dwim_after_load()
def set_dataset(self, data, tid=None): """Set the input dataset.""" if data is not None: if tid in self.inputs: # update existing input slot slot = self.inputs[tid] view = slot.view # reset the (header) view state. view.setModel(None) view.horizontalHeader().setSortIndicator(-1, Qt.AscendingOrder) else: view = QTableView() view.setSelectionBehavior(QTableView.SelectRows) view.setSortingEnabled(True) view.setHorizontalScrollMode(QTableView.ScrollPerPixel) header = view.horizontalHeader() header.setMovable(True) header.setClickable(True) header.setSortIndicatorShown(True) header.setSortIndicator(-1, Qt.AscendingOrder) # QHeaderView does not 'reset' the model sort column, # because there is no guaranty (requirement) that the # models understand the -1 sort column. def sort_reset(index, order): if view.model() is not None and index == -1: view.model().sort(index, order) header.sortIndicatorChanged.connect(sort_reset) view.dataset = data self.tabs.addTab(view, getattr(data, "name", "Data")) self._setup_table_view(view, data) slot = TableSlot(tid, data, table_summary(data), view) view._input_slot = slot self.inputs[tid] = slot self.tabs.setCurrentIndex(self.tabs.indexOf(view)) self.set_info(slot.summary) if isinstance(slot.summary.len, concurrent.futures.Future): def update(f): QMetaObject.invokeMethod( self, "_update_info", Qt.QueuedConnection) slot.summary.len.add_done_callback(update) elif tid in self.inputs: slot = self.inputs.pop(tid) view = slot.view view.hide() view.deleteLater() self.tabs.removeTab(self.tabs.indexOf(view)) current = self.tabs.currentWidget() if current is not None: self.set_info(current._input_slot.summary) self.tabs.tabBar().setVisible(self.tabs.count() > 1)
class TalkEditorApp(FreeseerApp): '''Freeseer talk database editor main gui class''' def __init__(self, config, db): FreeseerApp.__init__(self) self.config = config self.db = db icon = QIcon() icon.addPixmap(QPixmap(':/freeseer/logo.png'), QIcon.Normal, QIcon.Off) self.setWindowIcon(icon) self.resize(960, 600) # # Setup Layout # self.mainWidget = QWidget() self.mainLayout = QVBoxLayout() self.mainWidget.setLayout(self.mainLayout) self.setCentralWidget(self.mainWidget) self.mainLayout.setAlignment(QtCore.Qt.AlignTop) # Add the Title Row (Use BOLD / Big Font) #self.titleLayout = QHBoxLayout() #self.backButton = QPushButton('Back to Recorder') #if backButton: # Only show the back button if requested by caller # self.titleLayout.addWidget(self.backButton) #self.titleLayout.addStretch() # Add custom widgets self.commandButtons = CommandButtons() self.tableView = QTableView() self.tableView.setSortingEnabled(True) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.talkDetailsWidget = TalkDetailsWidget() self.importTalksWidget = ImportTalksWidget() self.mainLayout.addWidget(self.importTalksWidget) #self.mainLayout.addLayout(self.titleLayout) self.mainLayout.addWidget(self.commandButtons) self.mainLayout.addWidget(self.tableView) self.mainLayout.addWidget(self.talkDetailsWidget) self.mainLayout.addWidget(self.importTalksWidget) # --- End Layout # Initialize geometry, to be used for restoring window positioning. self.geometry = None # # Setup Menubar # self.actionExportCsv = QAction(self) self.actionExportCsv.setObjectName('actionExportCsv') self.actionRemoveAll = QAction(self) self.actionRemoveAll.setObjectName('actionRemoveAll') # Actions self.menuFile.insertAction(self.actionExit, self.actionExportCsv) self.menuFile.insertAction(self.actionExit, self.actionRemoveAll) # --- End Menubar # # TableView Connections # self.connect(self.tableView, SIGNAL('activated(const QModelIndex)'), self.talk_selected) self.connect(self.tableView, SIGNAL('selected(const QModelIndex)'), self.talk_selected) self.connect(self.tableView, SIGNAL('clicked(const QModelIndex)'), self.talk_selected) # Import Widget self.connect(self.importTalksWidget.csvRadioButton, SIGNAL('toggled(bool)'), self.toggle_import) self.connect(self.importTalksWidget.importButton, SIGNAL('clicked()'), self.import_talks) self.connect(self.importTalksWidget.cancelButton, SIGNAL('clicked()'), self.hide_import_talks_widget) self.importTalksWidget.setHidden(True) self.connect(self.importTalksWidget.csvFileSelectButton, QtCore.SIGNAL('clicked()'), self.csv_file_select) self.connect(self.importTalksWidget.csvLineEdit, QtCore.SIGNAL('returnPressed()'), self.importTalksWidget.importButton.click) self.connect(self.importTalksWidget.rssLineEdit, QtCore.SIGNAL('returnPressed()'), self.importTalksWidget.importButton.click) self.connect(self.actionExportCsv, QtCore.SIGNAL('triggered()'), self.export_talks_to_csv) self.connect(self.actionRemoveAll, QtCore.SIGNAL('triggered()'), self.confirm_reset) # Command Buttons self.connect(self.commandButtons.removeButton, SIGNAL('clicked()'), self.remove_talk) self.connect(self.commandButtons.removeAllButton, SIGNAL('clicked()'), self.confirm_reset) self.connect(self.commandButtons.importButton, SIGNAL('clicked()'), self.show_import_talks_widget) self.connect(self.commandButtons.exportButton, SIGNAL('clicked()'), self.export_talks_to_csv) self.connect(self.commandButtons.searchButton, SIGNAL('clicked()'), self.search_talks) self.connect(self.commandButtons.searchLineEdit, SIGNAL('textEdited(QString)'), self.search_talks) self.connect(self.commandButtons.searchLineEdit, SIGNAL('returnPressed()'), self.search_talks) # Talk Details Buttons self.connect(self.talkDetailsWidget.addButton, SIGNAL('clicked()'), self.confirm_add) self.connect(self.talkDetailsWidget.saveButton, SIGNAL('clicked()'), self.add_talk) # Load default language actions = self.menuLanguage.actions() for action in actions: if action.data().toString() == self.config.default_language: action.setChecked(True) self.translate(action) break # Load Talk Database self.load_presentations_model() # Setup Autocompletion self.update_autocomple_fields() # Select first item #self.tableView.setCurrentIndex(self.proxy.index(0,0)) #self.talk_selected(self.proxy.index(0,0)) # # Translation # def retranslate(self): self.setWindowTitle(self.app.translate("TalkEditorApp", "Freeseer Talk Editor")) # # Reusable Strings # self.confirmDBClearTitleString = self.app.translate("TalkEditorApp", "Remove All Talks from Database") self.confirmDBClearQuestionString = self.app.translate("TalkEditorApp", "Are you sure you want to clear the DB?") self.confirmTalkDetailsClearTitleString = self.app.translate("TalkEditorApp", "Unsaved Data") self.confirmTalkDetailsClearQuestionString = self.app.translate("TalkEditorApp", "Unsaved talk details will be lost. Continue?") # --- End Reusable Strings # # Menubar # self.actionExportCsv.setText(self.app.translate("TalkEditorApp", "&Export to CSV")) self.actionRemoveAll.setText(self.app.translate("TalkEditorApp", "&Remove All Talks")) # --- End Menubar # # TalkDetailsWidget # self.talkDetailsWidget.titleLabel.setText(self.app.translate("TalkEditorApp", "Title")) self.talkDetailsWidget.presenterLabel.setText(self.app.translate("TalkEditorApp", "Presenter")) self.talkDetailsWidget.categoryLabel.setText(self.app.translate("TalkEditorApp", "Category")) self.talkDetailsWidget.eventLabel.setText(self.app.translate("TalkEditorApp", "Event")) self.talkDetailsWidget.roomLabel.setText(self.app.translate("TalkEditorApp", "Room")) self.talkDetailsWidget.dateLabel.setText(self.app.translate("TalkEditorApp", "Date")) self.talkDetailsWidget.timeLabel.setText(self.app.translate("TalkEditorApp", "Time")) # --- End TalkDetailsWidget # # Import Talks Widget Translations # self.importTalksWidget.rssRadioButton.setText(self.app.translate("TalkEditorApp", "RSS URL")) self.importTalksWidget.csvRadioButton.setText(self.app.translate("TalkEditorApp", "CSV File")) self.importTalksWidget.importButton.setText(self.app.translate("TalkEditorApp", "Import")) # --- End Talks Widget Translations # # Command Button Translations\ # #self.commandButtons.addButton.setText(self.app.translate("TalkEditorApp", "Add")) self.commandButtons.importButton.setText(self.app.translate("TalkEditorApp", "Import")) self.commandButtons.exportButton.setText(self.app.translate("TalkEditorApp", "Export")) self.commandButtons.removeButton.setText(self.app.translate("TalkEditorApp", "Remove")) self.commandButtons.removeAllButton.setText(self.app.translate("TalkEditorApp", "Remove All")) # --- End Command Butotn Translations # # Search Widget Translations # self.commandButtons.searchButton.setText(self.app.translate("TalkEditorApp", "Search")) # --- End Command Button Translations def load_presentations_model(self): # Load Presentation Model self.presentationModel = self.db.get_presentations_model() self.proxy = QSortFilterProxyModel() self.proxy.setSourceModel(self.presentationModel) self.tableView.setModel(self.proxy) self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) # Fill table whitespace. self.tableView.horizontalHeader().setStretchLastSection(False) self.tableView.horizontalHeader().setResizeMode(1, QHeaderView.Stretch) # Hide the ID field self.tableView.setColumnHidden(0, True) # Map data to widgets self.mapper = QDataWidgetMapper() self.mapper.setModel(self.proxy) self.mapper.addMapping(self.talkDetailsWidget.titleLineEdit, 1) self.mapper.addMapping(self.talkDetailsWidget.presenterLineEdit, 2) self.mapper.addMapping(self.talkDetailsWidget.categoryLineEdit, 4) self.mapper.addMapping(self.talkDetailsWidget.eventLineEdit, 5) self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6) self.mapper.addMapping(self.talkDetailsWidget.descriptionTextEdit, 3) self.mapper.addMapping(self.talkDetailsWidget.dateEdit, 7) self.mapper.addMapping(self.talkDetailsWidget.timeEdit, 8) # Load StringLists self.titleList = QStringList(self.db.get_string_list("Title")) #self.speakerList = QStringList(self.db.get_speaker_list()) #self.categoryList = QStringList(self.db.get_category_list()) #self.eventList = QStringList(self.db.get_event_list()) #self.roomList = QStringList(self.db.get_room_list()) #Disble input self.talkDetailsWidget.disable_input_fields() def search_talks(self): # The default value is 0. If the value is -1, the keys will be read from all columns. self.proxy.setFilterKeyColumn(-1) self.proxy.setFilterFixedString(self.commandButtons.searchLineEdit.text()) def talk_selected(self, model): self.talkDetailsWidget.saveButton.setEnabled(False) self.mapper.setCurrentIndex(model.row()) self.talkDetailsWidget.enable_input_fields() def toggle_import(self): if self.importTalksWidget.csvRadioButton.isChecked(): self.importTalksWidget.csvLineEdit.setEnabled(True) self.importTalksWidget.csvFileSelectButton.setEnabled(True) self.importTalksWidget.rssLineEdit.setEnabled(False) else: self.importTalksWidget.csvLineEdit.setEnabled(False) self.importTalksWidget.csvFileSelectButton.setEnabled(False) self.importTalksWidget.rssLineEdit.setEnabled(True) def show_import_talks_widget(self): self.commandButtons.setHidden(True) self.tableView.setHidden(True) self.talkDetailsWidget.setHidden(True) self.importTalksWidget.setHidden(False) def hide_import_talks_widget(self): self.commandButtons.setHidden(False) self.tableView.setHidden(False) self.talkDetailsWidget.setHidden(False) self.importTalksWidget.setHidden(True) def add_talk(self): date = self.talkDetailsWidget.dateEdit.date() time = self.talkDetailsWidget.timeEdit.time() #datetime = QtCore.QDateTime(date, time) presentation = Presentation( unicode(self.talkDetailsWidget.titleLineEdit.text()).strip(), unicode(self.talkDetailsWidget.presenterLineEdit.text()).strip(), unicode(self.talkDetailsWidget.descriptionTextEdit.toPlainText()).strip(), unicode(self.talkDetailsWidget.categoryLineEdit.text()).strip(), unicode(self.talkDetailsWidget.eventLineEdit.text()).strip(), unicode(self.talkDetailsWidget.roomLineEdit.text()).strip(), unicode(date.toString(QtCore.Qt.ISODate)), unicode(time.toString(QtCore.Qt.ISODate))) # Do not add talks if they are empty strings if (len(presentation.title) == 0): return self.db.insert_presentation(presentation) # Update Model, Refreshes TableView self.presentationModel.select() # Select Last Row self.tableView.selectRow(self.presentationModel.rowCount() - 1) self.tableView.setCurrentIndex(self.proxy.index(self.proxy.rowCount() - 1, 0)) self.talk_selected(self.proxy.index(self.proxy.rowCount() - 1, 0)) self.update_autocomple_fields() self.talkDetailsWidget.disable_input_fields() def confirm_add(self): """Requests confirmation before clearing fields for a new talk.""" if self.are_fields_enabled() and self.unsaved_details_exist(): confirm = QMessageBox.question(self, self.confirmTalkDetailsClearTitleString, self.confirmTalkDetailsClearQuestionString, QMessageBox.Yes, QMessageBox.No) if confirm == QMessageBox.Yes: self.clear_talk_details_widget() else: self.clear_talk_details_widget() def clear_talk_details_widget(self): self.talkDetailsWidget.saveButton.setEnabled(True) self.talkDetailsWidget.enable_input_fields() self.talkDetailsWidget.titleLineEdit.clear() self.talkDetailsWidget.presenterLineEdit.clear() self.talkDetailsWidget.descriptionTextEdit.clear() self.talkDetailsWidget.categoryLineEdit.clear() #self.talkDetailsWidget.eventLineEdit.clear() #self.talkDetailsWidget.roomLineEdit.clear() self.presentationModel.select() def remove_talk(self): try: rows_selected = self.tableView.selectionModel().selectedRows() except: return # Reversed because rows in list change position once row is removed for row in reversed(rows_selected): self.presentationModel.removeRow(row.row()) def load_talk(self): try: self.tableView.currentIndex().row() except: return self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6) self.presentationModel.select() def reset(self): self.db.clear_database() self.presentationModel.select() def confirm_reset(self): """Presents a confirmation dialog to ask the user if they are sure they wish to remove the talk database. If Yes call the reset() function""" confirm = QMessageBox.question(self, self.confirmDBClearTitleString, self.confirmDBClearQuestionString, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if confirm == QMessageBox.Yes: self.reset() def add_talks_from_rss(self): rss_url = unicode(self.importTalksWidget.rssLineEdit.text()) if rss_url: self.db.add_talks_from_rss(rss_url) self.presentationModel.select() self.hide_import_talks_widget() else: error = QMessageBox() error.setText("Please enter a RSS URL") error.exec_() def closeEvent(self, event): log.info('Exiting talk database editor...') self.geometry = self.saveGeometry() event.accept() def csv_file_select(self): fname = QFileDialog.getOpenFileName( self, 'Select file', "", "*.csv") if fname: self.importTalksWidget.csvLineEdit.setText(fname) def add_talks_from_csv(self): fname = self.importTalksWidget.csvLineEdit.text() if fname: self.db.add_talks_from_csv(fname) self.presentationModel.select() self.hide_import_talks_widget() else: error = QMessageBox() error.setText("Please select a file") error.exec_() def import_talks(self): if self.importTalksWidget.csvRadioButton.isChecked(): self.add_talks_from_csv() else: self.add_talks_from_rss() self.update_autocomple_fields() def export_talks_to_csv(self): fname = QFileDialog.getSaveFileName(self, 'Select file', "", "*.csv") if fname: self.db.export_talks_to_csv(fname) def update_autocomple_fields(self): self.titleList = QStringList(self.db.get_string_list("Title")) self.speakerList = QStringList(self.db.get_string_list("Speaker")) self.categoryList = QStringList(self.db.get_string_list("Category")) self.eventList = QStringList(self.db.get_string_list("Event")) self.roomList = QStringList(self.db.get_string_list("Room")) self.titleCompleter = QCompleter(self.titleList) self.titleCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.speakerCompleter = QCompleter(self.speakerList) self.speakerCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.categoryCompleter = QCompleter(self.categoryList) self.categoryCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.eventCompleter = QCompleter(self.eventList) self.eventCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.roomCompleter = QCompleter(self.roomList) self.roomCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.talkDetailsWidget.titleLineEdit.setCompleter(self.titleCompleter) self.talkDetailsWidget.presenterLineEdit.setCompleter(self.speakerCompleter) self.talkDetailsWidget.categoryLineEdit.setCompleter(self.categoryCompleter) self.talkDetailsWidget.eventLineEdit.setCompleter(self.eventCompleter) self.talkDetailsWidget.roomLineEdit.setCompleter(self.roomCompleter) def are_fields_enabled(self): return (self.talkDetailsWidget.titleLineEdit.isEnabled() and self.talkDetailsWidget.presenterLineEdit.isEnabled() and self.talkDetailsWidget.categoryLineEdit.isEnabled() and self.talkDetailsWidget.eventLineEdit.isEnabled() and self.talkDetailsWidget.roomLineEdit.isEnabled() and self.talkDetailsWidget.dateEdit.isEnabled() and self.talkDetailsWidget.timeEdit.isEnabled()) def unsaved_details_exist(self): """Checks if details exist for a new talk Looks for text in the input fields and check the enabled state of the Save Talk button If the Save Talk button is enabled, the input fields contain values for a new talk Otherwise, the input fields contain values for an existing selected talk """ return (self.talkDetailsWidget.saveButton.isEnabled() and (self.talkDetailsWidget.titleLineEdit.text() or self.talkDetailsWidget.presenterLineEdit.text() or self.talkDetailsWidget.categoryLineEdit.text() or self.talkDetailsWidget.descriptionTextEdit.toPlainText()))
class FreezeTableWidget(QTableView): def __init__( self, table_data, headers, parent = None, *args ): """ Creates two QTableViews one of which is a frozen table while the other one can scroll behind it. :param table_data: The data that goes into the tables :type table_data: List :param headers: The header data of the tables. :type headers: List :param parent: The parent of the QTableView :type parent: QWidget :param args: :type args: """ QTableView.__init__(self, parent) # set the table model self.table_model = BaseSTDMTableModel( table_data, headers, parent ) # set the proxy model proxy_model = QSortFilterProxyModel(self) proxy_model.setSourceModel(self.table_model) # Assign a data model for TableView self.setModel(self.table_model) # frozen_table_view - first column self.frozen_table_view = QTableView(self) # Set the model for the widget, fixed column self.frozen_table_view.setModel(self.table_model) # Hide row headers self.frozen_table_view.verticalHeader().hide() # Widget does not accept focus self.frozen_table_view.setFocusPolicy( Qt.StrongFocus|Qt.TabFocus|Qt.ClickFocus ) # The user can not resize columns self.frozen_table_view.horizontalHeader().\ setResizeMode(QHeaderView.Fixed) self.frozen_table_view.setObjectName('frozen_table') self.setSelectionMode(QAbstractItemView.NoSelection) # Remove the scroll bar self.frozen_table_view.setHorizontalScrollBarPolicy( Qt.ScrollBarAlwaysOff ) self.frozen_table_view.setVerticalScrollBarPolicy( Qt.ScrollBarAlwaysOff ) # Puts more widgets to the foreground self.viewport().stackUnder(self.frozen_table_view) # # Log in to edit mode - even with one click # Set the properties of the column headings hh = self.horizontalHeader() # Text alignment centered hh.setDefaultAlignment(Qt.AlignCenter) self.set_column_width() # Set properties header lines vh = self.verticalHeader() vh.setDefaultSectionSize(25) # height lines # text alignment centered vh.setDefaultAlignment(Qt.AlignCenter) vh.setVisible(True) # Height of rows - as in the main widget self.frozen_table_view.verticalHeader().\ setDefaultSectionSize( vh.defaultSectionSize() ) # Show frozen table view self.frozen_table_view.show() # Set the size of him like the main self.setHorizontalScrollMode( QAbstractItemView.ScrollPerPixel ) self.setVerticalScrollMode( QAbstractItemView.ScrollPerPixel ) self.frozen_table_view.setVerticalScrollMode( QAbstractItemView.ScrollPerPixel ) ## select the first column (STR Type) self.frozen_table_view.selectColumn(0) self.frozen_table_view.setEditTriggers( QAbstractItemView.AllEditTriggers ) self.set_size() self.signals() def set_size(self): """ Sets the size and size policy of the tables. :return: :rtype: """ size_policy = QSizePolicy( QSizePolicy.Fixed, QSizePolicy.Fixed ) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth( self.sizePolicy().hasHeightForWidth() ) self.setSizePolicy(size_policy) self.setMinimumSize(QSize(55, 75)) self.setMaximumSize(QSize(5550, 5555)) self.SelectionMode( QAbstractItemView.SelectColumns ) # set column width to fit contents self.frozen_table_view.resizeColumnsToContents() # set row height self.frozen_table_view.resizeRowsToContents() def signals(self): """ Connects signals of the tables. """ # Connect the headers and scrollbars of # both tableviews together self.horizontalHeader().sectionResized.connect( self.update_section_width ) self.verticalHeader().sectionResized.connect( self.update_section_height ) self.frozen_table_view.verticalScrollBar().valueChanged.connect( self.verticalScrollBar().setValue ) self.verticalScrollBar().valueChanged.connect( self.frozen_table_view.verticalScrollBar().setValue ) def set_column_width(self): """ Sets the column width of the frozen QTableView. """ # Set the width of columns columns_count = self.table_model.columnCount(self) for col in range(columns_count): if col == 0: # Set the size self.horizontalHeader().resizeSection( col, 60 ) # Fix width self.horizontalHeader().setResizeMode( col, QHeaderView.Fixed ) # Width of a fixed column - as in the main widget self.frozen_table_view.setColumnWidth( col, self.columnWidth(col) ) elif col == 1: self.horizontalHeader().resizeSection( col, 150 ) self.horizontalHeader().setResizeMode( col, QHeaderView.Fixed ) self.frozen_table_view.setColumnWidth( col, self.columnWidth(col) ) else: self.horizontalHeader().resizeSection( col, 150 ) # Hide unnecessary columns in the # widget fixed columns self.frozen_table_view.setColumnHidden( col, True ) def add_widgets(self, spatial_unit, insert_row): """ Adds widget into the frozen table. :param str_type_id: The STR type id of the tenure type combobox :type str_type_id: Integer :param insert_row: The row number the widgets to be added. :type insert_row: Integer """ delegate = STRTypeDelegate(spatial_unit) # Set delegate to add combobox under # social tenure type column self.frozen_table_view.setItemDelegate( delegate ) self.frozen_table_view.setItemDelegateForColumn( 0, delegate ) index = self.frozen_table_view.model().index( insert_row, 0, QModelIndex() ) self.frozen_table_view.model().setData( index, '', Qt.EditRole ) self.frozen_table_view.openPersistentEditor( self.frozen_table_view.model().index(insert_row, 0) ) self.frozen_table_view.openPersistentEditor( self.frozen_table_view.model().index(insert_row, 1) ) def update_section_width( self, logicalIndex, oldSize, newSize ): """ Updates frozen table column width and geometry. :param logicalIndex: The section's logical number :type logicalIndex: Integer :param oldSize: The old size of the section :type oldSize: Integer :param newSize: The new size of the section :type newSize: Integer """ if logicalIndex==0 or logicalIndex==1: self.frozen_table_view.setColumnWidth( logicalIndex, newSize ) self.update_frozen_table_geometry() def update_section_height( self, logicalIndex, oldSize, newSize ): """ Updates frozen table column height. :param logicalIndex: The section's logical number :type logicalIndex: Integer :param oldSize: The old size of the section :type oldSize: Integer :param newSize: The new size of the section :type newSize: Integer """ self.frozen_table_view.setRowHeight( logicalIndex, newSize ) def resizeEvent(self, event): """ Handles the resize event of the frozen table view. It updates the frozen table view geometry on resize of table. :param event: The event :type event: QEvent """ QTableView.resizeEvent(self, event) try: self.update_frozen_table_geometry() except Exception as log: LOGGER.debug(str(log)) def scrollTo(self, index, hint): """ Scrolls the view if necessary to ensure that the item at index is visible. The view will try to position the item according to the given hint. :param index: The scroll index :type index: QModelIndex :param hint: The scroll hint :type hint: Integer """ if index.column() > 1: QTableView.scrollTo(self, index, hint) def update_frozen_table_geometry(self): """ Updates the frozen table view geometry. """ if self.verticalHeader().isVisible(): self.frozen_table_view.setGeometry( self.verticalHeader().width() + self.frameWidth(), self.frameWidth(), self.columnWidth(0) + self.columnWidth(1), self.viewport().height() + self.horizontalHeader().height() ) else: self.frozen_table_view.setGeometry( self.frameWidth(), self.frameWidth(), self.columnWidth(0) + self.columnWidth(1), self.viewport().height() + self.horizontalHeader().height() ) def move_cursor(self, cursor_action, modifiers): """ Override function for correct left to scroll the keyboard. Returns a QModelIndex object pointing to the next object in the table view, based on the given cursorAction and keyboard modifiers specified by modifiers. :param cursor_action: The cursor action :type cursor_action: Integer :param modifiers: Qt.KeyboardModifier value. :type modifiers: Object :return: The current cursor position. :rtype: QModelIndex """ current = QTableView.move_cursor( self, cursor_action, modifiers ) if cursor_action == self.MoveLeft and current.column() > 1 and \ self.visualRect(current).topLeft().x() < \ (self.frozen_table_view.columnWidth(0) + self.frozen_table_view.columnWidth(1)): new_value = self.horizontalScrollBar().value() + \ self.visualRect(current).topLeft().x() - \ (self.frozen_table_view.columnWidth(0) + self.frozen_table_view.columnWidth(1)) self.horizontalScrollBar().setValue(new_value) return current
class charsPanel(QWidget): def __init__(self, parent=None): super(charsPanel, self).__init__(parent) # Do the layout: refresh button and filter popup at the top, # with a table below. mainLayout = QVBoxLayout() self.setLayout(mainLayout) topLayout = QHBoxLayout() mainLayout.addLayout(topLayout, 0) self.refreshButton = QPushButton("Refresh") self.filterMenu = QComboBox() topLayout.addWidget(self.refreshButton, 0) topLayout.addStretch(1) topLayout.addWidget(self.filterMenu, 0) self.view = QTableView() self.view.setCornerButtonEnabled(False) self.view.setWordWrap(False) self.view.setAlternatingRowColors(True) mainLayout.addWidget(self.view, 1) # Set up the table model/view. Pass to the model a pointer # to the view so it can query the row under the mouse. self.model = myTableModel(view=self.view) #Interpose a sort filter proxy between the view and the model. self.proxy = mySortFilterProxy(self) self.proxy.setSourceModel(self.model) self.view.setModel(self.proxy) # Hook up the refresh button clicked signal to refresh below self.connect(self.refreshButton, SIGNAL("clicked()"), self.refresh) # Populate the filter popup with rows: # 0 : All - no filter # 1 : not 7-bit - show only things not in the 7-bit code # 2 : not Latin-1 - show only things outside Latin-1 self.filterMenu.addItem(QString(u"All")) self.filterMenu.addItem(QString(u"\u00ac" + u" 7-bit")) self.filterMenu.addItem(QString(u"\u00ac" + u" Latin-1")) # The filters refer to these properties, called with a QChar C self.lambdaAll = lambda C: True self.lambdaNotAscii = lambda C: (C.unicode() < 32) or (C.unicode() > 126) self.lambdaNotLatin = lambda C: (C.toLatin1() == b'\x00') self.filterLambda = self.lambdaAll # Connect a user-selection in the popup to our filter method. self.connect(self.filterMenu, SIGNAL("activated(int)"), self.filter) # Connect doubleclicked from our table view to self.findThis self.connect(self.view, SIGNAL("doubleClicked(QModelIndex)"), self.findThis) # Connect the model reset signals to functions to place and clear # a status message. self.connect(self.model, SIGNAL("modelAboutToBeReset()"), self.sigResetStarting) self.connect(self.model, SIGNAL("modelReset()"), self.sigResetOver) # This slot receives a double-click on the table. Figure out which # character it is and get the Find panel set up to search for it. def findThis(self, qmi): rep = None if qmi.column() == 3: # doubleclick in entity column, put entity in the replace field rep = qmi.data(Qt.DisplayRole).toString() if qmi.column() != 0: # get reference to column 0 qmi = qmi.sibling(qmi.row(), 0) qs = qmi.data(Qt.DisplayRole).toString() # Call for a find with respect case on, whole word and regex off IMC.findPanel.censusFinder(qs, rep, False, False) # this slot gets the activated(row) signal from the combo-box. # Based on the row, set self.filterLambda to a lambda that will # accept or reject a given QChar value. def filter(self, row): if row == 1: self.filterLambda = self.lambdaNotAscii elif row == 2: self.filterLambda = self.lambdaNotLatin else: self.filterLambda = self.lambdaAll self.model.reset() # This slot receives the main window's docWillChange signal. # It comes with a file path but we can ignore that. def docWillChange(self): #self.view.setSortingEnabled(False) self.model.beginResetModel() # Subroutine to reset the visual appearance of the table view, # invoked on table reset or docHasChanged because on instantiation # we have no data until a file is opened. def setUpTableView(self): self.view.resizeColumnsToContents() self.view.horizontalHeader().setStretchLastSection(True) self.view.resizeRowsToContents() self.view.setSortingEnabled(True) # This slot receives the main window's docHasChanged signal. # Let the table view populate with all-new metadata (or empty # data if the command was File>New). def docHasChanged(self): self.model.endResetModel() self.setUpTableView() # This slot receives the click of the refresh button. Tell the # model we are resetting everything so the view will suck up new # data. Then call our editor to rebuild the metadata. def refresh(self): #self.view.setSortingEnabled(False) self.model.beginResetModel() IMC.editWidget.rebuildMetadata() self.model.endResetModel() self.setUpTableView() # The model emits signals when it is starting to rebuild the table # and when it has finished rebuilding the table. Use these to put up # a status message, as the wait can be significant. def sigResetStarting(self): pqMsgs.showStatusMsg(QString(u"Rebuilding Character Table...")) def sigResetOver(self): pqMsgs.clearStatusMsg()
class ThemeConfigurationWidget(QWidget): """Themes are stored in directory 'themes' in configuration directory. Each theme file has .mixth extension and represents single theme. """ def __init__(self, parent): QWidget.__init__(self, parent) self.cmbThemes = QComboBox(self) self.cmbThemes.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.cmbThemes.currentIndexChanged[int].connect(self._changeCurrentTheme) self.btnCopyTheme = QPushButton(self) self.btnCopyTheme.setText(utils.tr('Copy theme...')) self.btnCopyTheme.clicked.connect(self._copyTheme) self.componentsView = QTableView(self) self.themeModel = ThemeModel() self.componentsView.setModel(self.themeModel) self.componentsView.setSelectionBehavior(QTableView.SelectRows) self.componentsView.setItemDelegateForColumn(1, ComponentDelegate()) self.componentsView.setEditTriggers(QTableView.DoubleClicked) self.setLayout(QVBoxLayout()) h_layout = QHBoxLayout() h_layout.addWidget(self.cmbThemes) h_layout.addWidget(self.btnCopyTheme) self.layout().addLayout(h_layout) self.layout().addWidget(self.componentsView) def resizeEvent(self, event): view_size = self.componentsView.size() hh = self.componentsView.horizontalHeader() hh.resizeSection(0, int((view_size.width() - self.componentsView.verticalHeader().width()) * 0.6)) hh.setStretchLastSection(True) def loadThemes(self, theme_to_select=None): if theme_to_select is None: theme_to_select = globalSettings[appsettings.HexWidget_Theme] self.cmbThemes.clear() self.cmbThemes.addItem(utils.tr('Default (unmodifiable)'), '') if not theme_to_select: self.cmbThemes.setCurrentIndex(0) for theme_name in hexwidget.Theme.availableThemes(): self.cmbThemes.addItem(theme_name.capitalize(), theme_name) if theme_name == theme_to_select: self.cmbThemes.setCurrentIndex(self.cmbThemes.count() - 1) def saveCurrentTheme(self): if self.themeModel.theme is not None and self.themeName: theme_name = self.themeName self.themeModel.theme.save(theme_name) self.loadThemes(theme_name) @property def themeName(self): return self.cmbThemes.itemData(self.cmbThemes.currentIndex()) def _copyTheme(self): while True: theme_name, ok = QInputDialog.getText(self, utils.tr('Copy theme'), utils.tr('Name for copy of theme:')) if not ok: break if (not theme_name or hexwidget.Theme.themeFromName(theme_name) is not None or not utils.isValidFilename(theme_name)): QMessageBox.information(self, utils.tr('Wrong name for theme'), utils.tr('Name for theme is invalid')) else: break if ok: self.themeModel.theme.save(theme_name) self.loadThemes(theme_name) def _changeCurrentTheme(self, index): if self.themeName and self.themeModel.modified: if QMessageBox.question(self, utils.tr('Save theme'), utils.tr('Do you want to save "{0}"?').format(self.themeName), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) == QMessageBox.Yes: self.themeModel.theme.save() theme_name = self.cmbThemes.itemData(index) if index >= 0 and theme_name is not None: theme = hexwidget.Theme.themeFromName(theme_name) or hexwidget.Theme() else: theme = None self.themeModel.theme = theme
class pagesPanel(QWidget): def __init__(self, parent=None): super(pagesPanel, self).__init__(parent) # The layout is very basic, the table with an Update button. mainLayout = QVBoxLayout() self.setLayout(mainLayout) hlayout = QHBoxLayout() self.updateButton = QPushButton("Update") self.insertText = QLineEdit() self.insertText.setFont(pqMsgs.getMonoFont()) self.insertButton = QPushButton("Insert") hlayout.addWidget(self.updateButton, 0) hlayout.addWidget(self.insertText, 1) # text gets all available room hlayout.addWidget(self.insertButton, 0) mainLayout.addLayout(hlayout) self.view = QTableView() self.view.setCornerButtonEnabled(False) self.view.setWordWrap(False) self.view.setAlternatingRowColors(True) self.view.setSortingEnabled(False) self.c1Delegate = formatDelegate() self.view.setItemDelegateForColumn(1, self.c1Delegate) self.c2Delegate = actionDelegate() self.view.setItemDelegateForColumn(2, self.c2Delegate) self.c3Delegate = folioDelegate() self.view.setItemDelegateForColumn(3, self.c3Delegate) mainLayout.addWidget(self.view, 1) # Set up the table model/view. self.model = myTableModel() self.view.setModel(self.model) # Connect the double-clicked signal of the view self.connect(self.view, SIGNAL("doubleClicked(QModelIndex)"), self.goToRow) # Connect the update button to the model's update method self.connect(self.updateButton, SIGNAL("clicked()"), self.model.updateFolios) # Connect the insert button to our insert method self.connect(self.insertButton, SIGNAL("clicked()"), self.insertMarkers) # This slot receives a double-click from the table view, # passing an index. If the click is in column 0, the scan number, # get the row; use it to get a text cursor from the page table # and make that the editor's cursor, thus moving to the top of that page. # Double-click on cols 1-3 initiates editing and maybe someday a # doubleclick on column 5 will do something with the proofer info. def goToRow(self, index): if index.column() == 0: tc = IMC.pageTable.getCursor(index.row()) IMC.editWidget.setTextCursor(tc) IMC.editWidget.setFocus(Qt.TabFocusReason) # This slot receives the main window's docWillChange signal. # It comes with a file path but we can ignore that. def docWillChange(self): self.model.beginResetModel() # Subroutine to reset the visual appearance of the table view, # invoked on table reset because on instantiation we have no table. def setUpTableView(self): # Header text is supplied by the table model headerData method # Here we are going to set the column widths of the first 4 # columns to a uniform 7 ens each based on the current font. # However, at least on Mac OS, the headers are rendered with a # much smaller font than the data, so we up it by 50%. hdr = self.view.horizontalHeader() pix = hdr.fontMetrics().width(QString("9999999")) hdr.resizeSection(0, pix) hdr.resizeSection(3, pix) pix += pix / 2 hdr.resizeSection(1, pix) hdr.resizeSection(2, pix) self.view.resizeColumnToContents(4) # This slot receives the main window's docHasChanged signal. # Let the table view populate with all-new metadata (or empty # data if the command was File>New). def docHasChanged(self): self.model.endResetModel() self.setUpTableView() # On the Insert button being pressed, make some basic sanity checks # and get user go-ahead then insert the given text at the head of # every page. def insertMarkers(self): # Copy the text and if it is empty, complain and exit. qi = QString(self.insertText.text()) if qi.isEmpty(): pqMsgs.warningMsg("No insert text specified") return # See how many pages are involved: all the ones that aren't marked skip n = 0 for i in range(IMC.pageTable.size()): if IMC.pageTable.getAction(i) != IMC.FolioRuleSkip: n += 1 if n == 0: # page table empty or all rows marked skip pqMsgs.warningMsg("No pages to give folios to") return m = "Insert this string at the top of {0} pages?".format(n) b = pqMsgs.okCancelMsg(QString(m), pqMsgs.trunc(qi, 35)) if b: # Convert any '\n' in the text to the QT line delimiter char # we do this in the copy so the lineEdit text doesn't change qi.replace(QString(u'\\n'), QString(IMC.QtLineDelim)) # get a cursor on the edit document tc = QTextCursor(IMC.editWidget.textCursor()) tc.beginEditBlock() # start single undoable operation # Working from the end of the document backward, go to the # top of each page and insert the string for i in reversed(range(IMC.pageTable.size())): if IMC.pageTable.getAction(i) != IMC.FolioRuleSkip: # Note the page's start position and set our work cursor to it pos = IMC.pageTable.getCursor(i).position() tc.setPosition(pos) # Make a copy of the insert string replacing %f with this folio f = IMC.pageTable.getDisplay(i) qf = QString(qi) qf.replace(QString(u'%f'), f, Qt.CaseInsensitive) tc.insertText(qf) # The insertion goes in ahead of the saved cursor position so now # it points after the inserted string. Put it back where it was. IMC.pageTable.setPosition(i, pos) tc.endEditBlock() # wrap up the undo op
class GmApp(QMainWindow): def __init__(self): super(QMainWindow, self).__init__() self.setWindowTitle("GuloMail by GulonSoft") self.setWindowIcon(QIcon("g-square.png")) self.createActions() self.createStatusBar() self.createMenus() self.createToolbars() self.createWidgets() self.createLayouts() def createActions(self): self.newAction=QAction("&New", self, shortcut=QKeySequence.New, statusTip="New") self.sendReceiveAction=QAction("Send / &Receive", self, shortcut="F9", statusTip="Send / Receive") self.printAction=QAction("&Print...", self, shortcut="Ctrl+P", statusTip="Print") self.quitAction=QAction("&Quit", self, shortcut="Ctrl+Q", statusTip="Quit", triggered=self.close) self.copyAction=QAction("&Copy", self, statusTip="Copy", shortcut=QKeySequence.Copy) self.deleteAction=QAction("&Delete", self, statusTip="Delete Message") self.nextAction=QAction("Next &Unread Message", self, shortcut="Ctrl+]", statusTip="Next unread message") self.previousAction=QAction("P&revious Unread Message", self, shortcut="Ctrl+[", statusTip="Previous unread message") self.replyAction=QAction("&Reply", self, shortcut="Ctrl+R", statusTip="Reply to sender", triggered=self.reply) self.replyToAllAction=QAction("Reply to &All", self, shortcut="Ctrl+Shift+R", statusTip="Reply to all", triggered=self.replyToAll) self.forwardAction=QAction("&Forward", self, shortcut="Ctrl+F", statusTip="Forward") self.junkAction=QAction("Junk", self, shortcut="Ctrl+J", statusTip="Mark as Junk") self.notJunkAction=QAction("Not junk", self, shortcut="Shift+Ctrl+J", statusTip="Mark as Not Junk") self.contentsAction=QAction("&Contents", self, statusTip="Help Contents", shortcut="F1", triggered=self.helpContents) self.aboutAction=QAction("&About", self, statusTip="About GuloMail", triggered=self.about) self.cancelAction=QAction("&Cancel", self, statusTip="Cancel") def createStatusBar(self): self.statusBar() def createMenus(self): self.fileMenu=self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAction) self.fileMenu.addAction(self.sendReceiveAction) self.fileMenu.addAction(self.printAction) self.fileMenu.addAction(self.quitAction) self.editMenu=self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.copyAction) self.editMenu.addAction(self.deleteAction) self.viewMenu=self.menuBar().addMenu("&View") self.folderMenu=self.menuBar().addMenu("F&older") self.messageMenu=self.menuBar().addMenu("&Message") self.goToMenu=self.messageMenu.addMenu("&Go To") self.goToMenu.addAction(self.nextAction) self.goToMenu.addAction(self.previousAction) self.messageMenu.addAction(self.replyAction) self.messageMenu.addAction(self.replyToAllAction) self.messageMenu.addAction(self.forwardAction) self.markAsMenu=self.messageMenu.addMenu("Mar&k as...") self.markAsMenu.addAction(self.junkAction) self.markAsMenu.addAction(self.notJunkAction) self.searchMenu=self.menuBar().addMenu("&Search") self.helpMenu=self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.contentsAction) self.helpMenu.addAction(self.aboutAction) def createToolbars(self): self.toolbar=self.addToolBar('Main Toolbar') self.toolbar.setMovable(False) self.toolbar.addAction(self.newAction) self.toolbar.addSeparator() self.toolbar.addAction(self.sendReceiveAction) self.toolbar.addSeparator() self.toolbar.addAction(self.replyAction) self.toolbar.addAction(self.replyToAllAction) self.toolbar.addAction(self.forwardAction) self.toolbar.addSeparator() self.toolbar.addAction(self.printAction) self.toolbar.addAction(self.deleteAction) self.toolbar.addAction(self.junkAction) self.toolbar.addAction(self.notJunkAction) self.toolbar.addAction(self.cancelAction) self.toolbar.addSeparator() self.toolbar.addAction(self.previousAction) self.toolbar.addAction(self.nextAction) def createWidgets(self): ## Message Table self.table=QTableView() self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.setGridStyle(Qt.NoPen) self.model = QStandardItemModel(8, 3, self) self.model.setHeaderData(0, Qt.Horizontal, "From") self.model.setHeaderData(1, Qt.Horizontal, "Subject") self.model.setHeaderData(2, Qt.Horizontal, "Received") self.table.setModel(self.model) self.selectionModel = QItemSelectionModel(self.model) self.selectionModel.SelectionFlag=0x0020 self.table.setSelectionModel(self.selectionModel) self.table.horizontalHeader().setStretchLastSection(True) self.table.verticalHeader().setVisible(False) self.table.setSortingEnabled(True) self.table.setAlternatingRowColors(True) ## Folder Tree View self.folderTree=QTreeWidget() self.folderTree.setColumnCount(1) self.folderTree.setHeaderLabel(QString('Folders')) self.treeItem=QTreeWidgetItem() self.treeItem.setText(0, 'Folders') self.inbox=QTreeWidgetItem() self.inbox.setText(0, 'Inbox') self.deletedItems=QTreeWidgetItem() self.deletedItems.setText(0, 'Deleted Items') self.drafts=QTreeWidgetItem() self.drafts.setText(0, 'Drafts') self.junk=QTreeWidgetItem() self.junk.setText(0, 'Junk') self.outbox=QTreeWidgetItem() self.outbox.setText(0, 'Outbox') self.sent=QTreeWidgetItem() self.sent.setText(0, 'Sent') self.treeItem.addChild(self.inbox) self.treeItem.addChild(self.deletedItems) self.treeItem.addChild(self.drafts) self.treeItem.addChild(self.junk) self.treeItem.addChild(self.outbox) self.treeItem.addChild(self.sent) self.folderTree.addTopLevelItem(self.treeItem) self.folderTree.expandAll() self.folderTree.setAnimated(True) self.folderTree.setMaximumWidth(150) ## Temp. placeholders self.textEdit=QTextEdit() self.textEdit2=QTextEdit() def createLayouts(self): self.mainSplitter=QSplitter() self.setCentralWidget(self.mainSplitter) self.mainSplitter.addWidget(self.folderTree) self.messageSplitter=QSplitter(Qt.Vertical) self.messageSplitter.addWidget(self.table) self.messageSplitter.addWidget(self.textEdit2) self.mainSplitter.addWidget(self.messageSplitter) def helpContents(self): print "Help" def reply(self): print "Reply" def replyToAll(self): print "Reply To All" def about(self): text=QString("GuloMail v0.1\n\n") text.append("GuloMail is a freeware email client written in Python using PyQt4 (Python bindings for Nokia's Qt)\n\n") text.append(QChar(0x00A9)) text.append("GulonSoft 2010\nhttp://www.gulon.co.uk/") QMessageBox.about(self, "About GuloMail", text)
class FreezeTableWidget(QTableView): def __init__(self, parent=None): QTableView.__init__(self, parent) self.freezeNum = 0 self.inited = False self.frozenTableView = QTableView(self) def columnCountChanged(self, old, new): log('columnCountChanged', old, new) def setSetting(self, setting): if self.inited and setting is not None: if 'freezeNum' in setting: self.setFreezeNum(setting['freezeNum']) if 'hideColumns' in setting: for col in range(self.model().columnCount()): if col in setting['hideColumns']: self.hideColumn(col) else: self.showColumn(col) if 'hideRows' in setting: for row in range(self.model().rowCount()): if row in setting['hideRows']: self.hideRow(row) else: self.showRow(row) def setFreezeNum(self, num): self.resizeColumnsToContents() for col in range(num): self.frozenTableView.setColumnHidden(col, False) if not self.isColumnHidden(col): width = self.columnWidth(col) # log('width:', col, width) if width != 0: self.frozenTableView.setColumnWidth(col, width) # self.setColumnHidden(col, False) for col in range(num, self.model().columnCount()): if not self.frozenTableView.isColumnHidden(col): # self.resizeColumnToContents(col) width = self.frozenTableView.columnWidth(col) self.frozenTableView.setColumnHidden(col, True) if width != 0: self.setColumnWidth(col, width) else: self.frozenTableView.setColumnHidden(col, True) #self.viewport().update() self.freezeNum = num #self.frozenTableView.viewport().stackUnder(self) #self.raise_() #self.viewport().stackUnder(self.frozenTableView); self.updateFrozenTableGeometry() # self.resizeColumnsToContents() def myInit(self, model, freezeNum): self.inited = True self.frozenTableView.setSortingEnabled(True) self.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self.setSortingEnabled(True) self.setModel(model) self.setAlternatingRowColors(True) self.freezeNum = freezeNum self.frozenTableView.setModel(self.model()) self.frozenTableView.setFocusPolicy(QtCore.Qt.NoFocus) self.frozenTableView.verticalHeader().hide() #self.frozenTableView.horizontalHeader().setResizeMode(QtGui.QHeaderView.Fixed); self.viewport().stackUnder(self.frozenTableView) self.frozenTableView.setStyleSheet("QTableView { border: none;" "background-color: #8EDE21;" "selection-background-color: #999}") self.frozenTableView.setSelectionModel(self.selectionModel()) self.frozenTableView.setSelectionMode(self.selectionMode()) self.frozenTableView.setSelectionBehavior(self.selectionBehavior()) for col in range(self.freezeNum, self.model().columnCount()): self.frozenTableView.setColumnHidden(col, True) for i in range(self.freezeNum): self.frozenTableView.setColumnWidth( self.freezeNum, self.columnWidth(self.freezeNum)) self.frozenTableView.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff) self.frozenTableView.setVerticalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff) self.frozenTableView.show() self.setHorizontalScrollMode(self.ScrollPerItem) self.setVerticalScrollMode(self.ScrollPerItem) self.frozenTableView.setVerticalScrollMode(self.ScrollPerItem) self.connect(self.frozenTableView.horizontalHeader(), QtCore.SIGNAL("sortIndicatorChanged (int,Qt::SortOrder)"), self.fSortIndicatorChanged) self.connect(self.horizontalHeader(), QtCore.SIGNAL("sortIndicatorChanged (int,Qt::SortOrder)"), self.sortIndicatorChanged) self.connect(self.horizontalHeader(), QtCore.SIGNAL("sectionResized(int,int,int)"), self.updateSectionWidth) self.connect(self.verticalHeader(), QtCore.SIGNAL("sectionResized(int,int,int)"), self.updateSectionHeight) self.connect(self.frozenTableView.horizontalHeader(), QtCore.SIGNAL("sectionResized(int,int,int)"), self.updateColumn) self.connect(self.frozenTableView.verticalHeader(), QtCore.SIGNAL("sectionResized(int,int,int)"), self.updateRow) self.connect(self.frozenTableView.verticalScrollBar(), QtCore.SIGNAL("valueChanged(int)"), self.verticalScrollBar().setValue) self.connect(self.verticalScrollBar(), QtCore.SIGNAL("valueChanged(int)"), self.frozenTableView.verticalScrollBar().setValue) self.resizeColumnsToContents() self.updateFrozenTableGeometry() def fSortIndicatorChanged(self, index, sortOrder): if index < self.freezeNum: self.frozenTableView.horizontalHeader().setSortIndicatorShown(True) self.horizontalHeader().setSortIndicatorShown(False) def sortIndicatorChanged(self, index, sortOrder): if index >= self.freezeNum: self.frozenTableView.horizontalHeader().setSortIndicatorShown( False) self.horizontalHeader().setSortIndicatorShown(True) def updateColumn(self, logicalIndex, a, newSize): self.setColumnWidth(logicalIndex, newSize) self.updateFrozenTableGeometry() def updateRow(self, logicalIndex, a, newSize): self.setRowHeight(logicalIndex, newSize) def updateSectionWidth(self, logicalIndex, a, newSize): #if logicalIndex==0 or logicalIndex == 1: self.frozenTableView.setColumnWidth(logicalIndex, newSize) self.updateFrozenTableGeometry() def updateSectionHeight(self, logicalIndex, a, newSize): self.frozenTableView.setRowHeight(logicalIndex, newSize) self.updateFrozenTableGeometry() def resizeEvent(self, event): pass QTableView.resizeEvent(self, event) self.updateFrozenTableGeometry() def moveCursor(self, cursorAction, modifiers): pass current = QTableView.moveCursor(self, cursorAction, modifiers) if cursorAction == self.MoveLeft and current.column()>0 \ and self.visualRect(current).topLeft().x() < self.frozenTableView.columnWidth(0): newValue = self.horizontalScrollBar().value() + self.visualRect( current).topLeft().x() - self.frozenTableView.columnWidth(0) self.horizontalScrollBar().setValue(newValue) return current # def scrollTo(self, index, hint): # pass # #if(index.column()>0): # print 'here' #QTableView.scrollTo(self, index, hint) def updateFrozenTableGeometry(self): width = 0 for i in range(self.freezeNum): width += self.columnWidth(i) self.frozenTableView.setGeometry(self.verticalHeader().sizeHint().width()+self.frameWidth(), \ self.frameWidth(), width, self.viewport().height()+self.horizontalHeader().height())
class LogDialog(QDialog): """LogDialog for the Freeseer project. It is the dialog window for the log. There is an instance for every FreeseerApp. It has a LogHandler which calls LogDialog's message() method when a new log message is received. The call to message() causes a call to add_entry() which adds the information to a new row in the table. """ def __init__(self, parent=None): super(LogDialog, self).__init__(parent) self.resize(800, 500) self.app = QApplication.instance() icon = QIcon() icon.addPixmap(QPixmap(_fromUtf8(":/freeseer/logo.png")), QIcon.Normal, QIcon.Off) self.setWindowIcon(icon) layout = QVBoxLayout() self.setLayout(layout) self.level = 0 self.handler = LogHandler() self.table_model = QStandardItemModel(0, 5) header_names = ["Date", "Level", "Module", "Message", "LevelNo"] date_column = header_names.index("Date") level_column = header_names.index("Level") module_column = header_names.index("Module") self.level_num_column = header_names.index("LevelNo") self.table_model.setHorizontalHeaderLabels(header_names) self.table_view = QTableView() self.table_view.setModel(self.table_model) self.table_view.horizontalHeader().setStretchLastSection(True) self.table_view.setColumnWidth(date_column, 125) self.table_view.setColumnWidth(level_column, 60) self.table_view.setColumnWidth(module_column, 250) self.table_view.setColumnHidden(self.level_num_column, True) self.table_view.setShowGrid(False) self.table_view.horizontalHeader().setClickable(False) self.table_view.verticalHeader().hide() self.table_view.setStyleSheet("""Qtable_view::item { border-bottom: 1px solid lightgrey; selection-background-color: white; selection-color: black; }""") top_panel = QHBoxLayout() self.log_levels = ["Debug", "Info", "Warning", "Error"] self.level_colors = ["#3E4C85", "#269629", "#B0AB21", "#B32020"] self.levels_label = QLabel("Filter Level: ") self.levels_label.setStyleSheet("QLabel { font-weight: bold }") self.current_level_label = QLabel(self.log_levels[0]) self.current_level_label.setStyleSheet("QLabel {{ color: {} }}".format(self.level_colors[0])) self.clear_button = QPushButton("Clear Log") self.levels_slider = QSlider(Qt.Horizontal) self.levels_slider.setStyleSheet(""" QSlider::handle:horizontal { background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #FFFFFF, stop:1 #E3E3E3); border: 1px solid #707070; width: 10px; margin-top: -4px; margin-bottom: -4px; border-radius: 4px; } QSlider::handle:horizontal:hover { background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #DEDEDE, stop:1 #C9C9C9); border: 1px solid #4F4F4F; border-radius: 4px; } QSlider::sub-page:horizontal { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #BFBFBF, stop: 1 #9E9E9E); background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1, stop: 0 #9E9E9E, stop: 1 #858585); border: 1px solid #777; height: 10px; border-radius: 4px; } QSlider::add-page:horizontal { background: #fff; border: 1px solid #707070; height: 10px; border-radius: 4px; }""") self.levels_slider.setRange(0, len(self.log_levels) - 1) self.levels_slider.setTickPosition(QSlider.TicksBelow) self.levels_slider.setTickInterval(1) top_panel.addSpacerItem(QSpacerItem(10, 0)) top_panel.addWidget(self.levels_label, 3) top_panel.addWidget(self.current_level_label, 2) top_panel.addWidget(self.levels_slider, 8) top_panel.addSpacerItem(QSpacerItem(25, 0)) top_panel.addWidget(self.clear_button, 10) layout.addLayout(top_panel) layout.addWidget(self.table_view) self.connect(self.clear_button, SIGNAL('clicked()'), functools.partial(self.table_model.setRowCount, 0)) self.connect(self.levels_slider, SIGNAL('valueChanged(int)'), self.slider_set_level) self.setWindowTitle("Log") self.handler.add_listener(self) def __del__(self): self.handler.remove_listener(self) def retranslate(self): self.setWindowTitle(self.app.translate("LogDialog", "Log")) self.clear_button.setText(self.app.translate("LogDialog", "Clear Log")) self.levels_label.setText("{}: ".format(self.app.translate("LogDialog", "Filter Level"))) def message(self, message): """Passes the log fields to add_entry() It is called by LogHandler when a log message is received""" self.add_entry(message["time"], message["level"], message["full_module_name"], message["message"], str(message["levelno"])) def add_entry(self, date, level, module, message, levelno): """Adds the given fields to a new row in the log table It is called by message() when a log message is received""" items = [QStandardItem(date), QStandardItem(level), QStandardItem(module), QStandardItem(message), QStandardItem(levelno)] for item in items: item.setEditable(False) self.table_model.appendRow(items) def slider_set_level(self, level): self.current_level_label.setText(self.log_levels[level]) self.current_level_label.setStyleSheet("QLabel {{ color: {} }}".format(self.level_colors[level])) self.set_level(level + 1) def set_level(self, level): """Sets the current level of the LogDialog. Level is based on the selection made in the levels_combo_box. It hides all messages with a lower level.""" self.level = level * 10 for i in range(self.table_model.rowCount()): if int(str(self.table_model.item(i, self.level_num_column).text())) < self.level: self.table_view.setRowHidden(i, True) else: self.table_view.setRowHidden(i, False)
class MainWindow(QMainWindow): """ Initialization """ def __init__(self, rulesModel, logoFnam, *args): QMainWindow.__init__(self, *args) self.rulesModel = rulesModel self.rulesModel.dataChanged.connect(self._statusRefresh) self.cancelled = True # for to handle win close box the same as Cancel button self.mainHSplit = QSplitter(self) # data | buttons self.mainHSplit.setChildrenCollapsible(False) self.setCentralWidget(self.mainHSplit) self.mainVSplit = QSplitter(Qt.Vertical) self.mainVSplit.setChildrenCollapsible(False) self.mainHSplit.addWidget(self.mainVSplit) self._drawRules() self.mainVSplit.addWidget(self.rulesView) self.condActSplit = QSplitter() self.condActSplit.setChildrenCollapsible(False) self._drawCondAct() self.mainVSplit.addWidget(self.condActSplit) # let rules view resize vertically two times faster than cond/action view self.rulesView.setSizeIncrement(self.rulesView.sizeIncrement().width(), 2 * self.condView.sizeIncrement().height()) self._drawButtons(logoFnam) self.setStatusBar(QStatusBar()) self.condView.horizontalHeader().setCascadingSectionResizes(True) self.rulesView.selectRow(0) def _drawRules(self): self.rulesView = QTableView() self.rulesView.setModel(self.rulesModel) self.rulesView.setEditTriggers(QAbstractItemView.AllEditTriggers) self.rulesView.setSelectionBehavior(QAbstractItemView.SelectRows) self.rulesView.setSelectionMode(QAbstractItemView.SingleSelection) self.rulesView.horizontalHeader().setStretchLastSection(True) self.rulesView.resizeColumnsToContents() #self.rulesView.verticalHeader().setMovable(True) # row remapping - see QHeaderView.logicalIndex() #self.rulesView.verticalHeader().setCascadingSectionResizes(True) # takes space from next row self.rulesView.selectionModel().currentRowChanged.connect(self._ruleRowChanged) self.rulesView.verticalHeader().sectionResized[int,int,int].connect(self._ruleRowHeightChanged) def _drawCondAct(self): if getattr(self, 'condGB', None): m_settings.setValue('spl_condAct', self.condActSplit.saveState()) self.condGB.deleteLater() # or .destroy() del self.condGB self.actionGB.deleteLater() del self.actionGB row = self._ruleCurrRow() rcount = self.rulesModel.rowCount() self.condGB = QGroupBox(self.tr('Conditions')) self.condView = QTableView() conds = self.rulesModel.ruleConditions(row) if row in range(rcount) \ else [] self.condModel = ConditionsModel(conds, self.rulesModel) self.condModel.dataChanged.connect(self._codeFragChanged) self.condView.setModel(self.condModel) self.condTypeDelegate = ComboBoxDelegate(Condition._types._typeCaptions) self.condView.setItemDelegateForColumn(0, self.condTypeDelegate) self.condView.setEditTriggers(QAbstractItemView.AllEditTriggers) self.condView.setSelectionBehavior(QAbstractItemView.SelectRows) self.condView.setSelectionMode(QAbstractItemView.SingleSelection) self.condView.horizontalHeader().setStretchLastSection(True) self.condView.resizeColumnsToContents() self.condView.selectionModel().currentRowChanged.connect(self._statusRefresh) vbox = QVBoxLayout() vbox.addWidget(self.condView) self.condGB.setLayout(vbox) self.condActSplit.addWidget(self.condGB) self.actionGB = QGroupBox(self.tr('Actions')) self.actionView = QTableView() # parent = self.actionGB) actions = self.rulesModel.ruleActions(row) if row in range(rcount) \ else [] self.actionModel = ActionsModel(actions, self.rulesModel) self.actionModel.dataChanged.connect(self._codeFragChanged) self.actionView.setModel(self.actionModel) self.actionTypeDelegate = ComboBoxDelegate(Action._types._typeCaptions) self.actionView.setItemDelegateForColumn(0, self.actionTypeDelegate) self.actionView.setEditTriggers(QAbstractItemView.AllEditTriggers) self.actionView.setSelectionBehavior(QAbstractItemView.SelectRows) self.actionView.setSelectionMode(QAbstractItemView.SingleSelection) self.actionView.horizontalHeader().setStretchLastSection(True) self.actionView.resizeColumnsToContents() self.actionView.selectionModel().currentRowChanged.connect(self._statusRefresh) vbox = QVBoxLayout() vbox.addWidget(self.actionView) self.actionGB.setLayout(vbox) self.condActSplit.addWidget(self.actionGB) self.condActSplit.restoreState(m_settings.value('spl_condAct').toByteArray()) def _drawButton(self, vbox, caption, slot, ena = False): but = QPushButton(self.tr(caption)) but.setEnabled(ena) but.clicked.connect(getattr(self, slot)) vbox.addWidget(but) # add to VBoxLayout return but def _drawButtons(self, logoFnam): gbox = QGroupBox() spol = QSizePolicy() spol.horizontalPolicy = QSizePolicy.Maximum gbox.setSizePolicy(spol) vbox = QVBoxLayout() if os.path.isfile(logoFnam): img = QPixmap(logoFnam) #.scaled(64, 64) lblLogo = QLabel() lblLogo.setPixmap(img) lblLogo.setAlignment(Qt.AlignTop | Qt.AlignRight) vbox.addWidget(lblLogo) #vbox.addSpacing(3) self.butSave = self._drawButton(vbox, "M&odify", 'closeSave') font = QFont() font.setBold(True) self.butSave.setFont(font) self.butCancel = self._drawButton(vbox, "Cancel", 'closeCancel', True) vbox.addSpacing(36) self.butAddRule = self._drawButton(vbox, "Add Rule", 'addRule', True) self.butCopyRule = self._drawButton(vbox, "Copy Rule", 'copyRule') self.butDelRule = self._drawButton(vbox, "Delete Rule", 'delRule') self.butMoveRuleUp = self._drawButton(vbox, "Move Rule Up", 'moveRuleUp') self.butMoveRuleDn = self._drawButton(vbox, "Move Rule Down", 'moveRuleDown') vbox.addSpacing(24) self.butAddCond = self._drawButton(vbox, "Add Condition", 'addCond') self.butDelCond = self._drawButton(vbox, "Delete Condition", 'delCond') vbox.addSpacing(15) self.butAddAction = self._drawButton(vbox, "Add Action", 'addAction') self.butDelAction = self._drawButton(vbox, "Delete Action", 'delAction') gbox.setLayout(vbox) self.mainHSplit.addWidget(gbox) """ Internal Bindings Signal Receivers """ # main win close events # .. (cancel closing with event.ignore(); QMainWindow calls event.accept()) @pyqtSlot(QCloseEvent) def closeEvent(self, event): self._saveAppState() # save rules if not empty and user clicked Modified/Save button if self.rulesModel.rowCount() > 0 and not self.cancelled: text = self.rulesModel.getRawRules().validate() if text: self.cancelled = True QMessageBox.information(self, APP_TITLE, self.tr("Validation failed because of:<p><p>") + text) event.ignore() return # RETURN - cancel app closing ###### self.rulesModel.saveScript() # accept window closing QMainWindow.closeEvent(self, event) # quit application m_app.quit() @pyqtSlot() def _statusRefresh(self): # dis/enable buttons, display view selections ruleRow = self._ruleCurrRow() condRow = self._condCurrRow() actionRow = self._actionCurrRow() self.butSave.setEnabled(self.rulesModel.isModified()) ruleCnt = self.rulesModel.rowCount() self.butCopyRule.setEnabled(ruleRow >= 0) self.butDelRule.setEnabled(ruleRow >= 0) self.butMoveRuleUp.setEnabled(ruleRow > 0) self.butMoveRuleDn.setEnabled(ruleRow >= 0 and ruleRow + 1 < ruleCnt) self.butAddCond.setEnabled(ruleRow >= 0) self.butDelCond.setEnabled(condRow >= 0) self.butAddAction.setEnabled(ruleRow >= 0) self.butDelAction.setEnabled(actionRow >= 0) # display currently selected list rows in the status bar - if empty if ruleRow >= 0 and False: # replace False with ~self.statusBar().isEmpty()?!?!? text = str(self.tr("Selected Rule: {ruleI}"))\ .format(ruleI = ruleRow + 1) if condRow >= 0: text += " " \ + str(self.tr("Selected Condition: {typeI}"))\ .format(typeI = condRow + 1) if actionRow >= 0: text += " " \ + str(self.tr("Selected Action: {typeI}"))\ .format(typeI = actionRow + 1) self.statusBar().showMessage(text, 3000) @pyqtSlot(int,int,int) def _ruleRowHeightChanged(self, section, oldsize, newsize): hdr = self.rulesView.verticalHeader() for row in range(hdr.count()): if row != section: hdr.resizeSection(row, newsize) @pyqtSlot() def _ruleRowChanged(self): self._drawCondAct() self._statusRefresh() @pyqtSlot() def _codeFragChanged(self): # refresh the rules list columns Conditions and Actions row = self._ruleCurrRow() leftColIndex = self.rulesModel.index(row, 2, QModelIndex()) rightColIndex = self.rulesModel.index(row, 3, QModelIndex()) self.rulesView.dataChanged(leftColIndex, rightColIndex) self._statusRefresh() """ User Action Signal Receivers """ @pyqtSlot() def closeSave(self): self.cancelled = False self.close() @pyqtSlot() def closeCancel(self): self.cancelled = True self.close() @pyqtSlot() def addRule(self): row = self._ruleCurrRow() self.rulesModel.insertRow(row) self.rulesView.selectRow(row) self._statusRefresh() @pyqtSlot() def copyRule(self): row = self._ruleCurrRow() self.rulesModel.setSourceRowForNextAdd(row) self.rulesModel.insertRow(row) self.rulesView.selectRow(row) self._statusRefresh() @pyqtSlot() def delRule(self): self.rulesModel.removeRow(self._ruleCurrRow()) self._statusRefresh() @pyqtSlot() def moveRuleUp(self): row = self._ruleCurrRow() self.rulesModel.moveRule(row, -1) self._statusRefresh() @pyqtSlot() def moveRuleDown(self): row = self._ruleCurrRow() self.rulesModel.moveRule(row) self._statusRefresh() @pyqtSlot() def addCond(self): cnt = self.condModel.rowCount() self.condModel.insertRow(cnt) self.condView.selectRow(cnt) self._statusRefresh() @pyqtSlot() def delCond(self): self.condModel.removeRow(self._condCurrRow()) self._statusRefresh() @pyqtSlot() def addAction(self): cnt = self.actionModel.rowCount() self.actionModel.insertRow(cnt) self.actionView.selectRow(cnt) self._statusRefresh() @pyqtSlot() def delAction(self): self.actionModel.removeRow(self._actionCurrRow()) self._statusRefresh() """ Helping Methods """ def _ruleCurrRow(self): #idxs = self.rulesView.selectedIndexes() #return idxs[0].row() if idxs else -1 return self.rulesView.currentIndex().row() def _condCurrRow(self): return self.condView.currentIndex().row() def _actionCurrRow(self): return self.actionView.currentIndex().row() # main win save/restore def _saveAppState(self): m_app.processEvents() # save win geometry and splitter positions _UI_SAVE(self, 'win_geometry') _UI_SAVE(self.mainHSplit, 'spl_mainH') _UI_SAVE(self.mainVSplit, 'spl_mainV') _UI_SAVE(self.condActSplit, 'spl_condAct') #_UI_SAVE(self.condView.horizontalHeader(), 'tvh_condHdr') def _restoreAppState(self): try: # will fail on first app startup after installation # restore last win position, -size and 3 splitter positions _UI_RESTORE(self, 'win_geometry') _UI_RESTORE(self.mainHSplit, 'spl_mainH') _UI_RESTORE(self.mainVSplit, 'spl_mainV') _UI_RESTORE(self.condActSplit, 'spl_condAct') #_UI_RESTORE(self.condView.horizontalHeader(), 'tvh_condHdr') except: # first start screenWidth = QApplication.desktop().width() screenHeight = QApplication.desktop().height() self.setGeometry(screenWidth / 9, screenHeight / 12, screenWidth / 1.26, screenHeight / 1.56)
class dlgSelectCuenta( QDialog ): def __init__( self, parent = None ): super( dlgSelectCuenta, self ).__init__( parent ) self.padre = parent self.ctaBancomodel = QSqlQueryModel() self.ctaBancomodel.setQuery( """ SELECT b.descripcion as Banco, cb.ctabancaria as 'No. Cuenta', tm.simbolo as Moneda, c.codigo as 'Codigo Contable', c.idcuenta as Id, c.descripcion as 'Cuenta Contable', IF( con.fecha IS NULL, LAST_DAY(MIN(d.fechacreacion)), (MAX(con.fecha) + INTERVAL 1 MONTH)) AS conciliar FROM cuentasbancarias cb JOIN bancos b ON cb.idbanco=b.idbanco JOIN cuentascontables c ON c.idcuenta=cb.idcuentacontable JOIN tiposmoneda tm ON tm.idtipomoneda=cb.idtipomoneda LEFT JOIN conciliaciones con ON con.idcuentabancaria=cb.idcuentacontable LEFT JOIN cuentasxdocumento cd ON cd.idcuenta=c.idcuenta LEFT JOIN documentos d ON cd.iddocumento = d.iddocumento WHERE d.iddocumento IS NOT NULL GROUP BY c.idcuenta ; """ ) # # if self.ctaBancomodel.rowCount() == 0 : # QMessageBox.critical(self,"Cuentas Bancarias","No existe ninguna cuenta bancaria") # self.destroy() self.setWindowTitle( u"Elija fecha y cuenta bancaria para la conciliación" ) self.filtermodel = QSortFilterProxyModel() self.filtermodel.setSourceModel( self.ctaBancomodel ) self.filtermodel.setFilterCaseSensitivity( Qt.CaseInsensitive ) self.filtermodel.setFilterKeyColumn( -1 ) self.tblCuenta = QTableView() self.tblCuenta.setSelectionMode( QAbstractItemView.SingleSelection ) self.tblCuenta.setSelectionBehavior( QAbstractItemView.SelectRows ) self.tblCuenta.setModel( self.filtermodel ) buttonbox = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel ) self.txtSearch = QLineEdit() formlayout = QFormLayout() formlayout.addRow( "&Buscar", self.txtSearch ) self.dtPicker = QDateTimeEdit() self.dtPicker.setReadOnly( True ) # self.dtPicker.setCalendarPopup(True) self.dtPicker.setAlignment( Qt.AlignHCenter ) self.dtPicker.setDisplayFormat( "MMMM 'd'el yyyy" ) # self.dtPicker.setMinimumDate(QDate(2009,1,1)) fecha = QDate.currentDate() self.dtPicker.setDate( QDate( fecha.year(), fecha.month(), fecha.daysInMonth() ) ) fechalayout = QFormLayout() fechalayout.addRow( "&Fecha", self.dtPicker ) layout = QVBoxLayout() layout.addLayout( fechalayout ) layout.addWidget( self.tblCuenta ) layout.addLayout( formlayout ) layout.addWidget( buttonbox ) self.setLayout( layout ) self.setMinimumWidth( 400 ) buttonbox.accepted.connect( self.aceptar ) buttonbox.rejected.connect( self.reject ) self.txtSearch.textChanged[unicode].connect( self.updateFilter ) self.tblCuenta.selectionModel().currentChanged[QModelIndex, QModelIndex].connect( self.on_tblCuenta_currentChanged ) self.setModal( True ) self.setWindowFlags( Qt.Dialog | Qt.MSWindowsFixedSizeDialogHint | Qt.WindowTitleHint ) self.show() self.tblCuenta.setFocus() self.tblCuenta.selectRow( 0 ) self.tblCuenta.setColumnHidden( 4, True ) self.tblCuenta.setColumnHidden( 5, True ) self.tblCuenta.setColumnHidden( 6, True ) self.tblCuenta.horizontalHeader().setStretchLastSection( True ) self.tblCuenta.resizeColumnsToContents() @property def data( self ): data = {} fila = self.tblCuenta.selectionModel().currentIndex().row() fecha = self.dtPicker.date() data['banco'] = self.filtermodel.index( fila, 0 ).data().toString() data['id_cuenta_contable'] = self.filtermodel.index( fila, 4 ).data().toInt()[0] data['codigo_cuenta_contable'] = self.filtermodel.index( fila, 3 ).data().toString() data['cuenta_bancaria'] = self.filtermodel.index( fila, 5 ).data().toString() data['fecha'] = QDate( fecha.year(), fecha.month(), fecha.daysInMonth() ) data['moneda'] = self.filtermodel.index( fila, 2 ).data().toString() if not QSqlDatabase.database().isOpen() and not QSqlDatabase.open(): raise Exception( QSqlDatabase.lastError() ) query = QSqlQuery() if not query.exec_( "CALL spSaldoCuenta( %d, %s )" % ( data['id_cuenta_contable'], QDate( data['fecha'].year(), data['fecha'].month(), data['fecha'].daysInMonth() ).toString( "yyyyMMdd" ) ) ): raise Exception( query.lastError().text() ) query.first() data['saldo_inicial_libro'] = Decimal( query.value( 0 ).toString() ) return data def aceptar( self ): fecha = QDate.currentDate() fecha = QDate( fecha.year(), fecha.month(), fecha.daysInMonth() ) if self.dtPicker.date() > fecha: QMessageBox.information( None, "Cuentas Bancarias", "La cuenta seleccionada ya fue conciliada" ) else: return self.accept() def exec_( self ): if self.ctaBancomodel.rowCount() == 0: QMessageBox.critical( self.padre, "Cuentas Bancarias", "No existe ninguna cuenta bancaria con movimientos en este mes" ) return self.reject() else: return QDialog.exec_( self ) def updateFilter( self, str ): self.filtermodel.setFilterWildcard( str ) # @pyqtSlot( "QModelIndex" ) # def on_tblCuenta_clicked(self, index): def on_tblCuenta_currentChanged( self, _current, _previous ): fila = self.tblCuenta.selectionModel().currentIndex().row() fecha = self.filtermodel.index( fila, 6 ).data().toDate() if fecha.toString() != "": self.dtPicker.setDate( fecha ) else: fecha = QDate.currentDate()
class QueueDialog(Window): def __init__(self, base): Window.__init__(self, base, i18n.get('messages_queue')) self.setFixedSize(500, 400) self.last_timestamp = None self.showed = False self.list_ = QTableView() self.list_.setSelectionBehavior(QAbstractItemView.SelectRows) self.list_.clicked.connect(self.__account_clicked) self.caption = QLabel() self.caption.setWordWrap(True) self.caption.setAlignment(Qt.AlignCenter) self.estimated_time = QLabel() self.estimated_time.setWordWrap(True) self.estimated_time.setAlignment(Qt.AlignCenter) self.delete_button = QPushButton(i18n.get('delete')) self.delete_button.setEnabled(False) self.delete_button.setToolTip(i18n.get('delete_selected_message')) self.delete_button.clicked.connect(self.__delete_message) self.clear_button = QPushButton(i18n.get('delete_all')) self.clear_button.setEnabled(False) self.clear_button.setToolTip(i18n.get('delete_all_messages_in_queue')) self.clear_button.clicked.connect(self.__delete_all) button_box = QHBoxLayout() button_box.addStretch(1) button_box.addWidget(self.clear_button) button_box.addWidget(self.delete_button) layout = QVBoxLayout() layout.addWidget(self.list_, 1) layout.addWidget(self.caption) layout.addWidget(self.estimated_time) layout.addLayout(button_box) layout.setSpacing(5) layout.setContentsMargins(5, 5, 5, 5) self.setLayout(layout) def __account_clicked(self, point): self.delete_button.setEnabled(True) self.clear_button.setEnabled(True) def __delete_message(self): self.__disable() selection = self.list_.selectionModel() index = selection.selectedIndexes()[0] message = i18n.get('delete_message_from_queue_confirm') confirmation = self.base.show_confirmation_message(i18n.get('confirm_delete'), message) if not confirmation: self.__enable() return self.base.delete_message_from_queue(index.row()) def __delete_all(self): self.__disable() message = i18n.get('clear_message_queue_confirm') confirmation = self.base.show_confirmation_message(i18n.get('confirm_delete'), message) if not confirmation: self.__enable() return self.base.clear_queue() def __enable(self): self.list_.setEnabled(True) self.delete_button.setEnabled(False) if len(self.base.core.list_statuses_queue()) > 0: self.clear_button.setEnabled(True) else: self.clear_button.setEnabled(False) def __disable(self): self.list_.setEnabled(False) self.delete_button.setEnabled(False) self.clear_button.setEnabled(False) def __on_timeout(self): now = int(time.time()) interval = self.base.core.get_queue_interval() * 60 if self.last_timestamp: est_time = ((self.last_timestamp + interval) - now) / 60 else: est_time = 0 humanized_est_time = self.base.humanize_time_intervals(est_time) next_message = ' '.join([i18n.get('next_message_should_be_posted_in'), humanized_est_time]) if len(self.base.core.list_statuses_queue()) == 0: self.estimated_time.setText('') else: self.estimated_time.setText(next_message) def start(self): self.timer = QTimer() self.timer.timeout.connect(self.__on_timeout) self.timer.start(60000) def closeEvent(self, event=None): if event: event.ignore() self.hide() self.showed = False def show(self): if self.showed: self.raise_() return self.update() Window.show(self) self.showed = True def update(self): model = QStandardItemModel() model.setHorizontalHeaderItem(0, QStandardItem(i18n.get('account'))) model.setHorizontalHeaderItem(1, QStandardItem(i18n.get('message'))) self.list_.setModel(model) now = int(time.time()) interval = self.base.core.get_queue_interval() * 60 if self.last_timestamp: est_time = ((self.last_timestamp + interval) - now) / 60 else: est_time = 0 row = 0 for status in self.base.core.list_statuses_queue(): username = get_username_from(status.account_id) protocol_image = "%s.png" % get_protocol_from(status.account_id) item = QStandardItem(QString.fromUtf8(username)) item.setIcon(QIcon(self.base.load_image(protocol_image, True))) model.setItem(row, 0, item) model.setItem(row, 1, QStandardItem(QString.fromUtf8(status.text))) row += 1 humanized_interval = self.base.humanize_time_intervals(self.base.core.get_queue_interval()) humanized_est_time = self.base.humanize_time_intervals(est_time) warning = i18n.get('messages_will_be_send') % humanized_interval next_message = ' '.join([i18n.get('next_message_should_be_posted_in'), humanized_est_time]) self.caption.setText(warning) if row == 0: self.estimated_time.setText('') else: self.estimated_time.setText(next_message) self.list_.horizontalHeader().setResizeMode(1, QHeaderView.Stretch) self.list_.resizeColumnsToContents() self.__enable() def update_timestamp(self): if len(self.base.core.list_statuses_queue()) > 0: self.last_timestamp = int(time.time()) else: self.last_timestamp = None
class LogDialog(QDialogWithDpi): """LogDialog for the Freeseer project. It is the dialog window for the log. There is an instance for every FreeseerApp. It has a LogHandler which calls LogDialog's message() method when a new log message is received. The call to message() causes a call to add_entry() which adds the information to a new row in the table. """ def __init__(self, parent=None): super(LogDialog, self).__init__(parent) self.resize(800, 500) self.app = QApplication.instance() icon = QIcon() icon.addPixmap(QPixmap(_fromUtf8(":/freeseer/logo.png")), QIcon.Normal, QIcon.Off) self.setWindowIcon(icon) layout = QVBoxLayout() self.setLayout(layout) self.level = 0 self.handler = LogHandler() self.table_model = QStandardItemModel(0, 5) header_names = ["Date", "Level", "Module", "Message", "LevelNo"] date_column = header_names.index("Date") level_column = header_names.index("Level") module_column = header_names.index("Module") self.level_num_column = header_names.index("LevelNo") self.table_model.setHorizontalHeaderLabels(header_names) self.table_view = QTableView() self.table_view.setModel(self.table_model) self.table_view.horizontalHeader().setStretchLastSection(True) self.table_view.setColumnWidth(date_column, self.set_width_with_dpi(125)) self.table_view.setColumnWidth(level_column, self.set_width_with_dpi(60)) self.table_view.setColumnWidth(module_column, self.set_width_with_dpi(250)) self.table_view.setColumnHidden(self.level_num_column, True) self.table_view.setShowGrid(False) self.table_view.horizontalHeader().setClickable(False) self.table_view.verticalHeader().hide() self.table_view.setStyleSheet("""Qtable_view::item { border-bottom: 1px solid lightgrey; selection-background-color: white; selection-color: black; }""") top_panel = QHBoxLayout() self.log_levels = ["Debug", "Info", "Warning", "Error"] self.level_colors = ["#3E4C85", "#269629", "#B0AB21", "#B32020"] self.levels_label = QLabel("Filter Level: ") self.levels_label.setStyleSheet("QLabel { font-weight: bold }") self.current_level_label = QLabel(self.log_levels[0]) self.current_level_label.setStyleSheet("QLabel {{ color: {} }}".format( self.level_colors[0])) self.clear_button = QPushButton("Clear Log") self.levels_slider = QSlider(Qt.Horizontal) self.levels_slider.setStyleSheet(""" QSlider::handle:horizontal { background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #FFFFFF, stop:1 #E3E3E3); border: 1px solid #707070; width: 10px; margin-top: -4px; margin-bottom: -4px; border-radius: 4px; } QSlider::handle:horizontal:hover { background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #DEDEDE, stop:1 #C9C9C9); border: 1px solid #4F4F4F; border-radius: 4px; } QSlider::sub-page:horizontal { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #BFBFBF, stop: 1 #9E9E9E); background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1, stop: 0 #9E9E9E, stop: 1 #858585); border: 1px solid #777; height: 10px; border-radius: 4px; } QSlider::add-page:horizontal { background: #fff; border: 1px solid #707070; height: 10px; border-radius: 4px; }""") self.levels_slider.setRange(0, len(self.log_levels) - 1) self.levels_slider.setTickPosition(QSlider.TicksBelow) self.levels_slider.setTickInterval(1) top_panel.addSpacerItem(self.qspacer_item_with_dpi(10, 0)) top_panel.addWidget(self.levels_label, 3) top_panel.addWidget(self.current_level_label, 2) top_panel.addWidget(self.levels_slider, 8) top_panel.addSpacerItem(self.qspacer_item_with_dpi(25, 0)) top_panel.addWidget(self.clear_button, 10) layout.addLayout(top_panel) layout.addWidget(self.table_view) self.connect(self.clear_button, SIGNAL('clicked()'), functools.partial(self.table_model.setRowCount, 0)) self.connect(self.levels_slider, SIGNAL('valueChanged(int)'), self.slider_set_level) self.setWindowTitle("Log") self.handler.add_listener(self) def __del__(self): self.handler.remove_listener(self) def retranslate(self): self.setWindowTitle(self.app.translate("LogDialog", "Log")) self.clear_button.setText(self.app.translate("LogDialog", "Clear Log")) self.levels_label.setText("{}: ".format( self.app.translate("LogDialog", "Filter Level"))) def message(self, message): """Passes the log fields to add_entry() It is called by LogHandler when a log message is received""" self.add_entry(message["time"], message["level"], message["full_module_name"], message["message"], str(message["levelno"])) def add_entry(self, date, level, module, message, levelno): """Adds the given fields to a new row in the log table It is called by message() when a log message is received""" items = [ QStandardItem(date), QStandardItem(level), QStandardItem(module), QStandardItem(message), QStandardItem(levelno) ] for item in items: item.setEditable(False) self.table_model.appendRow(items) def slider_set_level(self, level): self.current_level_label.setText(self.log_levels[level]) self.current_level_label.setStyleSheet("QLabel {{ color: {} }}".format( self.level_colors[level])) self.set_level(level + 1) def set_level(self, level): """Sets the current level of the LogDialog. Level is based on the selection made in the levels_combo_box. It hides all messages with a lower level.""" self.level = level * 10 for i in range(self.table_model.rowCount()): if int(str(self.table_model.item( i, self.level_num_column).text())) < self.level: self.table_view.setRowHidden(i, True) else: self.table_view.setRowHidden(i, False)
class charsPanel(QWidget): def __init__(self, parent=None): super(charsPanel, self).__init__(parent) # Do the layout: refresh button and filter popup at the top, # with a table below. mainLayout = QVBoxLayout() self.setLayout(mainLayout) topLayout = QHBoxLayout() mainLayout.addLayout(topLayout, 0) self.refreshButton = QPushButton("Refresh") self.filterMenu = QComboBox() topLayout.addWidget(self.refreshButton, 0) topLayout.addStretch(1) topLayout.addWidget(self.filterMenu, 0) self.view = QTableView() self.view.setCornerButtonEnabled(False) self.view.setWordWrap(False) self.view.setAlternatingRowColors(True) mainLayout.addWidget(self.view, 1) # Set up the table model/view. Pass to the model a pointer # to the view so it can query the row under the mouse. self.model = myTableModel(view=self.view) # Interpose a sort filter proxy between the view and the model. self.proxy = mySortFilterProxy(self) self.proxy.setSourceModel(self.model) self.view.setModel(self.proxy) # Hook up the refresh button clicked signal to refresh below self.connect(self.refreshButton, SIGNAL("clicked()"), self.refresh) # Populate the filter popup with rows: # 0 : All - no filter # 1 : not 7-bit - show only things not in the 7-bit code # 2 : not Latin-1 - show only things outside Latin-1 self.filterMenu.addItem(QString("All")) self.filterMenu.addItem(QString("\u00ac" + " 7-bit")) self.filterMenu.addItem(QString("\u00ac" + " Latin-1")) # The filters refer to these properties, called with a QChar C self.lambdaAll = lambda C: True self.lambdaNotAscii = lambda C: (C.unicode() < 32) or (C.unicode() > 126) self.lambdaNotLatin = lambda C: (C.toLatin1() == b"\x00") self.filterLambda = self.lambdaAll # Connect a user-selection in the popup to our filter method. self.connect(self.filterMenu, SIGNAL("activated(int)"), self.filter) # Connect doubleclicked from our table view to self.findThis self.connect(self.view, SIGNAL("doubleClicked(QModelIndex)"), self.findThis) # Connect the model reset signals to functions to place and clear # a status message. self.connect(self.model, SIGNAL("modelAboutToBeReset()"), self.sigResetStarting) self.connect(self.model, SIGNAL("modelReset()"), self.sigResetOver) # This slot receives a double-click on the table. Figure out which # character it is and get the Find panel set up to search for it. def findThis(self, qmi): rep = None if qmi.column() == 3: # doubleclick in entity column, put entity in the replace field rep = qmi.data(Qt.DisplayRole).toString() if qmi.column() != 0: # get reference to column 0 qmi = qmi.sibling(qmi.row(), 0) qs = qmi.data(Qt.DisplayRole).toString() # Call for a find with respect case on, whole word and regex off IMC.findPanel.censusFinder(qs, rep, False, False) # this slot gets the activated(row) signal from the combo-box. # Based on the row, set self.filterLambda to a lambda that will # accept or reject a given QChar value. def filter(self, row): if row == 1: self.filterLambda = self.lambdaNotAscii elif row == 2: self.filterLambda = self.lambdaNotLatin else: self.filterLambda = self.lambdaAll self.model.reset() # This slot receives the main window's docWillChange signal. # It comes with a file path but we can ignore that. def docWillChange(self): # self.view.setSortingEnabled(False) self.model.beginResetModel() # Subroutine to reset the visual appearance of the table view, # invoked on table reset or docHasChanged because on instantiation # we have no data until a file is opened. def setUpTableView(self): self.view.resizeColumnsToContents() self.view.horizontalHeader().setStretchLastSection(True) self.view.resizeRowsToContents() self.view.setSortingEnabled(True) # This slot receives the main window's docHasChanged signal. # Let the table view populate with all-new metadata (or empty # data if the command was File>New). def docHasChanged(self): self.model.endResetModel() self.setUpTableView() # This slot receives the click of the refresh button. Tell the # model we are resetting everything so the view will suck up new # data. Then call our editor to rebuild the metadata. def refresh(self): # self.view.setSortingEnabled(False) self.model.beginResetModel() IMC.editWidget.rebuildMetadata() self.model.endResetModel() self.setUpTableView() # The model emits signals when it is starting to rebuild the table # and when it has finished rebuilding the table. Use these to put up # a status message, as the wait can be significant. def sigResetStarting(self): pqMsgs.showStatusMsg(QString("Rebuilding Character Table...")) def sigResetOver(self): pqMsgs.clearStatusMsg()
class FreezeTableWidget(QTableView): def __init__(self, parent=None): QTableView.__init__(self, parent) self.freezeNum = 0 self.inited = False self.frozenTableView = QTableView(self) def columnCountChanged (self, old, new): log('columnCountChanged', old, new) def setSetting(self, setting): if self.inited and setting is not None: if 'freezeNum' in setting: self.setFreezeNum(setting['freezeNum']) if 'hideColumns' in setting: for col in range(self.model().columnCount()): if col in setting['hideColumns']: self.hideColumn(col) else: self.showColumn(col) if 'hideRows' in setting: for row in range(self.model().rowCount()): if row in setting['hideRows']: self.hideRow(row) else: self.showRow(row) def setFreezeNum(self, num): self.resizeColumnsToContents() for col in range(num): self.frozenTableView.setColumnHidden(col, False) if not self.isColumnHidden(col): width = self.columnWidth(col) # log('width:', col, width) if width != 0: self.frozenTableView.setColumnWidth(col, width) # self.setColumnHidden(col, False) for col in range(num, self.model().columnCount()): if not self.frozenTableView.isColumnHidden(col): # self.resizeColumnToContents(col) width = self.frozenTableView.columnWidth(col) self.frozenTableView.setColumnHidden(col, True) if width != 0: self.setColumnWidth(col, width) else: self.frozenTableView.setColumnHidden(col, True) #self.viewport().update() self.freezeNum = num #self.frozenTableView.viewport().stackUnder(self) #self.raise_() #self.viewport().stackUnder(self.frozenTableView); self.updateFrozenTableGeometry() # self.resizeColumnsToContents() def myInit(self, model, freezeNum): self.inited = True self.frozenTableView.setSortingEnabled(True) self.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers); self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self.setSortingEnabled(True) self.setModel(model) self.setAlternatingRowColors(True) self.freezeNum = freezeNum self.frozenTableView.setModel(self.model()); self.frozenTableView.setFocusPolicy(QtCore.Qt.NoFocus); self.frozenTableView.verticalHeader().hide(); #self.frozenTableView.horizontalHeader().setResizeMode(QtGui.QHeaderView.Fixed); self.viewport().stackUnder(self.frozenTableView); self.frozenTableView.setStyleSheet("QTableView { border: none;" "background-color: #8EDE21;" "selection-background-color: #999}"); self.frozenTableView.setSelectionModel(self.selectionModel()) self.frozenTableView.setSelectionMode(self.selectionMode()) self.frozenTableView.setSelectionBehavior(self.selectionBehavior()) for col in range(self.freezeNum, self.model().columnCount()): self.frozenTableView.setColumnHidden(col, True) for i in range(self.freezeNum): self.frozenTableView.setColumnWidth(self.freezeNum, self.columnWidth(self.freezeNum) ) self.frozenTableView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff); self.frozenTableView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff); self.frozenTableView.show(); self.setHorizontalScrollMode(self.ScrollPerItem); self.setVerticalScrollMode(self.ScrollPerItem); self.frozenTableView.setVerticalScrollMode(self.ScrollPerItem) self.connect(self.frozenTableView.horizontalHeader(), QtCore.SIGNAL("sortIndicatorChanged (int,Qt::SortOrder)"), self.fSortIndicatorChanged) self.connect(self.horizontalHeader(), QtCore.SIGNAL("sortIndicatorChanged (int,Qt::SortOrder)"), self.sortIndicatorChanged) self.connect(self.horizontalHeader(), QtCore.SIGNAL("sectionResized(int,int,int)"), self.updateSectionWidth) self.connect(self.verticalHeader(), QtCore.SIGNAL("sectionResized(int,int,int)"), self.updateSectionHeight) self.connect(self.frozenTableView.horizontalHeader(), QtCore.SIGNAL("sectionResized(int,int,int)"), self.updateColumn) self.connect(self.frozenTableView.verticalHeader(), QtCore.SIGNAL("sectionResized(int,int,int)"), self.updateRow) self.connect(self.frozenTableView.verticalScrollBar(), QtCore.SIGNAL("valueChanged(int)"), self.verticalScrollBar().setValue) self.connect(self.verticalScrollBar(), QtCore.SIGNAL("valueChanged(int)"), self.frozenTableView.verticalScrollBar().setValue) self.resizeColumnsToContents() self.updateFrozenTableGeometry(); def fSortIndicatorChanged(self, index, sortOrder): if index < self.freezeNum: self.frozenTableView.horizontalHeader().setSortIndicatorShown(True) self.horizontalHeader().setSortIndicatorShown(False) def sortIndicatorChanged(self, index, sortOrder): if index >= self.freezeNum: self.frozenTableView.horizontalHeader().setSortIndicatorShown(False) self.horizontalHeader().setSortIndicatorShown(True) def updateColumn(self, logicalIndex, a, newSize): self.setColumnWidth(logicalIndex,newSize); self.updateFrozenTableGeometry() def updateRow(self, logicalIndex, a, newSize): self.setRowHeight(logicalIndex, newSize) def updateSectionWidth(self, logicalIndex, a, newSize): #if logicalIndex==0 or logicalIndex == 1: self.frozenTableView.setColumnWidth(logicalIndex,newSize); self.updateFrozenTableGeometry() def updateSectionHeight(self, logicalIndex, a, newSize): self.frozenTableView.setRowHeight(logicalIndex, newSize); self.updateFrozenTableGeometry() def resizeEvent(self, event): pass QTableView.resizeEvent(self, event); self.updateFrozenTableGeometry() def moveCursor(self, cursorAction, modifiers): pass current = QTableView.moveCursor(self, cursorAction, modifiers); if cursorAction == self.MoveLeft and current.column()>0 \ and self.visualRect(current).topLeft().x() < self.frozenTableView.columnWidth(0): newValue = self.horizontalScrollBar().value() + self.visualRect(current).topLeft().x() - self.frozenTableView.columnWidth(0) self.horizontalScrollBar().setValue(newValue) return current # def scrollTo(self, index, hint): # pass # #if(index.column()>0): # print 'here' #QTableView.scrollTo(self, index, hint) def updateFrozenTableGeometry(self): width = 0 for i in range(self.freezeNum): width += self.columnWidth(i) self.frozenTableView.setGeometry(self.verticalHeader().sizeHint().width()+self.frameWidth(), \ self.frameWidth(), width, self.viewport().height()+self.horizontalHeader().height())
class TalkEditorApp(FreeseerApp): '''Freeseer talk database editor main gui class''' def __init__(self, config, db): super(TalkEditorApp, self).__init__(config) self.db = db icon = QIcon() icon.addPixmap(QPixmap(':/freeseer/logo.png'), QIcon.Normal, QIcon.Off) self.setWindowIcon(icon) self.resize(960, 600) # # Setup Layout # self.mainWidget = QWidget() self.mainLayout = QVBoxLayout() self.mainWidget.setLayout(self.mainLayout) self.setCentralWidget(self.mainWidget) self.mainLayout.setAlignment(Qt.AlignTop) # Add custom widgets self.commandButtons = CommandButtons() self.tableView = QTableView() self.tableView.setSortingEnabled(True) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.talkDetailsWidget = TalkDetailsWidget() self.importTalksWidget = ImportTalksWidget() self.newTalkWidget = NewTalkWidget() self.mainLayout.addWidget(self.importTalksWidget) #self.mainLayout.addLayout(self.titleLayout) self.mainLayout.addWidget(self.commandButtons) self.mainLayout.addWidget(self.tableView) self.mainLayout.addWidget(self.talkDetailsWidget) self.mainLayout.addWidget(self.importTalksWidget) # --- End Layout # Keep track of index of the most recently selected talk self.currentTalkIndex = QPersistentModelIndex() # Prompt user to "Continue Editing", "Discard Changes" or "Save Changes" self.savePromptBox = QMessageBox() self.savePromptBox.setWindowTitle("Unsaved Changes Exist") self.savePromptBox.setIcon(QMessageBox.Information) self.savePromptBox.setText( "The talk you were editing has unsaved changes.") self.continueButton = self.savePromptBox.addButton( "Continue Editing", QMessageBox.RejectRole) self.discardButton = self.savePromptBox.addButton( "Discard Changes", QMessageBox.DestructiveRole) self.saveButton = self.savePromptBox.addButton("Save Changes", QMessageBox.AcceptRole) self.savePromptBox.setDefaultButton(self.saveButton) # Initialize geometry, to be used for restoring window positioning. self.geometry = None # # Setup Menubar # self.actionExportCsv = QAction(self) self.actionExportCsv.setObjectName('actionExportCsv') self.actionRemoveAll = QAction(self) self.actionRemoveAll.setObjectName('actionRemoveAll') # Actions self.menuFile.insertAction(self.actionExit, self.actionExportCsv) self.menuFile.insertAction(self.actionExit, self.actionRemoveAll) # --- End Menubar # # TableView Connections # self.connect(self.tableView, SIGNAL('activated(const QModelIndex)'), self.click_talk) self.connect(self.tableView, SIGNAL('selected(const QModelIndex)'), self.click_talk) self.connect(self.tableView, SIGNAL('clicked(const QModelIndex)'), self.click_talk) # Import Widget self.connect(self.importTalksWidget.csvRadioButton, SIGNAL('toggled(bool)'), self.toggle_import) self.connect(self.importTalksWidget.importButton, SIGNAL('clicked()'), self.import_talks) self.connect(self.importTalksWidget.cancelButton, SIGNAL('clicked()'), self.hide_import_talks_widget) self.importTalksWidget.setHidden(True) self.connect(self.importTalksWidget.csvFileSelectButton, SIGNAL('clicked()'), self.csv_file_select) self.connect(self.importTalksWidget.csvLineEdit, SIGNAL('returnPressed()'), self.importTalksWidget.importButton.click) self.connect(self.importTalksWidget.rssLineEdit, SIGNAL('returnPressed()'), self.importTalksWidget.importButton.click) self.connect(self.actionExportCsv, SIGNAL('triggered()'), self.export_talks_to_csv) self.connect(self.actionRemoveAll, SIGNAL('triggered()'), self.confirm_reset) # Command Buttons self.connect(self.commandButtons.addButton, SIGNAL('clicked()'), self.click_add_button) self.connect(self.commandButtons.removeButton, SIGNAL('clicked()'), self.remove_talk) self.connect(self.commandButtons.removeAllButton, SIGNAL('clicked()'), self.confirm_reset) self.connect(self.commandButtons.importButton, SIGNAL('clicked()'), self.show_import_talks_widget) self.connect(self.commandButtons.exportButton, SIGNAL('clicked()'), self.export_talks_to_csv) self.connect(self.commandButtons.searchButton, SIGNAL('clicked()'), self.search_talks) self.connect(self.commandButtons.searchLineEdit, SIGNAL('textEdited(QString)'), self.search_talks) self.connect(self.commandButtons.searchLineEdit, SIGNAL('returnPressed()'), self.search_talks) # Talk Details Buttons self.connect(self.talkDetailsWidget.saveButton, SIGNAL('clicked()'), self.update_talk) # Talk Details Widget self.connect(self.talkDetailsWidget.titleLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.presenterLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.categoryLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.eventLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.roomLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.descriptionTextEdit, SIGNAL('modificationChanged(bool)'), self.enable_save) self.connect(self.talkDetailsWidget.dateEdit, SIGNAL('dateChanged(const QDate)'), self.enable_save) self.connect(self.talkDetailsWidget.startTimeEdit, SIGNAL('timeChanged(const QTime)'), self.enable_save) self.connect(self.talkDetailsWidget.endTimeEdit, SIGNAL('timeChanged(const QTime)'), self.enable_save) # New Talk Widget self.newTalkWidget.connect(self.newTalkWidget.addButton, SIGNAL('clicked()'), self.add_talk) self.newTalkWidget.connect(self.newTalkWidget.cancelButton, SIGNAL('clicked()'), self.newTalkWidget.reject) # Load default language actions = self.menuLanguage.actions() for action in actions: if action.data().toString() == self.config.default_language: action.setChecked(True) self.translate(action) break # Load Talk Database self.load_presentations_model() # Setup Autocompletion self.update_autocomplete_fields() self.talkDetailsWidget.saveButton.setEnabled(False) # Select first item #self.tableView.setCurrentIndex(self.proxy.index(0,0)) #self.talk_selected(self.proxy.index(0,0)) # # Translation # def retranslate(self): self.setWindowTitle( self.app.translate("TalkEditorApp", "Freeseer Talk Editor")) # # Reusable Strings # self.confirmDBClearTitleString = self.app.translate( "TalkEditorApp", "Remove All Talks from Database") self.confirmDBClearQuestionString = self.app.translate( "TalkEditorApp", "Are you sure you want to clear the DB?") self.confirmTalkDetailsClearTitleString = self.app.translate( "TalkEditorApp", "Unsaved Data") self.confirmTalkDetailsClearQuestionString = self.app.translate( "TalkEditorApp", "Unsaved talk details will be lost. Continue?") # --- End Reusable Strings # # Menubar # self.actionExportCsv.setText( self.app.translate("TalkEditorApp", "&Export to CSV")) self.actionRemoveAll.setText( self.app.translate("TalkEditorApp", "&Remove All Talks")) # --- End Menubar # # TalkDetailsWidget # self.talkDetailsWidget.titleLabel.setText( self.app.translate("TalkEditorApp", "Title")) self.talkDetailsWidget.presenterLabel.setText( self.app.translate("TalkEditorApp", "Presenter")) self.talkDetailsWidget.categoryLabel.setText( self.app.translate("TalkEditorApp", "Category")) self.talkDetailsWidget.eventLabel.setText( self.app.translate("TalkEditorApp", "Event")) self.talkDetailsWidget.roomLabel.setText( self.app.translate("TalkEditorApp", "Room")) self.talkDetailsWidget.dateLabel.setText( self.app.translate("TalkEditorApp", "Date")) self.talkDetailsWidget.startTimeLabel.setText( self.app.translate("TalkEditorApp", "Start Time")) self.talkDetailsWidget.endTimeLabel.setText( self.app.translate("TalkEditorApp", "End Time")) # --- End TalkDetailsWidget # # Import Talks Widget Translations # self.importTalksWidget.rssRadioButton.setText( self.app.translate("TalkEditorApp", "RSS URL")) self.importTalksWidget.csvRadioButton.setText( self.app.translate("TalkEditorApp", "CSV File")) self.importTalksWidget.importButton.setText( self.app.translate("TalkEditorApp", "Import")) # --- End Talks Widget Translations # # Command Button Translations\ # self.commandButtons.importButton.setText( self.app.translate("TalkEditorApp", "Import")) self.commandButtons.exportButton.setText( self.app.translate("TalkEditorApp", "Export")) self.commandButtons.addButton.setText( self.app.translate("TalkEditorApp", "Add New Talk")) self.commandButtons.removeButton.setText( self.app.translate("TalkEditorApp", "Remove")) self.commandButtons.removeAllButton.setText( self.app.translate("TalkEditorApp", "Remove All")) # --- End Command Butotn Translations # # Search Widget Translations # self.commandButtons.searchButton.setText( self.app.translate("TalkEditorApp", "Search")) # --- End Command Button Translations def load_presentations_model(self): # Load Presentation Model self.presentationModel = self.db.get_presentations_model() self.proxy = QSortFilterProxyModel() self.proxy.setSourceModel(self.presentationModel) self.tableView.setModel(self.proxy) self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive) # Fill table whitespace. self.tableView.horizontalHeader().setStretchLastSection(False) self.tableView.horizontalHeader().setResizeMode(1, QHeaderView.Stretch) # Hide the ID field self.tableView.setColumnHidden(0, True) # Map data to widgets self.mapper = QDataWidgetMapper() self.mapper.setModel(self.proxy) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.addMapping(self.talkDetailsWidget.titleLineEdit, 1) self.mapper.addMapping(self.talkDetailsWidget.presenterLineEdit, 2) self.mapper.addMapping(self.talkDetailsWidget.categoryLineEdit, 4) self.mapper.addMapping(self.talkDetailsWidget.eventLineEdit, 5) self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6) self.mapper.addMapping(self.talkDetailsWidget.descriptionTextEdit, 3) self.mapper.addMapping(self.talkDetailsWidget.dateEdit, 7) self.mapper.addMapping(self.talkDetailsWidget.startTimeEdit, 8) self.mapper.addMapping(self.talkDetailsWidget.endTimeEdit, 9) # Load StringLists self.titleList = QStringList(self.db.get_string_list("Title")) #self.speakerList = QStringList(self.db.get_speaker_list()) #self.categoryList = QStringList(self.db.get_category_list()) #self.eventList = QStringList(self.db.get_event_list()) #self.roomList = QStringList(self.db.get_room_list()) #Disble input self.talkDetailsWidget.disable_input_fields() def search_talks(self): # The default value is 0. If the value is -1, the keys will be read from all columns. self.proxy.setFilterKeyColumn(-1) self.proxy.setFilterFixedString( self.commandButtons.searchLineEdit.text()) def show_save_prompt(self): """Prompts the user to save or discard changes, or continue editing.""" self.savePromptBox.exec_() self.savePromptBox.setDefaultButton(self.saveButton) return self.savePromptBox.clickedButton() def click_talk(self, model): """Warns user if there are unsaved changes, and selects talk clicked by the user.""" log.info("Selecting row %d", model.row()) modelRow = model.row() if self.unsaved_details_exist(): log.info("Unsaved changes exist in row %d", self.currentTalkIndex.row()) confirm = self.show_save_prompt() if confirm == self.saveButton: log.info("Saving changes in row %d...", self.currentTalkIndex.row()) self.tableView.selectRow(self.currentTalkIndex.row()) self.update_talk() newModel = self.tableView.currentIndex().sibling(modelRow, 0) self.select_talk(newModel) elif confirm == self.discardButton: log.info("Discarding changes in row %d...", self.currentTalkIndex.row()) self.talk_selected(model) else: log.info("Continue editing row %d", self.currentTalkIndex.row()) self.tableView.selectRow(self.currentTalkIndex.row()) else: self.talk_selected(model) def click_add_button(self): """Warns user if there are unsaved changes, and shows the New Talk window.""" if self.unsaved_details_exist(): log.info("Unsaved changes exist in row %d", self.currentTalkIndex.row()) confirm = self.show_save_prompt() if confirm == self.saveButton: log.info("Saving changes in row %d...", self.currentTalkIndex.row()) self.update_talk() self.show_new_talk_popup() elif confirm == self.discardButton: log.info("Discarding changes in row %d...", self.currentTalkIndex.row()) # Ensure that changes are discarded self.talk_selected(self.currentTalkIndex) self.show_new_talk_popup() else: log.info("Continue editing row %d", self.currentTalkIndex.row()) else: self.show_new_talk_popup() def talk_selected(self, model): self.mapper.setCurrentIndex(model.row()) self.talkDetailsWidget.enable_input_fields() self.talkDetailsWidget.saveButton.setEnabled(False) self.currentTalkIndex = QPersistentModelIndex(model) def toggle_import(self): if self.importTalksWidget.csvRadioButton.isChecked(): self.importTalksWidget.csvLineEdit.setEnabled(True) self.importTalksWidget.csvFileSelectButton.setEnabled(True) self.importTalksWidget.rssLineEdit.setEnabled(False) else: self.importTalksWidget.csvLineEdit.setEnabled(False) self.importTalksWidget.csvFileSelectButton.setEnabled(False) self.importTalksWidget.rssLineEdit.setEnabled(True) def show_import_talks_widget(self): self.commandButtons.setHidden(True) self.tableView.setHidden(True) self.talkDetailsWidget.setHidden(True) self.importTalksWidget.setHidden(False) def hide_import_talks_widget(self): self.commandButtons.setHidden(False) self.tableView.setHidden(False) self.talkDetailsWidget.setHidden(False) self.importTalksWidget.setHidden(True) def add_talk(self): """Adds a new talk to the database using data from the NewTalkWidget input fields""" presentation = self.create_presentation( self.newTalkWidget.talkDetailsWidget) if presentation: self.db.insert_presentation(presentation) self.newTalkWidget.accept() # Close the dialog def update_talk(self): """Updates the currently selected talk using data from the TalkEditorApp input fields""" selected_talk = self.tableView.currentIndex() if selected_talk.row( ) >= 0: # The tableView index begins at 0 and is -1 by default talk_id = selected_talk.sibling(selected_talk.row(), 0).data().toString() presentation = self.create_presentation(self.talkDetailsWidget) if presentation: self.db.update_presentation(talk_id, presentation) self.apply_changes(selected_talk) self.talkDetailsWidget.saveButton.setEnabled(False) def create_presentation(self, talkDetailsWidget): """Creates and returns an instance of Presentation using data from the input fields""" date = talkDetailsWidget.dateEdit.date() startTime = talkDetailsWidget.startTimeEdit.time() endTime = talkDetailsWidget.endTimeEdit.time() title = unicode(talkDetailsWidget.titleLineEdit.text()).strip() if title: return Presentation( unicode(talkDetailsWidget.titleLineEdit.text()).strip(), unicode(talkDetailsWidget.presenterLineEdit.text()).strip(), unicode(talkDetailsWidget.descriptionTextEdit.toPlainText()). strip(), unicode(talkDetailsWidget.categoryLineEdit.text()).strip(), unicode(talkDetailsWidget.eventLineEdit.text()).strip(), unicode(talkDetailsWidget.roomLineEdit.text()).strip(), unicode(date.toString(Qt.ISODate)), unicode(startTime.toString(Qt.ISODate)), unicode(endTime.toString(Qt.ISODate))) def show_new_talk_popup(self): """Displays a modal dialog with a talk details view When Add is selected, a new talk is added to the database using the input field data. When Cancel is selected, no talk is added. """ log.info('Opening Add Talk window...') self.clear_new_talk_fields() self.remove_new_talk_placeholder_text() self.newTalkWidget.talkDetailsWidget.titleLineEdit.setFocus() if self.newTalkWidget.exec_() == 1: self.apply_changes() self.talkDetailsWidget.disable_input_fields() else: log.info('No talk added...') def apply_changes(self, updated_talk=None): """Repopulates the model to display the effective changes Updates the autocomplete fields. Displays the updated model in the table view, and selects the newly updated/added talk. """ self.presentationModel.select() self.select_talk(updated_talk) self.update_autocomplete_fields() def select_talk(self, talk=None): """Selects the given talk in the table view If no talk is given, the last row in the table view is selected. """ if talk: row = talk.row() column = talk.column() else: row = self.presentationModel.rowCount() - 1 # Select last row column = 0 self.tableView.selectRow(row) self.tableView.setCurrentIndex(self.proxy.index(row, column)) self.talk_selected(self.proxy.index(row, column)) def remove_talk(self): try: rows_selected = self.tableView.selectionModel().selectedRows() except: return # Reversed because rows in list change position once row is removed for row in reversed(rows_selected): self.presentationModel.removeRow(row.row()) self.talkDetailsWidget.clear_input_fields() self.talkDetailsWidget.disable_input_fields() def load_talk(self): try: self.tableView.currentIndex().row() except: return self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6) self.presentationModel.select() def reset(self): self.db.clear_database() self.presentationModel.select() self.talkDetailsWidget.clear_input_fields() self.talkDetailsWidget.disable_input_fields() def confirm_reset(self): """Presents a confirmation dialog to ask the user if they are sure they wish to remove the talk database. If Yes call the reset() function""" confirm = QMessageBox.question(self, self.confirmDBClearTitleString, self.confirmDBClearQuestionString, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if confirm == QMessageBox.Yes: self.reset() def add_talks_from_rss(self): rss_url = unicode(self.importTalksWidget.rssLineEdit.text()) if rss_url: self.db.add_talks_from_rss(rss_url) self.presentationModel.select() self.hide_import_talks_widget() else: error = QMessageBox() error.setText("Please enter a RSS URL") error.exec_() def closeEvent(self, event): if self.unsaved_details_exist(): log.info("Unsaved changes exist in row %d", self.currentTalkIndex.row()) confirm = self.show_save_prompt() if confirm == self.saveButton: log.info("Saving changes in row %d...", self.currentTalkIndex.row()) self.update_talk() log.info('Exiting talk database editor...') self.geometry = self.saveGeometry() event.accept() elif confirm == self.discardButton: log.info("Discarding changes in row %d...", self.currentTalkIndex.row()) # Ensure that changes are discarded self.talk_selected(self.currentTalkIndex) log.info('Exiting talk database editor...') self.geometry = self.saveGeometry() event.accept() else: log.info("Continue editing row %d", self.currentTalkIndex.row()) event.ignore() else: log.info('Exiting talk database editor...') self.geometry = self.saveGeometry() event.accept() def csv_file_select(self): fname = QFileDialog.getOpenFileName(self, 'Select file', "", "*.csv") if fname: self.importTalksWidget.csvLineEdit.setText(fname) def add_talks_from_csv(self): fname = self.importTalksWidget.csvLineEdit.text() if fname: self.db.add_talks_from_csv(fname) self.presentationModel.select() self.hide_import_talks_widget() else: error = QMessageBox() error.setText("Please select a file") error.exec_() def import_talks(self): if self.importTalksWidget.csvRadioButton.isChecked(): self.add_talks_from_csv() else: self.add_talks_from_rss() self.update_autocomplete_fields() def export_talks_to_csv(self): fname = QFileDialog.getSaveFileName(self, 'Select file', "", "*.csv") if fname: self.db.export_talks_to_csv(fname) def update_autocomplete_fields(self): self.titleList = QStringList(self.db.get_string_list("Title")) self.speakerList = QStringList(self.db.get_string_list("Speaker")) self.categoryList = QStringList(self.db.get_string_list("Category")) self.eventList = QStringList(self.db.get_string_list("Event")) self.roomList = QStringList(self.db.get_string_list("Room")) self.titleCompleter = QCompleter(self.titleList) self.titleCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.speakerCompleter = QCompleter(self.speakerList) self.speakerCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.categoryCompleter = QCompleter(self.categoryList) self.categoryCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.eventCompleter = QCompleter(self.eventList) self.eventCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.roomCompleter = QCompleter(self.roomList) self.roomCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.talkDetailsWidget.titleLineEdit.setCompleter(self.titleCompleter) self.talkDetailsWidget.presenterLineEdit.setCompleter( self.speakerCompleter) self.talkDetailsWidget.categoryLineEdit.setCompleter( self.categoryCompleter) self.talkDetailsWidget.eventLineEdit.setCompleter(self.eventCompleter) self.talkDetailsWidget.roomLineEdit.setCompleter(self.roomCompleter) def are_fields_enabled(self): return (self.talkDetailsWidget.titleLineEdit.isEnabled() and self.talkDetailsWidget.presenterLineEdit.isEnabled() and self.talkDetailsWidget.categoryLineEdit.isEnabled() and self.talkDetailsWidget.eventLineEdit.isEnabled() and self.talkDetailsWidget.roomLineEdit.isEnabled() and self.talkDetailsWidget.dateEdit.isEnabled() and self.talkDetailsWidget.startTimeEdit.isEnabled() and self.talkDetailsWidget.endTimeEdit.isEnabled()) def unsaved_details_exist(self): """Checks if changes have been made to new/existing talk details Looks for text in the input fields and check the enabled state of the Save Talk button If the Save Talk button is enabled, the input fields contain modified values """ return (self.talkDetailsWidget.saveButton.isEnabled() and (self.talkDetailsWidget.titleLineEdit.text() or self.talkDetailsWidget.presenterLineEdit.text() or self.talkDetailsWidget.categoryLineEdit.text() or self.talkDetailsWidget.descriptionTextEdit.toPlainText())) def enable_save(self): self.talkDetailsWidget.saveButton.setEnabled(True) def clear_new_talk_fields(self): """Removes existing data from all NewTalkWidget fields except event, room, date and time""" self.newTalkWidget.talkDetailsWidget.titleLineEdit.clear() self.newTalkWidget.talkDetailsWidget.presenterLineEdit.clear() self.newTalkWidget.talkDetailsWidget.descriptionTextEdit.clear() self.newTalkWidget.talkDetailsWidget.categoryLineEdit.clear() def remove_new_talk_placeholder_text(self): """Removes placeholder text in NewTalkWidget originally set by TalkDetailsWidget""" self.newTalkWidget.talkDetailsWidget.titleLineEdit.setPlaceholderText( "") self.newTalkWidget.talkDetailsWidget.presenterLineEdit.setPlaceholderText( "") self.newTalkWidget.talkDetailsWidget.categoryLineEdit.setPlaceholderText( "") self.newTalkWidget.talkDetailsWidget.eventLineEdit.setPlaceholderText( "") self.newTalkWidget.talkDetailsWidget.roomLineEdit.setPlaceholderText( "")
class BranchView(QWidget): """ This is a widget containing the tableView and the ButtonLineEdit with the branch name. """ def __init__(self, parent, model, checkbox, all_models): QWidget.__init__(self, parent) self._ui = Ui_BranchView() self._ui.setupUi(self) self._model = model self._all_models = all_models self._parent = parent self._table_view = QTableView(parent) self._name_widget = ButtonLineEdit(model, checkbox, all_models, self) self._ui.layout.addWidget(self._name_widget, 0, 0) self._ui.layout.addWidget(self._table_view, 1, 0) self._hidden_rows_from_models = [] self.set_model(model) self.connect_signals() def connect_signals(self): """ Connect the right signals to the right slots. """ connect(self._table_view, SIGNAL("customContextMenuRequested(const QPoint&)"), self.context_menu) signals = "activated(const QModelIndex&)", "clicked(const QModelIndex&)" for signal in signals: connect(self._table_view, SIGNAL(signal), self.fwd_commit_clicked) connect(self._name_widget, SIGNAL("newHistAction"), self.fwd_new_hist_action) connect(self._name_widget, SIGNAL("hideDataFromModel"), self.hide_data) connect(self._name_widget, SIGNAL("unhideDataFromModel"), self.unhide_data) connect(self._name_widget, SIGNAL("showColumn"), self.show_column) connect(self._name_widget, SIGNAL("hideColumn"), self.hide_column) def fwd_commit_clicked(self, index): """ Simple signal forwarder to RebaseMainClass. """ self.emit(SIGNAL("activated(const QModelIndex&)"), index) def fwd_new_hist_action(self, action): """ Simple signal forwarder to RebaseMainClass. """ self.emit(SIGNAL("newHistAction"), action) def unhide_data(self): """ Unhide previously hidden data from another model. """ # Un-forbid dropping on a reduced view of the model self._table_view.setDragDropMode(self._table_view.DragDrop) for row in self._hidden_rows_from_models: self._table_view.showRow(row) self._hidden_rows_from_models = [] def hide_data(self, data): """ Hide certain rows of the table view model based on the given data list. :param data: The list of commits used to hide rows of the table view. The list is build like: [ [authored_timestamp, author_name, commit_message], ... ] """ self.unhide_data() # Forbid dropping on a reduced view of the model self._table_view.setDragDropMode(self._table_view.DragOnly) for row in xrange(self._model.rowCount()): if to_hide_subset(self._model, row) in data: self._table_view.hideRow(row) self._hidden_rows_from_models.append(row) def show_column(self, column): """ Show the given column of the table view. """ column_position = self._model.get_columns().index(column) self._table_view.showColumn(column_position) self.resize_table_view() def hide_column(self, column): """ Hide the given column of the table view. """ column_position = self._model.get_columns().index(column) self._table_view.hideColumn(column_position) self.resize_table_view() def context_menu(self, q_point): """ Creates a menu with the actions: - copy - delete - paste after - paste before """ menu = QMenu(self._parent) table_view = self._table_view indexes = table_view.selectedIndexes() selected_rows = set([index.row() for index in indexes]) copy_data = self._parent.get_copy_data() copy_action = menu.addAction("Copy") delete_action = menu.addAction("Delete") paste_after_action = menu.addAction("Paste after") paste_after_action.setDisabled(copy_data == "") paste_before_action = menu.addAction("Paste before") paste_before_action.setDisabled(copy_data == "") create_branch_action = menu.addAction("Create branch from this commit") chosen_action = menu.exec_(table_view.viewport().mapToGlobal(q_point)) if chosen_action == delete_action: self.remove_rows() elif chosen_action == copy_action: self.emit(SIGNAL("newCopiedData"), table_view.model().mimeData(indexes)) elif chosen_action == paste_after_action: drop_after = max(selected_rows) + 1 table_view.model().dropMimeData(copy_data, Qt.CopyAction, drop_after, 0, self.parent()) elif chosen_action == paste_before_action: drop_before = min(selected_rows) table_view.model().dropMimeData(copy_data, Qt.CopyAction, drop_before, 0, self.parent()) elif chosen_action == create_branch_action: self.emit(SIGNAL("newBranchFromCommit"), indexes) def remove_rows(self, rows=False): """ When <Del> is pressed, this method removes the selected rows of the table view. We delete the rows starting with the last one, in order to use the correct indexes. :param rows: This is intended for tests. It's a list of index rows. """ remove_selected_rows(self._table_view, self._parent, rows) def model(self): """ Return the QTableView model. """ return self._model def set_model(self, model): """ Sets the QTableView model and the label's name. """ table_view = self._table_view table_view.setModel(model) self._model = model show_fields = ["hexsha", "message"] self._name_widget.inform_shown_columns(show_fields) for column, field in enumerate(model.get_columns()): if not field in show_fields: table_view.hideColumn(column) table_view.setSelectionMode(table_view.ExtendedSelection) table_view.setDragDropMode(table_view.DragDrop) table_view.setSelectionBehavior(table_view.SelectRows) table_view.setEditTriggers(table_view.NoEditTriggers) table_view.setContextMenuPolicy(Qt.CustomContextMenu) self.resize_table_view() def resize_table_view(self): """ Resize the table view to its contents. """ custom_resize_columns_to_contents(self._table_view) self._table_view.horizontalHeader().setStretchLastSection(True) def show_modifications(self): """ Show modifications of the branch view and name. """ self._table_view.setModel(self._model) self._name_widget.show_modifications() def hide_modifications(self): """ Hide modifications of the branch view and name. """ if hasattr(self._model, 'get_orig_q_git_model') and \ self._model.get_orig_q_git_model(): model = self._model.get_orig_q_git_model() self._table_view.setModel(model) self._name_widget.hide_modifications() def reset_displayed_name(self): self._name_widget.reset_displayed_name() def tableview_has_focus(self): return self._table_view.hasFocus()
class ClusterWidget(QSplitter): def __init__(self, peaks, parent=None): QSplitter.__init__(self, Qt.Vertical, parent) self.peaks = peaks self.choosenOne = [pe for pe in self.peaks if pe is not None][0] #self.peakModel = QStandardItemModel() self.identificationModel = QStandardItemModel() self.setupUi() self.setModel() self.connect(self.calcCorr, SIGNAL('pressed()'), self.setRankValue) #self.setRankValue() def setupUi(self): self.widget = MSView(MSQtCanvas(self.peaks, "peaks@%s"%str(self.peaks[0]), labels={'bottom':'RT(s)', 'left':'INTENSITY'}, flags='peak')) self.tableView = QTableView() self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.setSortingEnabled(True) self.corr = QLabel("Nan") self.calcCorr = QPushButton("r_coef:") #v = QVBoxLayout(self) self.addWidget(self.widget) self.wid = QWidget() vb = QVBoxLayout() vb.addWidget(self.calcCorr) vb.addWidget(self.corr) hb = QHBoxLayout(self.wid) #if self.choosenOne.formulas: hb.addWidget(self.tableView) #else: # hb.addWidget(QLabel("Identification not performed yet...")) hb.addLayout(vb) self.addWidget(self.wid) def setModel(self): from gui.MetBaseGui import MSStandardItem #we assume that the different peaks have the same identifiers #TODO: may have to merge several stuffs later if self.choosenOne.formulas: self.identificationModel.setHorizontalHeaderLabels(["score", "formula", "diff mass", "names"]) for i, f in enumerate(self.choosenOne.formulas.iterkeys()): self.identificationModel.setItem(i, 0, MSStandardItem(str(self.choosenOne.formulas[f]["score"]))) self.identificationModel.setItem(i, 1, QStandardItem(str(f))) self.identificationModel.setItem(i, 2, MSStandardItem(str(self.choosenOne.formulas[f]["diffmass"]))) self.identificationModel.setItem(i, 3, QStandardItem(self.choosenOne.formulas[f]["names"])) if self.choosenOne.formulas[f]["names"] != 'Not Found': for j in xrange(4): self.identificationModel.item(i, j).setBackground(QBrush(Qt.green)) else: for j in xrange(4): self.identificationModel.item(i, j).setBackground(QBrush(Qt.red)) self.tableView.setModel(self.identificationModel) def setRankValue(self): #m = qApp.instance().model #m.pearsonIntraCalculation() #peaks =[] #for spl in m: # peaks+=[p.r_coef for p in spl.mappedPeaks if p.r_coef] #if not self.choosenOne.r_coef: self.choosenOne.pCalcBasedOnPeakShape() #from _bisect import bisect_left #x = bisect_left(sorted(peaks), self.choosenOne.r_coef) s = '<br><b>%f</b></br>'%np.round(self.choosenOne.r_coef, 4) #s+='<br><b>Rank: </b>%d</br>'%abs(len(peaks)-x) self.corr.setText(s)
class TalkEditorApp(FreeseerApp): '''Freeseer talk database editor main gui class''' def __init__(self, config, db): FreeseerApp.__init__(self) self.config = config self.db = db icon = QIcon() icon.addPixmap(QPixmap(':/freeseer/logo.png'), QIcon.Normal, QIcon.Off) self.setWindowIcon(icon) self.resize(960, 600) # # Setup Layout # self.mainWidget = QWidget() self.mainLayout = QVBoxLayout() self.mainWidget.setLayout(self.mainLayout) self.setCentralWidget(self.mainWidget) self.mainLayout.setAlignment(QtCore.Qt.AlignTop) # Add the Title Row (Use BOLD / Big Font) #self.titleLayout = QHBoxLayout() #self.backButton = QPushButton('Back to Recorder') #if backButton: # Only show the back button if requested by caller # self.titleLayout.addWidget(self.backButton) #self.titleLayout.addStretch() # Add custom widgets self.commandButtons = CommandButtons() self.tableView = QTableView() self.tableView.setSortingEnabled(True) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.talkDetailsWidget = TalkDetailsWidget() self.importTalksWidget = ImportTalksWidget() self.mainLayout.addWidget(self.importTalksWidget) #self.mainLayout.addLayout(self.titleLayout) self.mainLayout.addWidget(self.commandButtons) self.mainLayout.addWidget(self.tableView) self.mainLayout.addWidget(self.talkDetailsWidget) self.mainLayout.addWidget(self.importTalksWidget) # --- End Layout # Initialize geometry, to be used for restoring window positioning. self.geometry = None # # Setup Menubar # self.actionExportCsv = QAction(self) self.actionExportCsv.setObjectName('actionExportCsv') self.actionRemoveAll = QAction(self) self.actionRemoveAll.setObjectName('actionRemoveAll') # Actions self.menuFile.insertAction(self.actionExit, self.actionExportCsv) self.menuFile.insertAction(self.actionExit, self.actionRemoveAll) # --- End Menubar # # TableView Connections # self.connect(self.tableView, SIGNAL('activated(const QModelIndex)'), self.talk_selected) self.connect(self.tableView, SIGNAL('selected(const QModelIndex)'), self.talk_selected) self.connect(self.tableView, SIGNAL('clicked(const QModelIndex)'), self.talk_selected) # Import Widget self.connect(self.importTalksWidget.csvRadioButton, SIGNAL('toggled(bool)'), self.toggle_import) self.connect(self.importTalksWidget.importButton, SIGNAL('clicked()'), self.import_talks) self.connect(self.importTalksWidget.cancelButton, SIGNAL('clicked()'), self.hide_import_talks_widget) self.importTalksWidget.setHidden(True) self.connect(self.importTalksWidget.csvFileSelectButton, QtCore.SIGNAL('clicked()'), self.csv_file_select) self.connect(self.importTalksWidget.csvLineEdit, QtCore.SIGNAL('returnPressed()'), self.importTalksWidget.importButton.click) self.connect(self.importTalksWidget.rssLineEdit, QtCore.SIGNAL('returnPressed()'), self.importTalksWidget.importButton.click) self.connect(self.actionExportCsv, QtCore.SIGNAL('triggered()'), self.export_talks_to_csv) self.connect(self.actionRemoveAll, QtCore.SIGNAL('triggered()'), self.confirm_reset) # Command Buttons self.connect(self.commandButtons.removeButton, SIGNAL('clicked()'), self.remove_talk) self.connect(self.commandButtons.removeAllButton, SIGNAL('clicked()'), self.confirm_reset) self.connect(self.commandButtons.importButton, SIGNAL('clicked()'), self.show_import_talks_widget) self.connect(self.commandButtons.exportButton, SIGNAL('clicked()'), self.export_talks_to_csv) self.connect(self.commandButtons.searchButton, SIGNAL('clicked()'), self.search_talks) self.connect(self.commandButtons.searchLineEdit, SIGNAL('textEdited(QString)'), self.search_talks) self.connect(self.commandButtons.searchLineEdit, SIGNAL('returnPressed()'), self.search_talks) # Talk Details Buttons self.connect(self.talkDetailsWidget.addButton, SIGNAL('clicked()'), self.clear_talk_details_widget) self.connect(self.talkDetailsWidget.saveButton, SIGNAL('clicked()'), self.add_talk) # Load default language actions = self.menuLanguage.actions() for action in actions: if action.data().toString() == self.config.default_language: action.setChecked(True) self.translate(action) break # Load Talk Database self.load_presentations_model() # Setup Autocompletion self.update_autocomple_fields() # Select first item #self.tableView.setCurrentIndex(self.proxy.index(0,0)) #self.talk_selected(self.proxy.index(0,0)) # # Translation # def retranslate(self): self.setWindowTitle(self.app.translate("TalkEditorApp", "Freeseer Talk Editor")) # # Reusable Strings # self.confirmDBClearTitleString = self.app.translate("TalkEditorApp", "Remove All Talks from Database") self.confirmDBClearQuestionString = self.app.translate("TalkEditorApp", "Are you sure you want to clear the DB?") # --- End Reusable Strings # # Menubar # self.actionExportCsv.setText(self.app.translate("TalkEditorApp", "&Export to CSV")) self.actionRemoveAll.setText(self.app.translate("TalkEditorApp", "&Remove All Talks")) # --- End Menubar # # TalkDetailsWidget # self.talkDetailsWidget.titleLabel.setText(self.app.translate("TalkEditorApp", "Title")) self.talkDetailsWidget.presenterLabel.setText(self.app.translate("TalkEditorApp", "Presenter")) self.talkDetailsWidget.categoryLabel.setText(self.app.translate("TalkEditorApp", "Category")) self.talkDetailsWidget.eventLabel.setText(self.app.translate("TalkEditorApp", "Event")) self.talkDetailsWidget.roomLabel.setText(self.app.translate("TalkEditorApp", "Room")) self.talkDetailsWidget.dateLabel.setText(self.app.translate("TalkEditorApp", "Date")) self.talkDetailsWidget.timeLabel.setText(self.app.translate("TalkEditorApp", "Time")) # --- End TalkDetailsWidget # # Import Talks Widget Translations # self.importTalksWidget.rssRadioButton.setText(self.app.translate("TalkEditorApp", "RSS URL")) self.importTalksWidget.csvRadioButton.setText(self.app.translate("TalkEditorApp", "CSV File")) self.importTalksWidget.importButton.setText(self.app.translate("TalkEditorApp", "Import")) # --- End Talks Widget Translations # # Command Button Translations\ # #self.commandButtons.addButton.setText(self.app.translate("TalkEditorApp", "Add")) self.commandButtons.importButton.setText(self.app.translate("TalkEditorApp", "Import")) self.commandButtons.exportButton.setText(self.app.translate("TalkEditorApp", "Export")) self.commandButtons.removeButton.setText(self.app.translate("TalkEditorApp", "Remove")) self.commandButtons.removeAllButton.setText(self.app.translate("TalkEditorApp", "Remove All")) # --- End Command Butotn Translations # # Search Widget Translations # self.commandButtons.searchButton.setText(self.app.translate("TalkEditorApp", "Search")) # --- End Command Button Translations def load_presentations_model(self): # Load Presentation Model self.presentationModel = self.db.get_presentations_model() self.proxy = QSortFilterProxyModel() self.proxy.setSourceModel(self.presentationModel) self.tableView.setModel(self.proxy) self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) # Fill table whitespace. self.tableView.horizontalHeader().setStretchLastSection(False) self.tableView.horizontalHeader().setResizeMode(1, QHeaderView.Stretch) # Hide the ID field self.tableView.setColumnHidden(0, True) # Map data to widgets self.mapper = QDataWidgetMapper() self.mapper.setModel(self.proxy) self.mapper.addMapping(self.talkDetailsWidget.titleLineEdit, 1) self.mapper.addMapping(self.talkDetailsWidget.presenterLineEdit, 2) self.mapper.addMapping(self.talkDetailsWidget.categoryLineEdit, 4) self.mapper.addMapping(self.talkDetailsWidget.eventLineEdit, 5) self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6) self.mapper.addMapping(self.talkDetailsWidget.descriptionTextEdit, 3) self.mapper.addMapping(self.talkDetailsWidget.dateEdit, 7) self.mapper.addMapping(self.talkDetailsWidget.timeEdit, 8) # Load StringLists self.titleList = QStringList(self.db.get_string_list("Title")) #self.speakerList = QStringList(self.db.get_speaker_list()) #self.categoryList = QStringList(self.db.get_category_list()) #self.eventList = QStringList(self.db.get_event_list()) #self.roomList = QStringList(self.db.get_room_list()) #Disble input self.talkDetailsWidget.disable_input_fields() def search_talks(self): # The default value is 0. If the value is -1, the keys will be read from all columns. self.proxy.setFilterKeyColumn(-1) self.proxy.setFilterFixedString(self.commandButtons.searchLineEdit.text()) def talk_selected(self, model): self.talkDetailsWidget.saveButton.setEnabled(False) self.mapper.setCurrentIndex(model.row()) self.talkDetailsWidget.enable_input_fields() def toggle_import(self): if self.importTalksWidget.csvRadioButton.isChecked(): self.importTalksWidget.csvLineEdit.setEnabled(True) self.importTalksWidget.csvFileSelectButton.setEnabled(True) self.importTalksWidget.rssLineEdit.setEnabled(False) else: self.importTalksWidget.csvLineEdit.setEnabled(False) self.importTalksWidget.csvFileSelectButton.setEnabled(False) self.importTalksWidget.rssLineEdit.setEnabled(True) def show_import_talks_widget(self): self.commandButtons.setHidden(True) self.tableView.setHidden(True) self.talkDetailsWidget.setHidden(True) self.importTalksWidget.setHidden(False) def hide_import_talks_widget(self): self.commandButtons.setHidden(False) self.tableView.setHidden(False) self.talkDetailsWidget.setHidden(False) self.importTalksWidget.setHidden(True) def add_talk(self): date = self.talkDetailsWidget.dateEdit.date() time = self.talkDetailsWidget.timeEdit.time() #datetime = QtCore.QDateTime(date, time) presentation = Presentation( unicode(self.talkDetailsWidget.titleLineEdit.text()), unicode(self.talkDetailsWidget.presenterLineEdit.text()), unicode(self.talkDetailsWidget.descriptionTextEdit.toPlainText()), unicode(self.talkDetailsWidget.categoryLineEdit.text()), unicode(self.talkDetailsWidget.eventLineEdit.text()), unicode(self.talkDetailsWidget.roomLineEdit.text()), unicode(date.toString(QtCore.Qt.ISODate)), unicode(time.toString(QtCore.Qt.ISODate))) # Do not add talks if they are empty strings if (len(presentation.title) == 0): return self.db.insert_presentation(presentation) # Update Model, Refreshes TableView self.presentationModel.select() # Select Last Row self.tableView.selectRow(self.presentationModel.rowCount() - 1) self.tableView.setCurrentIndex(self.proxy.index(self.proxy.rowCount() - 1, 0)) self.talk_selected(self.proxy.index(self.proxy.rowCount() - 1, 0)) self.update_autocomple_fields() self.talkDetailsWidget.disable_input_fields() def clear_talk_details_widget(self): self.talkDetailsWidget.saveButton.setEnabled(True) self.talkDetailsWidget.enable_input_fields() self.talkDetailsWidget.titleLineEdit.clear() self.talkDetailsWidget.presenterLineEdit.clear() self.talkDetailsWidget.descriptionTextEdit.clear() #self.talkDetailsWidget.categoryLineEdit.clear() #self.talkDetailsWidget.eventLineEdit.clear() #self.talkDetailsWidget.roomLineEdit.clear() self.presentationModel.select() def remove_talk(self): try: rows_selected = self.tableView.selectionModel().selectedRows() except: return # Reversed because rows in list change position once row is removed for row in reversed(rows_selected): self.presentationModel.removeRow(row.row()) def load_talk(self): try: self.tableView.currentIndex().row() except: return self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6) self.presentationModel.select() def reset(self): self.db.clear_database() self.presentationModel.select() def confirm_reset(self): """Presents a confirmation dialog to ask the user if they are sure they wish to remove the talk database. If Yes call the reset() function""" confirm = QMessageBox.question(self, self.confirmDBClearTitleString, self.confirmDBClearQuestionString, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if confirm == QMessageBox.Yes: self.reset() def add_talks_from_rss(self): rss_url = unicode(self.importTalksWidget.rssLineEdit.text()) if rss_url: self.db.add_talks_from_rss(rss_url) self.presentationModel.select() self.hide_import_talks_widget() else: error = QMessageBox() error.setText("Please enter a RSS URL") error.exec_() def closeEvent(self, event): log.info('Exiting talk database editor...') self.geometry = self.saveGeometry() event.accept() def csv_file_select(self): fname = QFileDialog.getOpenFileName( self, 'Select file', "", "*.csv") if fname: self.importTalksWidget.csvLineEdit.setText(fname) def add_talks_from_csv(self): fname = self.importTalksWidget.csvLineEdit.text() if fname: self.db.add_talks_from_csv(fname) self.presentationModel.select() self.hide_import_talks_widget() else: error = QMessageBox() error.setText("Please select a file") error.exec_() def import_talks(self): if self.importTalksWidget.csvRadioButton.isChecked(): self.add_talks_from_csv() else: self.add_talks_from_rss() self.update_autocomple_fields() def export_talks_to_csv(self): fname = QFileDialog.getSaveFileName(self, 'Select file', "", "*.csv") if fname: self.db.export_talks_to_csv(fname) def update_autocomple_fields(self): self.titleList = QStringList(self.db.get_string_list("Title")) self.speakerList = QStringList(self.db.get_string_list("Speaker")) self.categoryList = QStringList(self.db.get_string_list("Category")) self.eventList = QStringList(self.db.get_string_list("Event")) self.roomList = QStringList(self.db.get_string_list("Room")) self.titleCompleter = QCompleter(self.titleList) self.titleCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.speakerCompleter = QCompleter(self.speakerList) self.speakerCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.categoryCompleter = QCompleter(self.categoryList) self.categoryCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.eventCompleter = QCompleter(self.eventList) self.eventCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.roomCompleter = QCompleter(self.roomList) self.roomCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.talkDetailsWidget.titleLineEdit.setCompleter(self.titleCompleter) self.talkDetailsWidget.presenterLineEdit.setCompleter(self.speakerCompleter) self.talkDetailsWidget.categoryLineEdit.setCompleter(self.categoryCompleter) self.talkDetailsWidget.eventLineEdit.setCompleter(self.eventCompleter) self.talkDetailsWidget.roomLineEdit.setCompleter(self.roomCompleter)
class QueueDialog(Window): def __init__(self, base): Window.__init__(self, base, i18n.get('messages_queue')) self.setFixedSize(500, 400) self.last_timestamp = None self.showed = False self.list_ = QTableView() self.list_.setSelectionBehavior(QAbstractItemView.SelectRows) self.list_.clicked.connect(self.__account_clicked) self.caption = QLabel() self.caption.setWordWrap(True) self.caption.setAlignment(Qt.AlignCenter) self.estimated_time = QLabel() self.estimated_time.setWordWrap(True) self.estimated_time.setAlignment(Qt.AlignCenter) self.delete_button = QPushButton(i18n.get('delete')) self.delete_button.setEnabled(False) self.delete_button.setToolTip(i18n.get('delete_selected_message')) self.delete_button.clicked.connect(self.__delete_message) self.clear_button = QPushButton(i18n.get('delete_all')) self.clear_button.setEnabled(False) self.clear_button.setToolTip(i18n.get('delete_all_messages_in_queue')) self.clear_button.clicked.connect(self.__delete_all) button_box = QHBoxLayout() button_box.addStretch(1) button_box.addWidget(self.clear_button) button_box.addWidget(self.delete_button) layout = QVBoxLayout() layout.addWidget(self.list_, 1) layout.addWidget(self.caption) layout.addWidget(self.estimated_time) layout.addLayout(button_box) layout.setSpacing(5) layout.setContentsMargins(5, 5, 5, 5) self.setLayout(layout) def __account_clicked(self, point): self.delete_button.setEnabled(True) self.clear_button.setEnabled(True) def __delete_message(self): self.__disable() selection = self.list_.selectionModel() index = selection.selectedIndexes()[0] message = i18n.get('delete_message_from_queue_confirm') confirmation = self.base.show_confirmation_message( i18n.get('confirm_delete'), message) if not confirmation: self.__enable() return self.base.delete_message_from_queue(index.row()) def __delete_all(self): self.__disable() message = i18n.get('clear_message_queue_confirm') confirmation = self.base.show_confirmation_message( i18n.get('confirm_delete'), message) if not confirmation: self.__enable() return self.base.clear_queue() def __enable(self): self.list_.setEnabled(True) self.delete_button.setEnabled(False) if len(self.base.core.list_statuses_queue()) > 0: self.clear_button.setEnabled(True) else: self.clear_button.setEnabled(False) def __disable(self): self.list_.setEnabled(False) self.delete_button.setEnabled(False) self.clear_button.setEnabled(False) def __on_timeout(self): now = int(time.time()) interval = self.base.core.get_queue_interval() * 60 if self.last_timestamp: est_time = ((self.last_timestamp + interval) - now) / 60 else: est_time = 0 humanized_est_time = self.base.humanize_time_intervals(est_time) next_message = ' '.join( [i18n.get('next_message_should_be_posted_in'), humanized_est_time]) if len(self.base.core.list_statuses_queue()) == 0: self.estimated_time.setText('') else: self.estimated_time.setText(next_message) def start(self): self.timer = QTimer() self.timer.timeout.connect(self.__on_timeout) self.timer.start(60000) def closeEvent(self, event=None): if event: event.ignore() self.hide() self.showed = False def show(self): if self.showed: self.raise_() return self.update() Window.show(self) self.showed = True def update(self): model = QStandardItemModel() model.setHorizontalHeaderItem(0, QStandardItem(i18n.get('account'))) model.setHorizontalHeaderItem(1, QStandardItem(i18n.get('message'))) self.list_.setModel(model) now = int(time.time()) interval = self.base.core.get_queue_interval() * 60 if self.last_timestamp: est_time = ((self.last_timestamp + interval) - now) / 60 else: est_time = 0 row = 0 for status in self.base.core.list_statuses_queue(): username = get_username_from(status.account_id) protocol_image = "%s.png" % get_protocol_from(status.account_id) item = QStandardItem(QString.fromUtf8(username)) item.setIcon(QIcon(self.base.load_image(protocol_image, True))) model.setItem(row, 0, item) model.setItem(row, 1, QStandardItem(QString.fromUtf8(status.text))) row += 1 humanized_interval = self.base.humanize_time_intervals( self.base.core.get_queue_interval()) humanized_est_time = self.base.humanize_time_intervals(est_time) warning = i18n.get('messages_will_be_send') % humanized_interval next_message = ' '.join( [i18n.get('next_message_should_be_posted_in'), humanized_est_time]) self.caption.setText(warning) if row == 0: self.estimated_time.setText('') else: self.estimated_time.setText(next_message) self.list_.horizontalHeader().setResizeMode(1, QHeaderView.Stretch) self.list_.resizeColumnsToContents() self.__enable() def update_timestamp(self): if len(self.base.core.list_statuses_queue()) > 0: self.last_timestamp = int(time.time()) else: self.last_timestamp = None
class Emotion(QtGui.QWidget): EMOTION_DIR = "./resource/expression" WIDTH = 460 HEIGHT = 300 selectChanged = pyqtSignal(str) def __init__(self,parent=None):# super(Emotion,self).__init__(parent) super(Emotion,self).setWindowFlags(QtCore.Qt.Popup) self.resize(QSize(Emotion.WIDTH,Emotion.HEIGHT)) self.setWindowTitle("表情選擇") #self.setModal(True) #self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) self.emotion_initial() def emotion_initial(self): self.emotion_table = QTableView() self.emotion_table.horizontalHeader().setVisible(False) self.emotion_table.verticalHeader().setVisible(False) self.emotion_table.setMouseTracking(True) self.emotion_table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.emotion_table.verticalHeader().setDefaultSectionSize(30) self.emotion_table.horizontalHeader().setDefaultSectionSize(30) self.emotion_table.setIconSize(QSize(30,30)) self.emotion_table.entered.connect(self.showEmotionTips) self.emotion_model = QStandardItemModel() emotions = os.listdir(Emotion.EMOTION_DIR) i = 0 emotions_size = len(emotions) emotions = sorted(emotions,cmp=emotioncmp) while i < emotions_size: self.add_emotion(emotions[i:i+14]) i = i + 14 self.emotion_table.setModel(self.emotion_model) self.emotion_table.clicked.connect(self.emotion_click) # mainLayout=QVBoxLayout() mainLayout.addWidget(self.emotion_table) self.setLayout(mainLayout) #self. def showEmotionTips(self,index): if index.isValid(): QToolTip.showText(QCursor.pos(), "Hello", None) def add_emotion(self,emotions): ''' :param emotions a list of emotion will be adding to emotion table ''' cells = [] for emotion in emotions: item = QtGui.QStandardItem(QIcon(os.path.join(Emotion.EMOTION_DIR,emotion)),emotion) cells.append(item) self.emotion_model.appendRow(cells) #def eventFilter(self, event): #p = QCursor.pos() - self.pos() #item = self.emotion_table def emotion_click(self): row = self.emotion_table.currentIndex().row() column = self.emotion_table.currentIndex().column() #self.accept() self.close() self.selectChanged.emit(self.get_selected_emotion(row,column)) def get_selected_emotion(self,row,column): emotion = self.emotion_model.data(self.emotion_model.index(row, column)) if emotion: return str(emotion.toString()) else: return "N/A"
class MSMainWindow(QMainWindow): """Gui of the main window""" #MAX_RECENT_FILES = 10 #start putting links spyder numpy scipy et tutti quanti links=('http://numpy.scipy.org/', 'http://packages.python.org/spyder/', 'http://www.riverbankcomputing.co.uk/software/pyqt/intro') pluginPath=path.normcase('pluginmanager/plugins/') def __init__(self, availablePlugins): """ Constructor with all the models needed setup menus """ QMainWindow.__init__(self) self.setDockOptions(QMainWindow.VerticalTabs | QMainWindow.AnimatedDocks) self.plugins = availablePlugins self.pluginsInst=[] settings=QSettings('INRA/INSA', '-'.join([QApplication.instance().APPLICATION_NAME_STR, QApplication.instance().VERSION_STR])) self.recentFiles = list(settings.value("RecentFiles").toStringList()) self.setStyleSheet(stylesheet) self.pipeline = MSPipelineToolBar("Pipeline toolbar", parent=self) self.addToolBar(0x1,self.pipeline) self._setupModels() self._setupUi() self._setupMenus() def _setupModels(self): """ Warning:Causes segfault when horizontal labels set to True on aura peu etre a la fin un model par sampleList c'est ce qui parait le plus logique """ #drag and drop table sample self.sampleModel = QStandardItemModel(self) self.sampleModel.setHorizontalHeaderLabels(["Sample", "Class"]) #treeView1 self.spectraModel = QStandardItemModel(self) #treeview2 self.peakModel = QStandardItemModel(self) #treeview3 self.clusterModel = QStandardItemModel(self) def _setupMenus(self): #file self.fileMenu = QMenu('&File') self.fileMenu.setTearOffEnabled(True) self.op=QMenu("&Open...",self.fileMenu) self.op.setIcon(QIcon(path.normcase("gui/icons/fileopen.png"))) open_=QAction("&Open rawfiles", self) open_.setToolTip("Open an mzXML or netCDF file") open_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_O)) open_icon=QIcon(path.normcase("gui/icons/fileopen.png")) open_.setIcon(open_icon) self.op.addAction(open_) load_=QAction("&Open projects...", self) load_.setToolTip("load binary file containing saved objects") load_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S)) load_icon=QIcon(QPixmap(path.normcase("gui/icons/project_open.png"))) load_.setIcon(load_icon) self.op.addAction(load_) self.fileMenu.addMenu(self.op) save_=QAction("&Save...", self) save_.setToolTip("save the actual application model") save_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S)) save_icon=QIcon(path.normcase("gui/icons/save_all.png")) save_.setIcon(save_icon) self.fileMenu.addAction(save_) pkl = QAction("&load a peaklist", self) #TODO:load peaklist pkl.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_P)) pkl.setToolTip("load a peaklist and process it") pkl.setIcon(QIcon(path.normcase("gui/icons/featuredetect.png"))) self.fileMenu.addAction(pkl) convert_=QAction("&Convert...", self) convert_.setEnabled(False) convert_.setToolTip("Convert a .wiff file if Analyst(c) is installed") convert_icon=QIcon(path.normcase("gui/icons/goto.png")) convert_.setIcon(convert_icon) self.fileMenu.addAction(convert_) a = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Launch a batch") a.setEnabled(False) b = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Merge") b.setToolTip("Merge MRM file") #b.setEnabled(False) self.fileMenu.addSeparator() # # for i in xrange(self.MAX_RECENT_FILES): # a = QAction('', self) # a.setVisible(False) # self.fileMenu.addAction(a) # # for i in xrange(min(self.MAX_RECENT_FILES, len(self.recentFiles))): # self.fileMenu.actions()[5+i].setVisible(True) # self.fileMenu.actions()[5+i].setText(self.recentFiles[i].split('/')[-1]) exit_action =QAction("&Exit", self) exit_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q)) exit_action.setIcon(QIcon(QPixmap(path.normcase('gui/icons/exit.png')))) self.fileMenu.addAction(exit_action) self.menuBar().addMenu(self.fileMenu) self.editMenu=QMenu("&Edit") self.editMenu.setTearOffEnabled(True) self.editMenu.addAction(QIcon(path.normcase('gui/icons/edit_undo.png')), '&Undo...') self.editMenu.addAction(QIcon(path.normcase('gui/icons/edit_redo.png')), '&Redo...') self.editMenu.actions()[0].setEnabled(False) self.editMenu.actions()[1].setEnabled(False) self.editMenu.addSeparator() self.editMenu.addAction(QIcon(path.normcase('gui/icons/run.png')), '&Preferences') self.exportMenu = QMenu("&Export...") self.exportMenu.setIcon(QIcon(path.normcase('gui/icons/file_export.png'))) self.exportMenu.addAction("&Peaklist") self.exportMenu.addAction("&Clusters intensity matrix") self.editMenu.addMenu(self.exportMenu) self.menuBar().addMenu(self.editMenu) #view self.viewMenu =QMenu("&View") self.viewMenu.setTearOffEnabled(True) self.viewMenu.addAction(QIcon(path.normcase('gui/icons/window_duplicate')), "&Cascade View", self.mdiArea.cascadeSubWindows, QKeySequence(Qt.CTRL + Qt.Key_K)) self.viewMenu.addAction(QIcon(path.normcase('gui/icons/view_icon')), "&Title View", self.mdiArea.tileSubWindows, QKeySequence(Qt.CTRL + Qt.Key_N)) self.viewMenu.addAction(QIcon(path.normcase("gui/icons/stop_process.png")), "&Close all subWindows", self.mdiArea.closeAllSubWindows, QKeySequence(Qt.CTRL+Qt.Key_W)) self.plotting =QMenu("&Plotting...") self.plotting.setIcon(QIcon(QPixmap(path.normcase("gui/icons/plot.png")))) self.plotting.addAction("&3D Plot") #self.plotting.addAction("&Cytoscape web") self.plotting.addAction("&Spectrogram Plot") #self.multiplePlot = QAction("&Visualize Raw/Treated Data", self) #self.multiplePlot.setCheckable(True) #self.multiplePlot.setEnabled(False) #self.sub_plot_.addAction(self.multiplePlot) self.viewMenu.addMenu(self.plotting) self.viewMenu.addSeparator() self.show_hide=QMenu("&Show/Hide") m=self.createPopupMenu() m.setTitle("&Show/Hide") self.viewMenu.addMenu(m) #self.pref = QMenu("&Preferences") #self.pref.addAction(self.multiplePlot) #self.viewMenu.addMenu(self.pref) self.menuBar().addMenu(self.viewMenu) #algorithm self.algoMenu= QMenu("&Algorithm") self.algoMenu.setTearOffEnabled(True) self.preProcessing=QMenu("&PreProcessing(experimental)") self.preProcessing.addAction("&Smoothing raw data...") self.preProcessing.addAction("&Cut off raw data...") self.preProcessing.addAction('&Calibration (mz dimension)') self.preProcessing.addAction("&Resize sample...") self.algoMenu.addMenu(self.preProcessing) self.peakPickingMenu = QMenu("&Peack Picking & Alignement(XCMS)", self) self.peakPickingMenu.setIcon(QIcon(path.normcase("gui/icons/pickedpeakicon.png"))) matched = QAction("&MatchedFiltered", self) matched.setIcon(QIcon(path.normcase('gui/icons/RLogo'))) matched.setToolTip("Peak Detection and Integration using MatchedFiltered algorithm") self.peakPickingMenu.addAction(matched) centwave=QAction("&CentWave", self) centwave.setIcon(QIcon(path.normcase('gui/icons/RLogo'))) centwave.setToolTip("Peak Detection and Integration using CentWave algorithm") self.peakPickingMenu.addAction(centwave) #peak_.setShortcut(.QKeySequence(CTRL + Key_P)) # peak_icon=.QIcon(.QPixmap(path.normcase("gui/icons/pickedpeakicon.png"))) #peak_.setIcon(peak_icon) self.algoMenu.addMenu(self.peakPickingMenu) self.alignment = QMenu("&Alignment") self.alignment.setIcon(QIcon(path.normcase('gui/icons/format_indent_more.png'))) self.alignment.addAction("&Polynomial fitting(exp)") self.alignment.addAction("&DynamicTimeWarping") self.alignment.addAction("&ObiWarp") self.alignment.actions()[2].setEnabled(False) self.algoMenu.addMenu(self.alignment) self.algoMenu.addAction("Normalization") clust_ = QAction("&Clustering", self) clust_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_L)) clust_icon=QIcon(QPixmap(path.normcase("gui/icons/cluster.png"))) clust_.setIcon(clust_icon) self.algoMenu.addAction(clust_) id_ = QAction("&Identification", self) id_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_I)) id_.setToolTip("Try to identify peaks with several methods") id_.setIcon(QIcon(QPixmap(path.normcase("gui/icons/findcompound.png")))) self.algoMenu.addAction(id_) self.menuBar().addMenu(self.algoMenu) #tools self.toolsMenu =QMenu("&Tools") self.toolsMenu.setTearOffEnabled(True) web = QAction("&Web Browser", self) web.setIcon(QIcon(QPixmap(path.normcase("gui/icons/applications_internet.png")))) self.toolsMenu.addAction(web) #cyto = QAction("&cytoscape", self) #cyto_icon =QIcon(QPixmap(path.normcase("gui/icons/cytoscape.jpeg"))) #cyto.setIcon(cyto_icon) #self.toolsMenu.addAction(cyto) editor = QAction("&Editor", self) editor.setIcon(QIcon(QPixmap(path.normcase("gui/icons/document_sign.png")))) self.toolsMenu.addAction(editor) pet=QAction("&Short Periodic Table", self) pet.setIcon(QIcon(QPixmap(path.normcase("gui/icons/pet.jpg")))) self.toolsMenu.addAction(pet) self.menuBar().addMenu(self.toolsMenu) #plugins self.pluginMenu = QMenu('&Plugins') self.pluginMenu.setTearOffEnabled(True) instPl= QAction("&Install a plugin", self) instPl.setIcon(QIcon(path.normcase('gui/icons/pluginInstall.png'))) self.pluginMenu.addAction(instPl) self.launchingMenu = QMenu("&Launch PLugins", self) self.launchingMenu.setIcon(QIcon(path.normcase('gui/icons/plugin'))) for plug in self.plugins: #fullname="".join([self.pluginPath, str(plug)]) mod=imp.load_source(self.__module__, plug) if mod.autoActivation: qApp=QApplication.instance() name=getattr(mod, 'className') cls=getattr(mod, name) p=cls(qApp.model, self, parent=self) #p=qApp.pluginManager.loadPlugin(qApp.model, self, plug.split('/')[-1]) self.pluginsInst.append(p) else: self.launchingMenu.addAction(plug.split('/')[-1]) self.pluginMenu.addMenu(self.launchingMenu) self.pluginMenu.addAction(QIcon(path.normcase("gui/icons/process_stop.png")), "&Remove loaded Plugin") self.menuBar().addMenu(self.pluginMenu) #about self.aboutMenu= QMenu("&About") self.aboutMenu.setTearOffEnabled(True) metms = QAction(QIcon(path.normcase('gui/icons/deluge.png')), "&about metMS...", self) self.aboutMenu.addAction(metms) pyqt = QAction("&about PyQt4...", self) pyqt_icon =QIcon(QPixmap(path.normcase("gui/icons/logo_QT4.png"))) pyqt.setIcon(pyqt_icon) self.aboutMenu.addAction(pyqt) metms = QAction("&metMS Documentation", self) metms_icon =QIcon(QPixmap(path.normcase("gui/icons/deluge.png"))) metms.setIcon(metms_icon) self.aboutMenu.addAction(metms) self.menuBar().addMenu(self.aboutMenu) def _setupUi(self, background=None): """ Make the GUI """ #mdi self.mdiArea = MSMdiArea(self) self.mdiArea.setBackground(QBrush(QPixmap(path.normcase('gui/icons/blac2.png'))))#QColor(Qt.blue).darker())) self.setCentralWidget(self.mdiArea) #sample dock widget self.sampleDockWidget = QDockWidget("Samples", self) #sampleWidget = QWidget() self.sampleTableView = MSDragFromTableView() self.sampleTableView.setModel(self.sampleModel) self.sampleTableView.setSelectionBehavior(1) self.sampleTableView.verticalHeader().hide() self.sampleTableView.verticalHeader().setDefaultSectionSize(15) self.sampleTableView.horizontalHeader().setDefaultSectionSize(150) self.sampleDockWidget.setWidget(self.sampleTableView)#sampleWidget) self.sampleDockWidget.visible=True #workflow dock self.workflowDockWidget = QDockWidget("Visualizer", self) self.workflowDockWidget.visible = True a=QWidget(self) v=QVBoxLayout(a) q=QToolBar() #self.workingSample = QLabel("Working Sample:None") #q.addWidget(self.workingSample) q.addWidget(QLabel("ppm :")) self.ppmEditer=QDoubleSpinBox() self.usePpm=QCheckBox("use ?") q.addWidget(self.ppmEditer) q.addWidget(self.usePpm) q.addSeparator() self.removeButton=QToolButton(self) self.removeButton.setIcon(QIcon(path.normcase("gui/icons/delete.png"))) q.addWidget(self.removeButton) self.markAsGood=QAction(QIcon(path.normcase("gui/icons/button_ok.png")),"mark peak as good", self) self.markAsBad=QAction(QIcon(path.normcase("gui/icons/stop.png")), "mark peak as bad", self) self.hideItem = QAction(QIcon(path.normcase("gui/icons/list_remove.png")), "Hide Item", self) q.addAction(self.markAsGood) q.addAction(self.markAsBad) q.addAction(self.hideItem) v.addWidget(q) self.tabWidget = QTabWidget() self.tab = QWidget() verticalLayout = QVBoxLayout(self.tab) self.treeView = MSToDropTableView() self.treeView.verticalHeader().setDefaultSectionSize(20) self.treeView.setModel(self.spectraModel) self.spectraLabel = QLabel("Sample: None") verticalLayout.addWidget(self.treeView) verticalLayout.addWidget(self.spectraLabel) self.tabWidget.addTab(self.tab, QIcon(path.normcase("gui/icons/spectrumicon.png")),"Spectra") self.tab_2 = QWidget() verticalLayout_4 = QVBoxLayout(self.tab_2) self.treeView_2 = MSToDropTableView()#MSTreeView(self.tab_2)# QTableView(self)# self.treeView_2.verticalHeader().setDefaultSectionSize(20) self.treeView_2.setModel(self.peakModel) self.peakLabel = QLabel("Sample: None") verticalLayout_4.addWidget(self.treeView_2) verticalLayout_4.addWidget(self.peakLabel) self.tabWidget.addTab(self.tab_2,QIcon(path.normcase("gui/icons/peakicon.png")), "Peaks List") self.tab_3 = QWidget() verticalLayout_5 = QVBoxLayout(self.tab_3) self.treeView_3 = MSToDropTreeView() self.treeView_3.setAnimated(True) self.treeView_3.setModel(self.clusterModel) self.clusterLabel = QLabel("Sample: None") verticalLayout_5.addWidget(self.treeView_3) verticalLayout_5.addWidget(self.clusterLabel) self.tabWidget.addTab(self.tab_3, QIcon(path.normcase("gui/icons/clustering.png")), "Clusters") self.tabWidget.setCurrentIndex(0) for l in (self.spectraLabel, self.peakLabel, self.clusterLabel): l.setAutoFillBackground(True) v.addWidget(self.tabWidget) self.workflowDockWidget.setWidget(a) self.addDockWidget(Qt.DockWidgetArea(0x2),self.workflowDockWidget) from gui.MetBaseGui import MSIsoCalculator self.isoCalc = MSIsoCalculator(self) self.isoCalcDockWidget=QDockWidget('isotopes calculation', self) self.isoCalcDockWidget.setWidget(self.isoCalc) self.addDockWidget(Qt.DockWidgetArea(0x2), self.isoCalcDockWidget) self.isoCalcDockWidget.setVisible(False) self.isoCalcDockWidget.visible=False from gui.MetBaseGui import FormulaGenerator self.generator=FormulaGenerator(self) self.generatorDockWidget=QDockWidget('formula generator', self) self.generatorDockWidget.setWidget(self.generator) self.addDockWidget(Qt.DockWidgetArea(0x2), self.generatorDockWidget) self.generatorDockWidget.setVisible(False) self.generatorDockWidget.visible=False self.compoundTreeView = MSCompoundTreeView(self) self.compoundDockWidget = QDockWidget("Compounds", self) self.compoundDockWidget.setWidget(self.compoundTreeView) self.addDockWidget(Qt.DockWidgetArea(0x2),self.compoundDockWidget) self.compoundDockWidget.setVisible(False) self.compoundDockWidget.visible=False self.comparativeTableView = QTableView(self) self.comparativeTableView.horizontalHeader().setStretchLastSection(True) self.comparativeTableView.verticalHeader().setDefaultSectionSize(20) self.comparativeDock = QDockWidget("Comparative View", self) self.comparativeDock.setWidget(self.comparativeTableView) self.addDockWidget(Qt.DockWidgetArea(0x8), self.comparativeDock) self.comparativeDock.setVisible(False) self.comparativeDock.visible = False self.tabifyDockWidget(self.compoundDockWidget, self.isoCalcDockWidget) self.tabifyDockWidget(self.isoCalcDockWidget, self.workflowDockWidget ) self.tabifyDockWidget(self.workflowDockWidget, self.generatorDockWidget) #set the end #WARNING: possible that the internal shell widget cause random segfault #with the error of QObject::killTimers...? not sure ! self.shell = QWidget()#InternalShell(namespace={'metms': QApplication.instance()}, # parent=self, # multithreaded=False) self.shellDock = QDockWidget("Python Shell", self) self.shellDock.setWindowIcon(QIcon(path.normcase('gui/icons/stop.png'))) self.shellDock.setWidget(self.shell) self.shellDock.setMinimumWidth(255) self.shellDock.visible=True self.addDockWidget(0x2, self.shellDock) self.addDockWidget(0x2, self.sampleDockWidget) self.tabifyDockWidget(self.shellDock, self.sampleDockWidget) self.pb = QProgressBar(self) self.pb.setMaximumWidth(245) self.stopProcess = QToolButton(self) self.stopProcess.setIcon(QIcon(path.normcase("gui/icons/process_stop.png"))) m = QMenu() #self.connect(m, SIGNAL('triggered(QAction*'), QApplication.instance().taskManager.abortByName) self.stopProcess.setMenu(m) self.stopProcess.setPopupMode(1) #Menu Button #self.connect(self.stopProcess, SIGNAL("clicked()"), self.stopThread) self.statusBar().addPermanentWidget(self.stopProcess) self.statusBar().addPermanentWidget(self.pb) def updateStopProcessMenu(self): """ update the menu of the stop process button, based directly on the processes stored by the task manager """ self.stopProcess.menu().clear() for c in QApplication.instance().taskManager: self.stopProcess.menu().addAction(c.title) #QApplication.instance().taskManager.abort(QApplication.instance().taskManager[-1]) def addMdiSubWindow(self, plot, title="", showMaximized=False): """ Allow addition of new window in the mdiarea """ win=self.mdiArea.addSubWindow(plot) #print "widget parent", plot.parent() win.setAttribute(Qt.WA_DeleteOnClose) #win.connect(win, SIGNAL('destroyed(QObject *)'), self.testdestroy) #plot.setParent(win) win.setWindowTitle(title) if showMaximized: win.showMaximized() else: win.resize(400, 300) win.show() return win def updateTreeView(self): """ Tree View update switch spectre/chromato """ if self.treeView.model() == self.spectraModel: self.treeView.setModel(self.chromaModel) self.tabWidget.setTabText(0, "Chroma") else: self.treeView.setModel(self.spectraModel) #self.treeView.setSelectionMode(1) self.tabWidget.setTabText(0, "Spectra") def addTreeViewModel (self,model1, model2): """Add a model """ self.chromaModel.appendRow(model1) self.spectraModel.appendRow(model2) def _actionHovered(self, action): """emulate tooltip cause they do not work that much""" tip = action.toolTip() QToolTip.showText(QCursor.pos(), tip) def showErrorMessage(self, title, string): QMessageBox.critical(self, title, string, 0, 0) def showWarningMessage(self, title, string): return QMessageBox.warning(self, title, string, QMessageBox.Ok|QMessageBox.Cancel) def showInformationMessage(self, title, string): QMessageBox.information(self, title, string, 0) def updateProgressBar(self, i): """update the value of the progress bar for all the treatment""" self.pb.setValue(min(i, 100)) def to_indetermined_mode(self): self.pb.setMaximum(0) def to_determined_mode(self): self.pb.setMaximum(100) def showInStatusBar(self, string, time=5000): self.statusBar().showMessage(string, time) def addInterpreterDock(self, shell): self.shellDock = QDockWidget(self) self.shellDock.setWidget(shell) self.shellDock.setWindowTitle("shell") self.addDockWidget(0x2, self.shellDock) def showMetMSInformation(self): QMessageBox.about(self, self.tr("About %1").arg("metMS"), self.tr("""<b>%1 %2</b> <br>metabolite Mass Spectrometry <p>Copyright © 2010 Marco INSA, INRA <br>Licensed under the terms of the CeciLL License <p>Developed and maintained by Marco <br>Bug reports and feature requests: <a href="http://github.com/jerkos/metms">metMS site</a><br> Discussions around the project: <a href="http://groups.google.com/group/spyderlib">Google Group</a> <p>This project is part of the BRIDGE project <p>Python %3, Qt %4, PyQt %5""") \ .arg("metMS").arg(__version__) \ .arg(platform.python_version()).arg(QT_VERSION_STR) \ .arg(PYQT_VERSION_STR))
class LayerSelectionPage(QFrame): #TODO. Filtering, (visible) row selection, multi selection colparams = ((0,65,'Name'), (1,235,'Title'), (2,350,'Keywords')) XFER_BW = 40 def __init__(self, parent=None): super(LayerSelectionPage, self).__init__(parent) self.parent = parent #convenience link self.confconn_link = self.parent.parent.confconn #flag top prevent read read action on keyword delete. New logic makes this redundant #self.keywordbypass = False QToolTip.setFont(QFont('SansSerif', 10)) #label filterlabel = QLabel('Filter') availablelabel = QLabel('Available Layers') selectionlabel = QLabel('Layer Selections') keywordlabel = QLabel('Keyword') explainlabel = QLabel("Edit Group assignments using this dialog or to simply initialise the Layer-Config just click 'Finish'") #selection buttons chooseallbutton = QPushButton('>>') chooseallbutton.setFixedWidth(self.XFER_BW) chooseallbutton.clicked.connect(self.doChooseAllClickAction) choosebutton = QPushButton('>') choosebutton.setFixedWidth(self.XFER_BW) choosebutton.clicked.connect(self.doChooseClickAction) rejectbutton = QPushButton('<') rejectbutton.setFixedWidth(self.XFER_BW) rejectbutton.clicked.connect(self.doRejectClickAction) rejectallbutton = QPushButton('<<') rejectallbutton.setFixedWidth(self.XFER_BW) rejectallbutton.clicked.connect(self.doRejectAllClickAction) #operation buttons finishbutton = QPushButton('Finish') finishbutton.setToolTip('Finish and Close layer selection dialog') finishbutton.clicked.connect(self.parent.close) resetbutton = QPushButton('Reset') resetbutton.font() resetbutton.setToolTip('Read Layer from LDS GetCapabilities request. Overwrites current Layer Config') resetbutton.clicked.connect(self.doResetClickAction) self.available_sfpm = LDSSFPAvailableModel(self) self.selection_sfpm = LDSSFPSelectionModel(self) self.available_sfpm.setSourceModel(self.parent.available_model) self.selection_sfpm.setSourceModel(self.parent.selection_model) #textedits filteredit = QLineEdit('') filteredit.setToolTip('Filter Available-Layers pane (filter operates across Name and Title fields and accepts Regex expressions)') filteredit.textChanged.connect(self.available_sfpm.setActiveFilter) self.keywordcombo = QComboBox() self.keywordcombo.setToolTip('Select or Add a unique identifier to be saved in layer config (keyword)') self.keywordcombo.addItems(list(self.confconn_link.assigned)) self.keywordcombo.setEditable(True) self.keywordcombo.activated.connect(self.doKeyComboChangeAction) lgindex = self.confconn_link.getLayerGroupIndex(self.confconn_link.lgval,col=1) lgentry = self.confconn_link.lglist[lgindex] if LU.assessNone(lgindex) else None #keywordedit = self.keywordcombo.lineEdit().text().toUtf8().data().decode('utf8')# for writing #if no entry or layer indicated then blank self.keywordcombo.lineEdit().setText('' if lgentry is None or lgentry[0]==LORG.LAYER else lgentry[1])#self.confconn_link.lgval)#TODO. group only #header headmodel = QStandardItemModel() headmodel.setHorizontalHeaderLabels([i[2] for i in self.colparams][:self.parent.available_model.columnCount()]) headview1 = QHeaderView(Qt.Horizontal) headview1.setModel(headmodel) headview1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) headview2 = QHeaderView(Qt.Horizontal) headview2.setModel(headmodel) headview2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) #table self.available = QTableView() self.available.setSelectionBehavior(QAbstractItemView.SelectRows) self.available.setSelectionMode(QAbstractItemView.MultiSelection) self.selection = QTableView() self.selection.setSelectionBehavior(QAbstractItemView.SelectRows) self.selection.setSelectionMode(QAbstractItemView.MultiSelection) #interesting, must set model after selection attributes but before headers else row selections/headers don't work properly self.available.setModel(self.available_sfpm) self.selection.setModel(self.selection_sfpm) self.available.setSortingEnabled(True) self.available.setHorizontalHeader(headview1) self.selection.setSortingEnabled(True) self.selection.setHorizontalHeader(headview2) for cp in self.colparams: self.available.setColumnWidth(cp[0],cp[1]) self.selection.setColumnWidth(cp[0],cp[1]) self.available.verticalHeader().setVisible(False) self.available.horizontalHeader().setVisible(True) self.selection.verticalHeader().setVisible(False) self.selection.horizontalHeader().setVisible(True) #layout vbox00 = QVBoxLayout() vbox00.addWidget(availablelabel) vbox00.addWidget(self.available) vbox01 = QVBoxLayout() vbox01.addWidget(chooseallbutton) vbox01.addWidget(choosebutton) vbox01.addWidget(rejectbutton) vbox01.addWidget(rejectallbutton) vbox02 = QVBoxLayout() vbox02.addWidget(selectionlabel) vbox02.addWidget(self.selection) vbox10 = QVBoxLayout() vbox10.addWidget(filterlabel) vbox10.addWidget(filteredit) hbox12 = QHBoxLayout() hbox12.addWidget(keywordlabel) hbox12.addStretch(1) #hbox12.addWidget(inspbutton) #hbox12.addWidget(addbutton) #hbox12.addWidget(delbutton) vbox12 = QVBoxLayout() vbox12.addLayout(hbox12) vbox12.addWidget(self.keywordcombo) #00|01|02 #10|11|12 grid0 = QGridLayout() grid0.addLayout(vbox00,1,0) grid0.addLayout(vbox01,1,1) grid0.addLayout(vbox02,1,2) grid0.addLayout(vbox10,0,0) grid0.addLayout(vbox12,0,2) hbox2 = QHBoxLayout() hbox2.addWidget(resetbutton) hbox2.addStretch(1) hbox2.addWidget(explainlabel) hbox2.addWidget(finishbutton) #gbox1.setLayout(hbox2) vbox3 = QVBoxLayout() vbox3.addLayout(grid0) #vbox3.addLayout(hbox3) #vbox3.addWidget(line0) vbox3.addLayout(hbox2) self.setLayout(vbox3) def doChooseAllClickAction(self): '''Moves the lot to Selected''' #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode(LQ.readWidgetText(self.keywordcombo.lineEdit().text())) if not self.checkKeyword(ktext): return #------------------------------ self.parent.signalModels(self.parent.STEP.PRE) #self.parent.selection_model.mdata += self.parent.available_model.mdata self.parent.selection_model.initData(self.confconn_link.complete) self.parent.available_model.initData([]) self.parent.signalModels(self.parent.STEP.POST) #------------------------------ self.parent.writeKeysToLayerConfig(ktext) #self.confconn_link.setupAssignedLayerList() if self.keywordcombo.findText(ktext) == -1: self.keywordcombo.addItem(ktext) def doChooseClickAction(self): '''Takes available selected and moves to selection''' #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode(LQ.readWidgetText(self.keywordcombo.lineEdit().text())) #ktext = str(self.keywordcombo.lineEdit().text()) if not self.checkKeyword(ktext): return #------------------------------ select = self.available.selectionModel() if select.hasSelection(): self.transferSelectedRows(select.selectedRows(),self.available_sfpm,self.selection_sfpm) #------------------------------ self.parent.writeKeysToLayerConfig(ktext) #self.confconn_link.assigned = self.confconn_link.setupAssignedLayerList() # -1 to indicate no index since 0,1,... are valid if self.keywordcombo.findText(ktext) == -1: self.keywordcombo.addItem(ktext) else: ldslog.warn('L2R > Transfer action without selection') #TRACE# #pdb.set_trace() self.available.clearSelection() def transferSelectedRows(self,indices,from_model,to_model): tlist = [] for proxymodelindex in indices: transfer = from_model.getData(proxymodelindex) tlist.append((proxymodelindex,transfer),) to_model.addData([t[1] for t in tlist]) from_model.delData([t[0] for t in tlist]) return tlist def doRejectClickAction(self): '''Takes available selected and moves to selection''' #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode(LQ.readWidgetText(self.keywordcombo.lineEdit().text())) if not self.checkKeyword(ktext): return #------------------------------ select = self.selection.selectionModel() if select.hasSelection(): tlist = self.transferSelectedRows(select.selectedRows(),self.selection_sfpm,self.available_sfpm) #------------------------------ kindex = self.keywordcombo.findText(ktext) remainder = self.parent.deleteKeysFromLayerConfig([ll[1][0] for ll in tlist],ktext) if remainder > 0 and kindex == -1: #items+newkey -> add self.parent.writeKeysToLayerConfig(ktext) self.keywordcombo.addItem(ktext) elif remainder == 0 and kindex > -1: #empty+oldkey -> del self.keywordcombo.removeItem(kindex) self.keywordcombo.clearEditText() else: ldslog.warn('R2L < Transfer action without selection') #TRACE# #pdb.set_trace() self.selection.clearSelection() def doRejectAllClickAction(self): #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode(LQ.readWidgetText(self.keywordcombo.lineEdit().text())) if not self.checkKeyword(ktext): return #------------------------------ self.parent.deleteKeysFromLayerConfig([ll[0] for ll in self.parent.selection_model.mdata],ktext) #------------------------------ self.parent.signalModels(self.parent.STEP.PRE) #self.parent.available_model.mdata += self.parent.selection_model.mdata self.parent.available_model.initData(self.confconn_link.complete) self.parent.selection_model.initData([]) self.parent.signalModels(self.parent.STEP.POST) #------------------------------ #self.confconn_link.setupAssignedLayerList() #self.keywordbypass = True self.keywordcombo.removeItem(self.keywordcombo.findText(ktext)) self.keywordcombo.clearEditText() def doKeyComboChangeAction(self): '''Reset the available pane and if there is anything in the keyword box use this to init the selection pane''' #HACK #if self.keywordbypass: # self.keywordbypass = False # return #------------------------------ #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode(LQ.readWidgetText(self.keywordcombo.lineEdit().text())) #------------------------------ av_sl = self.parent.splitData(ktext,self.confconn_link.complete) #av_sl = self.parent.splitData(ktext,self.confconn_link.complete) self.parent.signalModels(self.parent.STEP.PRE) self.parent.available_model.initData(av_sl[0]) self.parent.selection_model.initData(av_sl[1]) self.parent.signalModels(self.parent.STEP.POST) def doResetClickAction(self): '''Dumps the LC and rebuilds from a fresh read of the caps doc''' #int warning (QWidget parent, QString title, QString text, QString button0Text, QString button1Text = QString(), QString button2Text = QString(), int defaultButtonNumber = 0, int escapeButtonNumber = -1) ans = QMessageBox.warning(self, "Reset","This action will overwrite your Layer Configuration using the current LDS settings (potentially adding new or removing layers). Continue?","Continue","Cancel") if ans: #Cancel ldslog.warn('Cancelling Reset operation') return #Continue ldslog.warn('Reset Layer Config') self.parent.resetLayers() self.keywordcombo.clear() def checkKeyword(self,ktext): '''Checks keyword isn't null and isn't part of the LDS supplied keywords''' if LU.assessNone(ktext) is None: QMessageBox.about(self, "Keyword Required","Please enter a Keyword to assign Layer(s) to") return False if ktext in self.confconn_link.reserved: QMessageBox.about(self, "Reserved Keyword","'{}' is a reserved keyword, please select again".format(ktext)) return False return True
class LayerSelectionPage(QFrame): #TODO. Filtering, (visible) row selection, multi selection colparams = ((0, 65, 'Name'), (1, 235, 'Title'), (2, 350, 'Keywords')) XFER_BW = 40 def __init__(self, parent=None): super(LayerSelectionPage, self).__init__(parent) self.parent = parent #convenience link self.confconn_link = self.parent.parent.confconn #flag top prevent read read action on keyword delete. New logic makes this redundant #self.keywordbypass = False QToolTip.setFont(QFont('SansSerif', 10)) #label filterlabel = QLabel('Filter') availablelabel = QLabel('Available Layers') selectionlabel = QLabel('Layer Selections') keywordlabel = QLabel('Keyword') explainlabel = QLabel( "Edit Group assignments using this dialog or to simply initialise the Layer-Config just click 'Finish'" ) #selection buttons chooseallbutton = QPushButton('>>') chooseallbutton.setFixedWidth(self.XFER_BW) chooseallbutton.clicked.connect(self.doChooseAllClickAction) choosebutton = QPushButton('>') choosebutton.setFixedWidth(self.XFER_BW) choosebutton.clicked.connect(self.doChooseClickAction) rejectbutton = QPushButton('<') rejectbutton.setFixedWidth(self.XFER_BW) rejectbutton.clicked.connect(self.doRejectClickAction) rejectallbutton = QPushButton('<<') rejectallbutton.setFixedWidth(self.XFER_BW) rejectallbutton.clicked.connect(self.doRejectAllClickAction) #operation buttons finishbutton = QPushButton('Finish') finishbutton.setToolTip('Finish and Close layer selection dialog') finishbutton.clicked.connect(self.parent.close) resetbutton = QPushButton('Reset') resetbutton.font() resetbutton.setToolTip( 'Read Layer from LDS GetCapabilities request. Overwrites current Layer Config' ) resetbutton.clicked.connect(self.doResetClickAction) self.available_sfpm = LDSSFPAvailableModel(self) self.selection_sfpm = LDSSFPSelectionModel(self) self.available_sfpm.setSourceModel(self.parent.available_model) self.selection_sfpm.setSourceModel(self.parent.selection_model) #textedits filteredit = QLineEdit('') filteredit.setToolTip( 'Filter Available-Layers pane (filter operates across Name and Title fields and accepts Regex expressions)' ) filteredit.textChanged.connect(self.available_sfpm.setActiveFilter) self.keywordcombo = QComboBox() self.keywordcombo.setToolTip( 'Select or Add a unique identifier to be saved in layer config (keyword)' ) self.keywordcombo.addItems(list(self.confconn_link.assigned)) self.keywordcombo.setEditable(True) self.keywordcombo.activated.connect(self.doKeyComboChangeAction) lgindex = self.confconn_link.getLayerGroupIndex( self.confconn_link.lgval, col=1) lgentry = self.confconn_link.lglist[lgindex] if LU.assessNone( lgindex) else None #keywordedit = self.keywordcombo.lineEdit().text().toUtf8().data().decode('utf8')# for writing #if no entry or layer indicated then blank self.keywordcombo.lineEdit().setText( '' if lgentry is None or lgentry[0] == LORG.LAYER else lgentry[1]) #self.confconn_link.lgval)#TODO. group only #header headmodel = QStandardItemModel() headmodel.setHorizontalHeaderLabels([ i[2] for i in self.colparams ][:self.parent.available_model.columnCount()]) headview1 = QHeaderView(Qt.Horizontal) headview1.setModel(headmodel) headview1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) headview2 = QHeaderView(Qt.Horizontal) headview2.setModel(headmodel) headview2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) #table self.available = QTableView() self.available.setSelectionBehavior(QAbstractItemView.SelectRows) self.available.setSelectionMode(QAbstractItemView.MultiSelection) self.selection = QTableView() self.selection.setSelectionBehavior(QAbstractItemView.SelectRows) self.selection.setSelectionMode(QAbstractItemView.MultiSelection) #interesting, must set model after selection attributes but before headers else row selections/headers don't work properly self.available.setModel(self.available_sfpm) self.selection.setModel(self.selection_sfpm) self.available.setSortingEnabled(True) self.available.setHorizontalHeader(headview1) self.selection.setSortingEnabled(True) self.selection.setHorizontalHeader(headview2) for cp in self.colparams: self.available.setColumnWidth(cp[0], cp[1]) self.selection.setColumnWidth(cp[0], cp[1]) self.available.verticalHeader().setVisible(False) self.available.horizontalHeader().setVisible(True) self.selection.verticalHeader().setVisible(False) self.selection.horizontalHeader().setVisible(True) #layout vbox00 = QVBoxLayout() vbox00.addWidget(availablelabel) vbox00.addWidget(self.available) vbox01 = QVBoxLayout() vbox01.addWidget(chooseallbutton) vbox01.addWidget(choosebutton) vbox01.addWidget(rejectbutton) vbox01.addWidget(rejectallbutton) vbox02 = QVBoxLayout() vbox02.addWidget(selectionlabel) vbox02.addWidget(self.selection) vbox10 = QVBoxLayout() vbox10.addWidget(filterlabel) vbox10.addWidget(filteredit) hbox12 = QHBoxLayout() hbox12.addWidget(keywordlabel) hbox12.addStretch(1) #hbox12.addWidget(inspbutton) #hbox12.addWidget(addbutton) #hbox12.addWidget(delbutton) vbox12 = QVBoxLayout() vbox12.addLayout(hbox12) vbox12.addWidget(self.keywordcombo) #00|01|02 #10|11|12 grid0 = QGridLayout() grid0.addLayout(vbox00, 1, 0) grid0.addLayout(vbox01, 1, 1) grid0.addLayout(vbox02, 1, 2) grid0.addLayout(vbox10, 0, 0) grid0.addLayout(vbox12, 0, 2) hbox2 = QHBoxLayout() hbox2.addWidget(resetbutton) hbox2.addStretch(1) hbox2.addWidget(explainlabel) hbox2.addWidget(finishbutton) #gbox1.setLayout(hbox2) vbox3 = QVBoxLayout() vbox3.addLayout(grid0) #vbox3.addLayout(hbox3) #vbox3.addWidget(line0) vbox3.addLayout(hbox2) self.setLayout(vbox3) def doChooseAllClickAction(self): '''Moves the lot to Selected''' #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode( LQ.readWidgetText(self.keywordcombo.lineEdit().text())) if not self.checkKeyword(ktext): return #------------------------------ self.parent.signalModels(self.parent.STEP.PRE) #self.parent.selection_model.mdata += self.parent.available_model.mdata self.parent.selection_model.initData(self.confconn_link.complete) self.parent.available_model.initData([]) self.parent.signalModels(self.parent.STEP.POST) #------------------------------ self.parent.writeKeysToLayerConfig(ktext) #self.confconn_link.setupAssignedLayerList() if self.keywordcombo.findText(ktext) == -1: self.keywordcombo.addItem(ktext) def doChooseClickAction(self): '''Takes available selected and moves to selection''' #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode( LQ.readWidgetText(self.keywordcombo.lineEdit().text())) #ktext = str(self.keywordcombo.lineEdit().text()) if not self.checkKeyword(ktext): return #------------------------------ select = self.available.selectionModel() if select.hasSelection(): self.transferSelectedRows(select.selectedRows(), self.available_sfpm, self.selection_sfpm) #------------------------------ self.parent.writeKeysToLayerConfig(ktext) #self.confconn_link.assigned = self.confconn_link.setupAssignedLayerList() # -1 to indicate no index since 0,1,... are valid if self.keywordcombo.findText(ktext) == -1: self.keywordcombo.addItem(ktext) else: ldslog.warn('L2R > Transfer action without selection') #TRACE# #pdb.set_trace() self.available.clearSelection() def transferSelectedRows(self, indices, from_model, to_model): tlist = [] for proxymodelindex in indices: transfer = from_model.getData(proxymodelindex) tlist.append((proxymodelindex, transfer), ) to_model.addData([t[1] for t in tlist]) from_model.delData([t[0] for t in tlist]) return tlist def doRejectClickAction(self): '''Takes available selected and moves to selection''' #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode( LQ.readWidgetText(self.keywordcombo.lineEdit().text())) if not self.checkKeyword(ktext): return #------------------------------ select = self.selection.selectionModel() if select.hasSelection(): tlist = self.transferSelectedRows(select.selectedRows(), self.selection_sfpm, self.available_sfpm) #------------------------------ kindex = self.keywordcombo.findText(ktext) remainder = self.parent.deleteKeysFromLayerConfig( [ll[1][0] for ll in tlist], ktext) if remainder > 0 and kindex == -1: #items+newkey -> add self.parent.writeKeysToLayerConfig(ktext) self.keywordcombo.addItem(ktext) elif remainder == 0 and kindex > -1: #empty+oldkey -> del self.keywordcombo.removeItem(kindex) self.keywordcombo.clearEditText() else: ldslog.warn('R2L < Transfer action without selection') #TRACE# #pdb.set_trace() self.selection.clearSelection() def doRejectAllClickAction(self): #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode( LQ.readWidgetText(self.keywordcombo.lineEdit().text())) if not self.checkKeyword(ktext): return #------------------------------ self.parent.deleteKeysFromLayerConfig( [ll[0] for ll in self.parent.selection_model.mdata], ktext) #------------------------------ self.parent.signalModels(self.parent.STEP.PRE) #self.parent.available_model.mdata += self.parent.selection_model.mdata self.parent.available_model.initData(self.confconn_link.complete) self.parent.selection_model.initData([]) self.parent.signalModels(self.parent.STEP.POST) #------------------------------ #self.confconn_link.setupAssignedLayerList() #self.keywordbypass = True self.keywordcombo.removeItem(self.keywordcombo.findText(ktext)) self.keywordcombo.clearEditText() def doKeyComboChangeAction(self): '''Reset the available pane and if there is anything in the keyword box use this to init the selection pane''' #HACK #if self.keywordbypass: # self.keywordbypass = False # return #------------------------------ #ktext = LU.recode(self.keywordcombo.lineEdit().text().toUtf8().data()) ktext = LU.recode( LQ.readWidgetText(self.keywordcombo.lineEdit().text())) #------------------------------ av_sl = self.parent.splitData(ktext, self.confconn_link.complete) #av_sl = self.parent.splitData(ktext,self.confconn_link.complete) self.parent.signalModels(self.parent.STEP.PRE) self.parent.available_model.initData(av_sl[0]) self.parent.selection_model.initData(av_sl[1]) self.parent.signalModels(self.parent.STEP.POST) def doResetClickAction(self): '''Dumps the LC and rebuilds from a fresh read of the caps doc''' #int warning (QWidget parent, QString title, QString text, QString button0Text, QString button1Text = QString(), QString button2Text = QString(), int defaultButtonNumber = 0, int escapeButtonNumber = -1) ans = QMessageBox.warning( self, "Reset", "This action will overwrite your Layer Configuration using the current LDS settings (potentially adding new or removing layers). Continue?", "Continue", "Cancel") if ans: #Cancel ldslog.warn('Cancelling Reset operation') return #Continue ldslog.warn('Reset Layer Config') self.parent.resetLayers() self.keywordcombo.clear() def checkKeyword(self, ktext): '''Checks keyword isn't null and isn't part of the LDS supplied keywords''' if LU.assessNone(ktext) is None: QMessageBox.about(self, "Keyword Required", "Please enter a Keyword to assign Layer(s) to") return False if ktext in self.confconn_link.reserved: QMessageBox.about( self, "Reserved Keyword", "'{}' is a reserved keyword, please select again".format( ktext)) return False return True
class MSMainWindow(QMainWindow): """Gui of the main window""" # MAX_RECENT_FILES = 10 # start putting links spyder numpy scipy et tutti quanti links = ( "http://numpy.scipy.org/", "http://packages.python.org/spyder/", "http://www.riverbankcomputing.co.uk/software/pyqt/intro", ) pluginPath = path.normcase("pluginmanager/plugins/") def __init__(self, availablePlugins): """ Constructor with all the models needed setup menus """ QMainWindow.__init__(self) self.setDockOptions(QMainWindow.VerticalTabs | QMainWindow.AnimatedDocks) self.plugins = availablePlugins self.pluginsInst = [] settings = QSettings( "INRA/INSA", "-".join([QApplication.instance().APPLICATION_NAME_STR, QApplication.instance().VERSION_STR]) ) self.recentFiles = list(settings.value("RecentFiles").toStringList()) self.setStyleSheet(stylesheet) self.pipeline = MSPipelineToolBar("Pipeline toolbar", parent=self) self.addToolBar(0x1, self.pipeline) self._setupModels() self._setupUi() self._setupMenus() def _setupModels(self): """ Warning:Causes segfault when horizontal labels set to True on aura peu etre a la fin un model par sampleList c'est ce qui parait le plus logique """ # drag and drop table sample self.sampleModel = QStandardItemModel(self) self.sampleModel.setHorizontalHeaderLabels(["Sample", "Class"]) # treeView1 self.spectraModel = QStandardItemModel(self) # treeview2 self.peakModel = QStandardItemModel(self) # treeview3 self.clusterModel = QStandardItemModel(self) def _setupMenus(self): # file self.fileMenu = QMenu("&File") self.fileMenu.setTearOffEnabled(True) self.op = QMenu("&Open...", self.fileMenu) self.op.setIcon(QIcon(path.normcase("gui/icons/fileopen.png"))) open_ = QAction("&Open rawfiles", self) open_.setToolTip("Open an mzXML or netCDF file") open_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_O)) open_icon = QIcon(path.normcase("gui/icons/fileopen.png")) open_.setIcon(open_icon) self.op.addAction(open_) load_ = QAction("&Open projects...", self) load_.setToolTip("load binary file containing saved objects") load_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S)) load_icon = QIcon(QPixmap(path.normcase("gui/icons/project_open.png"))) load_.setIcon(load_icon) self.op.addAction(load_) self.fileMenu.addMenu(self.op) save_ = QAction("&Save...", self) save_.setToolTip("save the actual application model") save_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S)) save_icon = QIcon(path.normcase("gui/icons/save_all.png")) save_.setIcon(save_icon) self.fileMenu.addAction(save_) pkl = QAction("&load a peaklist", self) # TODO:load peaklist pkl.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_P)) pkl.setToolTip("load a peaklist and process it") pkl.setIcon(QIcon(path.normcase("gui/icons/featuredetect.png"))) self.fileMenu.addAction(pkl) convert_ = QAction("&Convert...", self) convert_.setEnabled(False) convert_.setToolTip("Convert a .wiff file if Analyst(c) is installed") convert_icon = QIcon(path.normcase("gui/icons/goto.png")) convert_.setIcon(convert_icon) self.fileMenu.addAction(convert_) a = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Launch a batch") a.setEnabled(False) b = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Merge") b.setToolTip("Merge MRM file") # b.setEnabled(False) self.fileMenu.addSeparator() # # for i in xrange(self.MAX_RECENT_FILES): # a = QAction('', self) # a.setVisible(False) # self.fileMenu.addAction(a) # # for i in xrange(min(self.MAX_RECENT_FILES, len(self.recentFiles))): # self.fileMenu.actions()[5+i].setVisible(True) # self.fileMenu.actions()[5+i].setText(self.recentFiles[i].split('/')[-1]) exit_action = QAction("&Exit", self) exit_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q)) exit_action.setIcon(QIcon(QPixmap(path.normcase("gui/icons/exit.png")))) self.fileMenu.addAction(exit_action) self.menuBar().addMenu(self.fileMenu) self.editMenu = QMenu("&Edit") self.editMenu.setTearOffEnabled(True) self.editMenu.addAction(QIcon(path.normcase("gui/icons/edit_undo.png")), "&Undo...") self.editMenu.addAction(QIcon(path.normcase("gui/icons/edit_redo.png")), "&Redo...") self.editMenu.actions()[0].setEnabled(False) self.editMenu.actions()[1].setEnabled(False) self.editMenu.addSeparator() self.editMenu.addAction(QIcon(path.normcase("gui/icons/run.png")), "&Preferences") self.exportMenu = QMenu("&Export...") self.exportMenu.setIcon(QIcon(path.normcase("gui/icons/file_export.png"))) self.exportMenu.addAction("&Peaklist") self.exportMenu.addAction("&Clusters intensity matrix") self.editMenu.addMenu(self.exportMenu) self.menuBar().addMenu(self.editMenu) # view self.viewMenu = QMenu("&View") self.viewMenu.setTearOffEnabled(True) self.viewMenu.addAction( QIcon(path.normcase("gui/icons/window_duplicate")), "&Cascade View", self.mdiArea.cascadeSubWindows, QKeySequence(Qt.CTRL + Qt.Key_K), ) self.viewMenu.addAction( QIcon(path.normcase("gui/icons/view_icon")), "&Title View", self.mdiArea.tileSubWindows, QKeySequence(Qt.CTRL + Qt.Key_N), ) self.viewMenu.addAction( QIcon(path.normcase("gui/icons/stop_process.png")), "&Close all subWindows", self.mdiArea.closeAllSubWindows, QKeySequence(Qt.CTRL + Qt.Key_W), ) self.plotting = QMenu("&Plotting...") self.plotting.setIcon(QIcon(QPixmap(path.normcase("gui/icons/plot.png")))) self.plotting.addAction("&3D Plot") # self.plotting.addAction("&Cytoscape web") self.plotting.addAction("&Spectrogram Plot") # self.multiplePlot = QAction("&Visualize Raw/Treated Data", self) # self.multiplePlot.setCheckable(True) # self.multiplePlot.setEnabled(False) # self.sub_plot_.addAction(self.multiplePlot) self.viewMenu.addMenu(self.plotting) self.viewMenu.addSeparator() self.show_hide = QMenu("&Show/Hide") m = self.createPopupMenu() m.setTitle("&Show/Hide") self.viewMenu.addMenu(m) # self.pref = QMenu("&Preferences") # self.pref.addAction(self.multiplePlot) # self.viewMenu.addMenu(self.pref) self.menuBar().addMenu(self.viewMenu) # algorithm self.algoMenu = QMenu("&Algorithm") self.algoMenu.setTearOffEnabled(True) self.preProcessing = QMenu("&PreProcessing(experimental)") self.preProcessing.addAction("&Smoothing raw data...") self.preProcessing.addAction("&Cut off raw data...") self.preProcessing.addAction("&Calibration (mz dimension)") self.preProcessing.addAction("&Resize sample...") self.algoMenu.addMenu(self.preProcessing) self.peakPickingMenu = QMenu("&Peack Picking & Alignement(XCMS)", self) self.peakPickingMenu.setIcon(QIcon(path.normcase("gui/icons/pickedpeakicon.png"))) matched = QAction("&MatchedFiltered", self) matched.setIcon(QIcon(path.normcase("gui/icons/RLogo"))) matched.setToolTip("Peak Detection and Integration using MatchedFiltered algorithm") self.peakPickingMenu.addAction(matched) centwave = QAction("&CentWave", self) centwave.setIcon(QIcon(path.normcase("gui/icons/RLogo"))) centwave.setToolTip("Peak Detection and Integration using CentWave algorithm") self.peakPickingMenu.addAction(centwave) # peak_.setShortcut(.QKeySequence(CTRL + Key_P)) # peak_icon=.QIcon(.QPixmap(path.normcase("gui/icons/pickedpeakicon.png"))) # peak_.setIcon(peak_icon) self.algoMenu.addMenu(self.peakPickingMenu) self.alignment = QMenu("&Alignment") self.alignment.setIcon(QIcon(path.normcase("gui/icons/format_indent_more.png"))) self.alignment.addAction("&Polynomial fitting(exp)") self.alignment.addAction("&DynamicTimeWarping") self.alignment.addAction("&ObiWarp") self.alignment.actions()[2].setEnabled(False) self.algoMenu.addMenu(self.alignment) self.algoMenu.addAction("Normalization") clust_ = QAction("&Clustering", self) clust_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_L)) clust_icon = QIcon(QPixmap(path.normcase("gui/icons/cluster.png"))) clust_.setIcon(clust_icon) self.algoMenu.addAction(clust_) id_ = QAction("&Identification", self) id_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_I)) id_.setToolTip("Try to identify peaks with several methods") id_.setIcon(QIcon(QPixmap(path.normcase("gui/icons/findcompound.png")))) self.algoMenu.addAction(id_) self.menuBar().addMenu(self.algoMenu) # tools self.toolsMenu = QMenu("&Tools") self.toolsMenu.setTearOffEnabled(True) web = QAction("&Web Browser", self) web.setIcon(QIcon(QPixmap(path.normcase("gui/icons/applications_internet.png")))) self.toolsMenu.addAction(web) # cyto = QAction("&cytoscape", self) # cyto_icon =QIcon(QPixmap(path.normcase("gui/icons/cytoscape.jpeg"))) # cyto.setIcon(cyto_icon) # self.toolsMenu.addAction(cyto) editor = QAction("&Editor", self) editor.setIcon(QIcon(QPixmap(path.normcase("gui/icons/document_sign.png")))) self.toolsMenu.addAction(editor) pet = QAction("&Short Periodic Table", self) pet.setIcon(QIcon(QPixmap(path.normcase("gui/icons/pet.jpg")))) self.toolsMenu.addAction(pet) self.menuBar().addMenu(self.toolsMenu) # plugins self.pluginMenu = QMenu("&Plugins") self.pluginMenu.setTearOffEnabled(True) instPl = QAction("&Install a plugin", self) instPl.setIcon(QIcon(path.normcase("gui/icons/pluginInstall.png"))) self.pluginMenu.addAction(instPl) self.launchingMenu = QMenu("&Launch PLugins", self) self.launchingMenu.setIcon(QIcon(path.normcase("gui/icons/plugin"))) for plug in self.plugins: # fullname="".join([self.pluginPath, str(plug)]) mod = imp.load_source(self.__module__, plug) if mod.autoActivation: qApp = QApplication.instance() name = getattr(mod, "className") cls = getattr(mod, name) p = cls(qApp.model, self, parent=self) # p=qApp.pluginManager.loadPlugin(qApp.model, self, plug.split('/')[-1]) self.pluginsInst.append(p) else: self.launchingMenu.addAction(plug.split("/")[-1]) self.pluginMenu.addMenu(self.launchingMenu) self.pluginMenu.addAction(QIcon(path.normcase("gui/icons/process_stop.png")), "&Remove loaded Plugin") self.menuBar().addMenu(self.pluginMenu) # about self.aboutMenu = QMenu("&About") self.aboutMenu.setTearOffEnabled(True) metms = QAction(QIcon(path.normcase("gui/icons/deluge.png")), "&about metMS...", self) self.aboutMenu.addAction(metms) pyqt = QAction("&about PyQt4...", self) pyqt_icon = QIcon(QPixmap(path.normcase("gui/icons/logo_QT4.png"))) pyqt.setIcon(pyqt_icon) self.aboutMenu.addAction(pyqt) metms = QAction("&metMS Documentation", self) metms_icon = QIcon(QPixmap(path.normcase("gui/icons/deluge.png"))) metms.setIcon(metms_icon) self.aboutMenu.addAction(metms) self.menuBar().addMenu(self.aboutMenu) def _setupUi(self, background=None): """ Make the GUI """ # mdi self.mdiArea = MSMdiArea(self) self.mdiArea.setBackground(QBrush(QPixmap(path.normcase("gui/icons/blac2.png")))) # QColor(Qt.blue).darker())) self.setCentralWidget(self.mdiArea) # sample dock widget self.sampleDockWidget = QDockWidget("Samples", self) # sampleWidget = QWidget() self.sampleTableView = MSDragFromTableView() self.sampleTableView.setModel(self.sampleModel) self.sampleTableView.setSelectionBehavior(1) self.sampleTableView.verticalHeader().hide() self.sampleTableView.verticalHeader().setDefaultSectionSize(15) self.sampleTableView.horizontalHeader().setDefaultSectionSize(150) self.sampleDockWidget.setWidget(self.sampleTableView) # sampleWidget) self.sampleDockWidget.visible = True # workflow dock self.workflowDockWidget = QDockWidget("Visualizer", self) self.workflowDockWidget.visible = True a = QWidget(self) v = QVBoxLayout(a) q = QToolBar() # self.workingSample = QLabel("Working Sample:None") # q.addWidget(self.workingSample) q.addWidget(QLabel("ppm :")) self.ppmEditer = QDoubleSpinBox() self.usePpm = QCheckBox("use ?") q.addWidget(self.ppmEditer) q.addWidget(self.usePpm) q.addSeparator() self.removeButton = QToolButton(self) self.removeButton.setIcon(QIcon(path.normcase("gui/icons/delete.png"))) q.addWidget(self.removeButton) self.markAsGood = QAction(QIcon(path.normcase("gui/icons/button_ok.png")), "mark peak as good", self) self.markAsBad = QAction(QIcon(path.normcase("gui/icons/stop.png")), "mark peak as bad", self) self.hideItem = QAction(QIcon(path.normcase("gui/icons/list_remove.png")), "Hide Item", self) q.addAction(self.markAsGood) q.addAction(self.markAsBad) q.addAction(self.hideItem) v.addWidget(q) self.tabWidget = QTabWidget() self.tab = QWidget() verticalLayout = QVBoxLayout(self.tab) self.treeView = MSToDropTableView() self.treeView.verticalHeader().setDefaultSectionSize(20) self.treeView.setModel(self.spectraModel) self.spectraLabel = QLabel("Sample: None") verticalLayout.addWidget(self.treeView) verticalLayout.addWidget(self.spectraLabel) self.tabWidget.addTab(self.tab, QIcon(path.normcase("gui/icons/spectrumicon.png")), "Spectra") self.tab_2 = QWidget() verticalLayout_4 = QVBoxLayout(self.tab_2) self.treeView_2 = MSToDropTableView() # MSTreeView(self.tab_2)# QTableView(self)# self.treeView_2.verticalHeader().setDefaultSectionSize(20) self.treeView_2.setModel(self.peakModel) self.peakLabel = QLabel("Sample: None") verticalLayout_4.addWidget(self.treeView_2) verticalLayout_4.addWidget(self.peakLabel) self.tabWidget.addTab(self.tab_2, QIcon(path.normcase("gui/icons/peakicon.png")), "Peaks List") self.tab_3 = QWidget() verticalLayout_5 = QVBoxLayout(self.tab_3) self.treeView_3 = MSToDropTreeView() self.treeView_3.setAnimated(True) self.treeView_3.setModel(self.clusterModel) self.clusterLabel = QLabel("Sample: None") verticalLayout_5.addWidget(self.treeView_3) verticalLayout_5.addWidget(self.clusterLabel) self.tabWidget.addTab(self.tab_3, QIcon(path.normcase("gui/icons/clustering.png")), "Clusters") self.tabWidget.setCurrentIndex(0) for l in (self.spectraLabel, self.peakLabel, self.clusterLabel): l.setAutoFillBackground(True) v.addWidget(self.tabWidget) self.workflowDockWidget.setWidget(a) self.addDockWidget(Qt.DockWidgetArea(0x2), self.workflowDockWidget) from gui.MetBaseGui import MSIsoCalculator self.isoCalc = MSIsoCalculator(self) self.isoCalcDockWidget = QDockWidget("isotopes calculation", self) self.isoCalcDockWidget.setWidget(self.isoCalc) self.addDockWidget(Qt.DockWidgetArea(0x2), self.isoCalcDockWidget) self.isoCalcDockWidget.setVisible(False) self.isoCalcDockWidget.visible = False from gui.MetBaseGui import FormulaGenerator self.generator = FormulaGenerator(self) self.generatorDockWidget = QDockWidget("formula generator", self) self.generatorDockWidget.setWidget(self.generator) self.addDockWidget(Qt.DockWidgetArea(0x2), self.generatorDockWidget) self.generatorDockWidget.setVisible(False) self.generatorDockWidget.visible = False self.compoundTreeView = MSCompoundTreeView(self) self.compoundDockWidget = QDockWidget("Compounds", self) self.compoundDockWidget.setWidget(self.compoundTreeView) self.addDockWidget(Qt.DockWidgetArea(0x2), self.compoundDockWidget) self.compoundDockWidget.setVisible(False) self.compoundDockWidget.visible = False self.comparativeTableView = QTableView(self) self.comparativeTableView.horizontalHeader().setStretchLastSection(True) self.comparativeTableView.verticalHeader().setDefaultSectionSize(20) self.comparativeDock = QDockWidget("Comparative View", self) self.comparativeDock.setWidget(self.comparativeTableView) self.addDockWidget(Qt.DockWidgetArea(0x8), self.comparativeDock) self.comparativeDock.setVisible(False) self.comparativeDock.visible = False self.tabifyDockWidget(self.compoundDockWidget, self.isoCalcDockWidget) self.tabifyDockWidget(self.isoCalcDockWidget, self.workflowDockWidget) self.tabifyDockWidget(self.workflowDockWidget, self.generatorDockWidget) # set the end # WARNING: possible that the internal shell widget cause random segfault # with the error of QObject::killTimers...? not sure ! self.shell = QWidget() # InternalShell(namespace={'metms': QApplication.instance()}, # parent=self, # multithreaded=False) self.shellDock = QDockWidget("Python Shell", self) self.shellDock.setWindowIcon(QIcon(path.normcase("gui/icons/stop.png"))) self.shellDock.setWidget(self.shell) self.shellDock.setMinimumWidth(255) self.shellDock.visible = True self.addDockWidget(0x2, self.shellDock) self.addDockWidget(0x2, self.sampleDockWidget) self.tabifyDockWidget(self.shellDock, self.sampleDockWidget) self.pb = QProgressBar(self) self.pb.setMaximumWidth(245) self.stopProcess = QToolButton(self) self.stopProcess.setIcon(QIcon(path.normcase("gui/icons/process_stop.png"))) m = QMenu() # self.connect(m, SIGNAL('triggered(QAction*'), QApplication.instance().taskManager.abortByName) self.stopProcess.setMenu(m) self.stopProcess.setPopupMode(1) # Menu Button # self.connect(self.stopProcess, SIGNAL("clicked()"), self.stopThread) self.statusBar().addPermanentWidget(self.stopProcess) self.statusBar().addPermanentWidget(self.pb) def updateStopProcessMenu(self): """ update the menu of the stop process button, based directly on the processes stored by the task manager """ self.stopProcess.menu().clear() for c in QApplication.instance().taskManager: self.stopProcess.menu().addAction(c.title) # QApplication.instance().taskManager.abort(QApplication.instance().taskManager[-1]) def addMdiSubWindow(self, plot, title="", showMaximized=False): """ Allow addition of new window in the mdiarea """ win = self.mdiArea.addSubWindow(plot) # print "widget parent", plot.parent() win.setAttribute(Qt.WA_DeleteOnClose) # win.connect(win, SIGNAL('destroyed(QObject *)'), self.testdestroy) # plot.setParent(win) win.setWindowTitle(title) if showMaximized: win.showMaximized() else: win.resize(400, 300) win.show() return win def updateTreeView(self): """ Tree View update switch spectre/chromato """ if self.treeView.model() == self.spectraModel: self.treeView.setModel(self.chromaModel) self.tabWidget.setTabText(0, "Chroma") else: self.treeView.setModel(self.spectraModel) # self.treeView.setSelectionMode(1) self.tabWidget.setTabText(0, "Spectra") def addTreeViewModel(self, model1, model2): """Add a model """ self.chromaModel.appendRow(model1) self.spectraModel.appendRow(model2) def _actionHovered(self, action): """emulate tooltip cause they do not work that much""" tip = action.toolTip() QToolTip.showText(QCursor.pos(), tip) def showErrorMessage(self, title, string): QMessageBox.critical(self, title, string, 0, 0) def showWarningMessage(self, title, string): return QMessageBox.warning(self, title, string, QMessageBox.Ok | QMessageBox.Cancel) def showInformationMessage(self, title, string): QMessageBox.information(self, title, string, 0) def updateProgressBar(self, i): """update the value of the progress bar for all the treatment""" self.pb.setValue(min(i, 100)) def to_indetermined_mode(self): self.pb.setMaximum(0) def to_determined_mode(self): self.pb.setMaximum(100) def showInStatusBar(self, string, time=5000): self.statusBar().showMessage(string, time) def addInterpreterDock(self, shell): self.shellDock = QDockWidget(self) self.shellDock.setWidget(shell) self.shellDock.setWindowTitle("shell") self.addDockWidget(0x2, self.shellDock) def showMetMSInformation(self): QMessageBox.about( self, self.tr("About %1").arg("metMS"), self.tr( """<b>%1 %2</b> <br>metabolite Mass Spectrometry <p>Copyright © 2010 Marco INSA, INRA <br>Licensed under the terms of the CeciLL License <p>Developed and maintained by Marco <br>Bug reports and feature requests: <a href="http://github.com/jerkos/metms">metMS site</a><br> Discussions around the project: <a href="http://groups.google.com/group/spyderlib">Google Group</a> <p>This project is part of the BRIDGE project <p>Python %3, Qt %4, PyQt %5""" ) .arg("metMS") .arg(__version__) .arg(platform.python_version()) .arg(QT_VERSION_STR) .arg(PYQT_VERSION_STR), )
class Aditi(QMainWindow): def __init__(self): QMainWindow.__init__(self) # title self.setWindowTitle("Aditi") self.setDockOptions(QMainWindow.VerticalTabs | QMainWindow.AnimatedDocks) #self.showMaximized() # model self.rawfiles_by_short_path = {} self.xic_by_rawfile_short_path = {} self.tic_by_rawfile_short_path = {} self.spec_by_rawfile_short_path = {} self.inf_line_tic_item = None self.curr_scan_id_by_short_path = {} # menu self.file_menu = self.menuBar().addMenu('&File') #self.file_menu.setTearOffEnabled(False) open_action = QAction("&Open...", self) open_action.setToolTip("Open a rawfile") open_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_O)) self.file_menu.addAction(open_action) open_action.triggered.connect(self.show_open_dialog) exit_action = QAction("&Exit", self) exit_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q)) self.file_menu.addAction(exit_action) exit_action.triggered.connect(self.quit) self.tab_widget = QTabWidget(self) # spectrum plot Widget self.graphics_layout_widget = GraphicsLayoutWidget(parent=self.tab_widget) self.graphics_layout_widget.keyPressEvent = self.handle_key_press_event self.graphics_layout_widget.useOpenGL(False) self.graphics_layout_widget.setAntialiasing(False) self.plot_widget_tic = self.graphics_layout_widget.addPlot(title="TIC(s)", labels={'left': "Intensity", 'bottom': "Retention Time (sec)"}) self.plot_widget_tic.showGrid(x=True, y=True) self.graphics_layout_widget.nextRow() self.plot_widget_spectrum = self.graphics_layout_widget.addPlot(title="Spectrum", labels={'left': "Intensity", 'bottom': "m/z"}) self.plot_widget_spectrum.showGrid(x=True, y=True) # finally add tab self.tab_widget.addTab(self.graphics_layout_widget, "Spectrum") # Xic plotWidget self.plot_widget_xic = PlotWidget(name="MainPlot", labels={'left': "Intensity", 'bottom': "Retention Time (sec)"}) self.plot_widget_xic.showGrid(x=True, y=True) self.tab_widget.addTab(self.plot_widget_xic, "Xic extraction") self.setCentralWidget(self.tab_widget) self.statusBar().showMessage("Ready") # dock 1 self.rawfile_dock_widget = QDockWidget("Rawfiles") self.rawfile_table_view = QTableView() self.rawfile_table_view.horizontalHeader().setVisible(False) self.rawfile_table_view.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents) self.rawfile_dock_widget.setWidget(self.rawfile_table_view) self.rawfile_model = QStandardItemModel() self.rawfile_model.setHorizontalHeaderLabels(["Rawfiles"]) self.rawfile_table_view.setModel(self.rawfile_model) self.rawfile_model.itemChanged.connect(self.item_changed) self.addDockWidget(0x2, self.rawfile_dock_widget) # xic dock widget extraction parameter self.xic_dock_widget = QDockWidget("Xic extraction") self.xic_widget = XicWidget() self.xic_widget.plotButton.clicked.connect(self.plot) self.xic_dock_widget.setWidget(self.xic_widget) self.addDockWidget(0x2, self.xic_dock_widget) def handle_key_press_event(self, evt): if self.inf_line_tic_item is None: return times = [] if evt.key() == Qt.Key_Left: for rawfile in self.rawfiles_by_short_path.values()[:1]: if not rawfile.is_checked: continue curr_scan_id = self.curr_scan_id_by_short_path[rawfile.short_path] scan_ids = rawfile.reader.rt_by_scan_id_by_ms_level[1].keys() idx = scan_ids.index(curr_scan_id) times.append(rawfile.reader.rt_by_scan_id_by_ms_level[1][scan_ids[idx - 1]]) self.curr_scan_id_by_short_path[rawfile.short_path] = scan_ids[idx - 1] elif evt.key() == Qt.Key_Right: for rawfile in self.rawfiles_by_short_path.values()[:1]: if not rawfile.is_checked: continue curr_scan_id = self.curr_scan_id_by_short_path[rawfile.short_path] scan_ids = rawfile.reader.rt_by_scan_id_by_ms_level[1].keys() idx = scan_ids.index(curr_scan_id) times.append(rawfile.reader.rt_by_scan_id_by_ms_level[1][scan_ids[idx + 1]]) self.curr_scan_id_by_short_path[rawfile.short_path] = scan_ids[idx + 1] self._plot_spectrum() if times: self.inf_line_tic_item.setPos(sum(times) / float(len(times))) def _plot_spectrum(self): self.plot_widget_spectrum.clear() min_mz, max_mz = 1e9, 0 min_int, max_int = 1e10, 0 for rawfile in self.rawfiles_by_short_path.values(): if not rawfile.is_checked: continue scan_id, mzs, intensities = rawfile.reader.get_scan(self.curr_scan_id_by_short_path[rawfile.short_path]) min_mz = min(min_mz, mzs[0]) max_mz = max(max_mz, mzs[-1]) min_int = min(min_int, min(intensities)) max_int = max(max_int, max(intensities)) item = BarGraphItem(x=mzs, height=intensities, width=0.01, pen=rawfile.qcolor, brush=rawfile.qcolor) self.plot_widget_spectrum.addItem(item) self.plot_widget_spectrum.setLimits(xMin=min_mz, xMax=max_mz, yMin=min_int, yMax=max_int) def plot_spectrum(self, ev): #clear if ev.button() == Qt.RightButton: return self.plot_widget_spectrum.clear() vb = self.plot_widget_tic.vb mouse_point = vb.mapSceneToView(ev.scenePos()) t = mouse_point.x() if self.inf_line_tic_item is None: self.inf_line_tic_item = InfiniteLine(pos=t, angle=90) self.plot_widget_tic.addItem(self.inf_line_tic_item) self.inf_line_tic_item.setMovable(True) else: self.inf_line_tic_item.setPos(t) min_mz, max_mz = 1e9, 0 min_int, max_int = 1e10, 0 for rawfile in self.rawfiles_by_short_path.values(): if not rawfile.is_checked: continue scan_id, mzs, intensities = rawfile.reader.get_scan_for_time(t) self.curr_scan_id_by_short_path[rawfile.short_path] = scan_id min_mz = min(min_mz, mzs[0]) max_mz = max(max_mz, mzs[-1]) min_int = min(min_int, min(intensities)) max_int = max(max_int, max(intensities)) item = BarGraphItem(x=mzs, height=intensities, width=0.01, pen=rawfile.qcolor, brush=rawfile.qcolor) self.plot_widget_spectrum.addItem(item) self.plot_widget_spectrum.setLimits(xMin=min_mz, xMax=max_mz, yMin=min_int, yMax=max_int) def item_changed(self, item): print "item changed", item.text() s = item.text() if item.checkState(): self.rawfiles_by_short_path[s].is_checked = True else: self.rawfiles_by_short_path[s].is_checked = False #self.qApp.emit(SIGNAL('redraw()')) self.update_plot_() def show_open_dialog(self): files = QFileDialog(self).getOpenFileNames() if files: preload = Preloader(files, self) preload.loaded.connect(self.update_rawfile_model) preload.start() def update_rawfile_model(self, obj): files, r = obj[0], obj[1] n = len(files) not_database = [] min_time, max_time = 1e9, 0 min_int, max_int = 1e9, 0 for i, f in enumerate(files): i_f = float(i) c = WithoutBlank.get_color(i_f / n, asQColor=True) c_ = WithoutBlank.get_color(i_f / n, asQColor=True) filename = f.split("\\")[-1] abs_path = str(f.replace("\\", "\\\\")) if r[i]: rawfile = Rawfile(abs_path, c, filename) self.rawfiles_by_short_path[filename] = rawfile #[MzDBReader(abs_path), c, True] self.rawfile_model.appendRow(Aditi.get_coloured_root_item(filename, c, c_)) times, intensities = rawfile.reader.get_tic() min_time = min(min_time, min(times)) max_time = max(max_time, max(times)) min_int = min(min_int, min(intensities)) max_int = max(max_int, max(intensities)) self.plot_widget_tic.plot(times, intensities, pen=mkPen(color=rawfile.qcolor, width=1.3)) else: not_database.append(str(filename)) self.plot_widget_tic.setLimits(xMin=min_time, xMax=max_time, yMin=min_int, yMax=max_int) self.plot_widget_tic.scene().sigMouseClicked.connect(self.plot_spectrum) if not_database: v = "\n".join(not_database) QMessageBox.information(self, "Error", "The following files are not valid sqlite database:\n" + v) @staticmethod def get_coloured_root_item(filepath, color, colorr): root = QStandardItem(filepath) gradient = QLinearGradient(-100, -100, 100, 100) gradient.setColorAt(0.7, colorr) gradient.setColorAt(1, color) root.setBackground(QBrush(gradient)) root.setEditable(False) root.setCheckState(Qt.Checked) root.setCheckable(True) return root def quit(self): res = QMessageBox.warning(self, "Exiting...", "Are you sure ?", QMessageBox.Ok | QMessageBox.Cancel) if res == QMessageBox.Cancel: return QtGui.qApp.quit() def plot(self): #clear pw self.plot_widget_xic.clear() # check sample checked checked_files = [rawfile for rawfile in self.rawfiles_by_short_path.values() if rawfile.is_checked] mz = self.xic_widget.mzSpinBox.value() mz_tol = self.xic_widget.mzTolSpinBox.value() mz_diff = mz * mz_tol / 1e6 min_mz, max_mz = mz - mz_diff, mz + mz_diff #Thread implementation not as fast # args = [(data[0], min_mz, max_mz, data[2]) for data in checked_files] # extractor_thread = Extractor(args, self) # extractor_thread.extracted.connect(self._plot) # extractor_thread.start() min_time_val, max_time_val = 10000, 0 min_int_val, max_int_val = 1e9, 0 for rawfile in checked_files: t1 = time.clock() times, intensities = rawfile.reader.get_xic(min_mz, max_mz) print "elapsed: ", time.clock() - t1 # min_time_val = min(min_time_val, times[0]) # max_time_val = max(max_time_val, times[-1]) # min_int_val = min(min_int_val, min(intensities)) # max_int_val = max(max_int_val, max(intensities)) item = self.plot_widget_xic.plot(times, intensities, pen=mkPen(color=rawfile.qcolor, width=1.3)) item.curve.setClickable(True) def on_curve_clicked(): if not rawfile.is_highlighted: item.setPen(mkPen(color=rawfile.qcolor, width=4)) rawfile.is_highlighted = True else: item.setPen(mkPen(color=rawfile.qcolor, width=2)) rawfile.is_highlighted = False item.sigClicked.connect(on_curve_clicked) #item.sigHovered = on_curve_clicked self.xic_by_rawfile_short_path[rawfile.short_path] = item self.plot_widget_xic.setTitle(title="Xic@" + str(mz)) #self.plot_widget_xic.setLimits(xMin=min_time_val, xMax=max_time_val, yMin=min_int_val, yMax=max_int_val) def update_plot_(self): for rawfile in self.rawfiles_by_short_path.viewvalues(): if rawfile.is_checked: try: self.plot_widget_xic.addItem(self.xic_by_rawfile_short_path[rawfile.short_path]) except KeyError: mz = self.xic_widget.mzSpinBox.value() mz_tol = self.xic_widget.mzTolSpinBox.value() mz_diff = mz * mz_tol / 1e6 min_mz, max_mz = mz - mz_diff, mz + mz_diff times, intensities = rawfile.reader.get_xic(min_mz, max_mz) item = self.plot_widget_xic.plot(times, intensities, pen=mkPen(color=rawfile.qcolor, width=2)) self.xic_by_rawfile_short_path[rawfile.short_path] = item else: try: #self.plot_widget_xic.removeItem(self.xic_by_rawfile_short_path[rawfile.short_path]) self.xic_by_rawfile_short_path[rawfile.short_path].hide() except KeyError: pass
class TalkEditorApp(FreeseerApp): '''Freeseer talk database editor main gui class''' def __init__(self, config, db): FreeseerApp.__init__(self) self.config = config self.db = db icon = QIcon() icon.addPixmap(QPixmap(':/freeseer/logo.png'), QIcon.Normal, QIcon.Off) self.setWindowIcon(icon) self.resize(960, 600) # # Setup Layout # self.mainWidget = QWidget() self.mainLayout = QVBoxLayout() self.mainWidget.setLayout(self.mainLayout) self.setCentralWidget(self.mainWidget) self.mainLayout.setAlignment(Qt.AlignTop) # Add custom widgets self.commandButtons = CommandButtons() self.tableView = QTableView() self.tableView.setSortingEnabled(True) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.talkDetailsWidget = TalkDetailsWidget() self.importTalksWidget = ImportTalksWidget() self.newTalkWidget = NewTalkWidget() self.mainLayout.addWidget(self.importTalksWidget) #self.mainLayout.addLayout(self.titleLayout) self.mainLayout.addWidget(self.commandButtons) self.mainLayout.addWidget(self.tableView) self.mainLayout.addWidget(self.talkDetailsWidget) self.mainLayout.addWidget(self.importTalksWidget) # --- End Layout # Initialize geometry, to be used for restoring window positioning. self.geometry = None # # Setup Menubar # self.actionExportCsv = QAction(self) self.actionExportCsv.setObjectName('actionExportCsv') self.actionRemoveAll = QAction(self) self.actionRemoveAll.setObjectName('actionRemoveAll') # Actions self.menuFile.insertAction(self.actionExit, self.actionExportCsv) self.menuFile.insertAction(self.actionExit, self.actionRemoveAll) # --- End Menubar # # TableView Connections # self.connect(self.tableView, SIGNAL('activated(const QModelIndex)'), self.talk_selected) self.connect(self.tableView, SIGNAL('selected(const QModelIndex)'), self.talk_selected) self.connect(self.tableView, SIGNAL('clicked(const QModelIndex)'), self.talk_selected) # Import Widget self.connect(self.importTalksWidget.csvRadioButton, SIGNAL('toggled(bool)'), self.toggle_import) self.connect(self.importTalksWidget.importButton, SIGNAL('clicked()'), self.import_talks) self.connect(self.importTalksWidget.cancelButton, SIGNAL('clicked()'), self.hide_import_talks_widget) self.importTalksWidget.setHidden(True) self.connect(self.importTalksWidget.csvFileSelectButton, SIGNAL('clicked()'), self.csv_file_select) self.connect(self.importTalksWidget.csvLineEdit, SIGNAL('returnPressed()'), self.importTalksWidget.importButton.click) self.connect(self.importTalksWidget.rssLineEdit, SIGNAL('returnPressed()'), self.importTalksWidget.importButton.click) self.connect(self.actionExportCsv, SIGNAL('triggered()'), self.export_talks_to_csv) self.connect(self.actionRemoveAll, SIGNAL('triggered()'), self.confirm_reset) # Command Buttons self.connect(self.commandButtons.addButton, SIGNAL('clicked()'), self.show_new_talk_popup) self.connect(self.commandButtons.removeButton, SIGNAL('clicked()'), self.remove_talk) self.connect(self.commandButtons.removeAllButton, SIGNAL('clicked()'), self.confirm_reset) self.connect(self.commandButtons.importButton, SIGNAL('clicked()'), self.show_import_talks_widget) self.connect(self.commandButtons.exportButton, SIGNAL('clicked()'), self.export_talks_to_csv) self.connect(self.commandButtons.searchButton, SIGNAL('clicked()'), self.search_talks) self.connect(self.commandButtons.searchLineEdit, SIGNAL('textEdited(QString)'), self.search_talks) self.connect(self.commandButtons.searchLineEdit, SIGNAL('returnPressed()'), self.search_talks) # Talk Details Buttons self.connect(self.talkDetailsWidget.saveButton, SIGNAL('clicked()'), self.update_talk) # Talk Details Widget self.connect(self.talkDetailsWidget.titleLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.presenterLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.categoryLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.eventLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.roomLineEdit, SIGNAL('textEdited(const QString)'), self.enable_save) self.connect(self.talkDetailsWidget.descriptionTextEdit, SIGNAL('modificationChanged(bool)'), self.enable_save) self.connect(self.talkDetailsWidget.dateEdit, SIGNAL('dateChanged(const QDate)'), self.enable_save) self.connect(self.talkDetailsWidget.startTimeEdit, SIGNAL('timeChanged(const QTime)'), self.enable_save) self.connect(self.talkDetailsWidget.endTimeEdit, SIGNAL('timeChanged(const QTime)'), self.enable_save) # New Talk Widget self.newTalkWidget.connect(self.newTalkWidget.addButton, SIGNAL('clicked()'), self.add_talk) self.newTalkWidget.connect(self.newTalkWidget.cancelButton, SIGNAL('clicked()'), self.newTalkWidget.reject) # Load default language actions = self.menuLanguage.actions() for action in actions: if action.data().toString() == self.config.default_language: action.setChecked(True) self.translate(action) break # Load Talk Database self.load_presentations_model() # Setup Autocompletion self.update_autocomplete_fields() self.talkDetailsWidget.saveButton.setEnabled(False) # Select first item #self.tableView.setCurrentIndex(self.proxy.index(0,0)) #self.talk_selected(self.proxy.index(0,0)) # # Translation # def retranslate(self): self.setWindowTitle(self.app.translate("TalkEditorApp", "Freeseer Talk Editor")) # # Reusable Strings # self.confirmDBClearTitleString = self.app.translate("TalkEditorApp", "Remove All Talks from Database") self.confirmDBClearQuestionString = self.app.translate("TalkEditorApp", "Are you sure you want to clear the DB?") self.confirmTalkDetailsClearTitleString = self.app.translate("TalkEditorApp", "Unsaved Data") self.confirmTalkDetailsClearQuestionString = self.app.translate("TalkEditorApp", "Unsaved talk details will be lost. Continue?") # --- End Reusable Strings # # Menubar # self.actionExportCsv.setText(self.app.translate("TalkEditorApp", "&Export to CSV")) self.actionRemoveAll.setText(self.app.translate("TalkEditorApp", "&Remove All Talks")) # --- End Menubar # # TalkDetailsWidget # self.talkDetailsWidget.titleLabel.setText(self.app.translate("TalkEditorApp", "Title")) self.talkDetailsWidget.presenterLabel.setText(self.app.translate("TalkEditorApp", "Presenter")) self.talkDetailsWidget.categoryLabel.setText(self.app.translate("TalkEditorApp", "Category")) self.talkDetailsWidget.eventLabel.setText(self.app.translate("TalkEditorApp", "Event")) self.talkDetailsWidget.roomLabel.setText(self.app.translate("TalkEditorApp", "Room")) self.talkDetailsWidget.dateLabel.setText(self.app.translate("TalkEditorApp", "Date")) self.talkDetailsWidget.startTimeLabel.setText(self.app.translate("TalkEditorApp", "Start Time")) self.talkDetailsWidget.endTimeLabel.setText(self.app.translate("TalkEditorApp", "End Time")) # --- End TalkDetailsWidget # # Import Talks Widget Translations # self.importTalksWidget.rssRadioButton.setText(self.app.translate("TalkEditorApp", "RSS URL")) self.importTalksWidget.csvRadioButton.setText(self.app.translate("TalkEditorApp", "CSV File")) self.importTalksWidget.importButton.setText(self.app.translate("TalkEditorApp", "Import")) # --- End Talks Widget Translations # # Command Button Translations\ # self.commandButtons.importButton.setText(self.app.translate("TalkEditorApp", "Import")) self.commandButtons.exportButton.setText(self.app.translate("TalkEditorApp", "Export")) self.commandButtons.addButton.setText(self.app.translate("TalkEditorApp", "Add New Talk")) self.commandButtons.removeButton.setText(self.app.translate("TalkEditorApp", "Remove")) self.commandButtons.removeAllButton.setText(self.app.translate("TalkEditorApp", "Remove All")) # --- End Command Butotn Translations # # Search Widget Translations # self.commandButtons.searchButton.setText(self.app.translate("TalkEditorApp", "Search")) # --- End Command Button Translations def load_presentations_model(self): # Load Presentation Model self.presentationModel = self.db.get_presentations_model() self.proxy = QSortFilterProxyModel() self.proxy.setSourceModel(self.presentationModel) self.tableView.setModel(self.proxy) self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive) # Fill table whitespace. self.tableView.horizontalHeader().setStretchLastSection(False) self.tableView.horizontalHeader().setResizeMode(1, QHeaderView.Stretch) # Hide the ID field self.tableView.setColumnHidden(0, True) # Map data to widgets self.mapper = QDataWidgetMapper() self.mapper.setModel(self.proxy) self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit) self.mapper.addMapping(self.talkDetailsWidget.titleLineEdit, 1) self.mapper.addMapping(self.talkDetailsWidget.presenterLineEdit, 2) self.mapper.addMapping(self.talkDetailsWidget.categoryLineEdit, 4) self.mapper.addMapping(self.talkDetailsWidget.eventLineEdit, 5) self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6) self.mapper.addMapping(self.talkDetailsWidget.descriptionTextEdit, 3) self.mapper.addMapping(self.talkDetailsWidget.dateEdit, 7) self.mapper.addMapping(self.talkDetailsWidget.startTimeEdit, 8) self.mapper.addMapping(self.talkDetailsWidget.endTimeEdit, 9) # Load StringLists self.titleList = QStringList(self.db.get_string_list("Title")) #self.speakerList = QStringList(self.db.get_speaker_list()) #self.categoryList = QStringList(self.db.get_category_list()) #self.eventList = QStringList(self.db.get_event_list()) #self.roomList = QStringList(self.db.get_room_list()) #Disble input self.talkDetailsWidget.disable_input_fields() def search_talks(self): # The default value is 0. If the value is -1, the keys will be read from all columns. self.proxy.setFilterKeyColumn(-1) self.proxy.setFilterFixedString(self.commandButtons.searchLineEdit.text()) def talk_selected(self, model): self.mapper.setCurrentIndex(model.row()) self.talkDetailsWidget.enable_input_fields() self.talkDetailsWidget.saveButton.setEnabled(False) def toggle_import(self): if self.importTalksWidget.csvRadioButton.isChecked(): self.importTalksWidget.csvLineEdit.setEnabled(True) self.importTalksWidget.csvFileSelectButton.setEnabled(True) self.importTalksWidget.rssLineEdit.setEnabled(False) else: self.importTalksWidget.csvLineEdit.setEnabled(False) self.importTalksWidget.csvFileSelectButton.setEnabled(False) self.importTalksWidget.rssLineEdit.setEnabled(True) def show_import_talks_widget(self): self.commandButtons.setHidden(True) self.tableView.setHidden(True) self.talkDetailsWidget.setHidden(True) self.importTalksWidget.setHidden(False) def hide_import_talks_widget(self): self.commandButtons.setHidden(False) self.tableView.setHidden(False) self.talkDetailsWidget.setHidden(False) self.importTalksWidget.setHidden(True) def add_talk(self): """Adds a new talk to the database using data from the NewTalkWidget input fields""" presentation = self.create_presentation(self.newTalkWidget.talkDetailsWidget) if presentation: self.db.insert_presentation(presentation) self.newTalkWidget.accept() # Close the dialog def update_talk(self): """Updates the currently selected talk using data from the TalkEditorApp input fields""" selected_talk = self.tableView.currentIndex() if selected_talk.row() >= 0: # The tableView index begins at 0 and is -1 by default talk_id = selected_talk.sibling(selected_talk.row(), 0).data().toString() presentation = self.create_presentation(self.talkDetailsWidget) if presentation: self.db.update_presentation(talk_id, presentation) self.apply_changes(selected_talk) self.talkDetailsWidget.saveButton.setEnabled(False) def create_presentation(self, talkDetailsWidget): """Creates and returns an instance of Presentation using data from the input fields""" date = talkDetailsWidget.dateEdit.date() startTime = talkDetailsWidget.startTimeEdit.time() endTime = talkDetailsWidget.endTimeEdit.time() title = unicode(talkDetailsWidget.titleLineEdit.text()).strip() if title: return Presentation( unicode(talkDetailsWidget.titleLineEdit.text()).strip(), unicode(talkDetailsWidget.presenterLineEdit.text()).strip(), unicode(talkDetailsWidget.descriptionTextEdit.toPlainText()).strip(), unicode(talkDetailsWidget.categoryLineEdit.text()).strip(), unicode(talkDetailsWidget.eventLineEdit.text()).strip(), unicode(talkDetailsWidget.roomLineEdit.text()).strip(), unicode(date.toString(Qt.ISODate)), unicode(startTime.toString(Qt.ISODate)), unicode(endTime.toString(Qt.ISODate))) def show_new_talk_popup(self): """Displays a modal dialog with a talk details view When Add is selected, a new talk is added to the database using the input field data. When Cancel is selected, no talk is added. """ log.info('Opening Add Talk window...') self.clear_new_talk_fields() self.remove_new_talk_placeholder_text() self.newTalkWidget.talkDetailsWidget.titleLineEdit.setFocus() if self.newTalkWidget.exec_() == 1: self.apply_changes() self.talkDetailsWidget.disable_input_fields() else: log.info('No talk added...') def apply_changes(self, updated_talk=None): """Repopulates the model to display the effective changes Updates the autocomplete fields. Displays the updated model in the table view, and selects the newly updated/added talk. """ self.presentationModel.select() self.select_talk(updated_talk) self.update_autocomplete_fields() def select_talk(self, talk=None): """Selects the given talk in the table view If no talk is given, the last row in the table view is selected. """ if talk: row = talk.row() column = talk.column() else: row = self.presentationModel.rowCount() - 1 # Select last row column = 0 self.tableView.selectRow(row) self.tableView.setCurrentIndex(self.proxy.index(row, column)) self.talk_selected(self.proxy.index(row, column)) def remove_talk(self): try: rows_selected = self.tableView.selectionModel().selectedRows() except: return # Reversed because rows in list change position once row is removed for row in reversed(rows_selected): self.presentationModel.removeRow(row.row()) def load_talk(self): try: self.tableView.currentIndex().row() except: return self.mapper.addMapping(self.talkDetailsWidget.roomLineEdit, 6) self.presentationModel.select() def reset(self): self.db.clear_database() self.presentationModel.select() def confirm_reset(self): """Presents a confirmation dialog to ask the user if they are sure they wish to remove the talk database. If Yes call the reset() function""" confirm = QMessageBox.question(self, self.confirmDBClearTitleString, self.confirmDBClearQuestionString, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if confirm == QMessageBox.Yes: self.reset() def add_talks_from_rss(self): rss_url = unicode(self.importTalksWidget.rssLineEdit.text()) if rss_url: self.db.add_talks_from_rss(rss_url) self.presentationModel.select() self.hide_import_talks_widget() else: error = QMessageBox() error.setText("Please enter a RSS URL") error.exec_() def closeEvent(self, event): log.info('Exiting talk database editor...') self.geometry = self.saveGeometry() event.accept() def csv_file_select(self): fname = QFileDialog.getOpenFileName( self, 'Select file', "", "*.csv") if fname: self.importTalksWidget.csvLineEdit.setText(fname) def add_talks_from_csv(self): fname = self.importTalksWidget.csvLineEdit.text() if fname: self.db.add_talks_from_csv(fname) self.presentationModel.select() self.hide_import_talks_widget() else: error = QMessageBox() error.setText("Please select a file") error.exec_() def import_talks(self): if self.importTalksWidget.csvRadioButton.isChecked(): self.add_talks_from_csv() else: self.add_talks_from_rss() self.update_autocomplete_fields() def export_talks_to_csv(self): fname = QFileDialog.getSaveFileName(self, 'Select file', "", "*.csv") if fname: self.db.export_talks_to_csv(fname) def update_autocomplete_fields(self): self.titleList = QStringList(self.db.get_string_list("Title")) self.speakerList = QStringList(self.db.get_string_list("Speaker")) self.categoryList = QStringList(self.db.get_string_list("Category")) self.eventList = QStringList(self.db.get_string_list("Event")) self.roomList = QStringList(self.db.get_string_list("Room")) self.titleCompleter = QCompleter(self.titleList) self.titleCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.speakerCompleter = QCompleter(self.speakerList) self.speakerCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.categoryCompleter = QCompleter(self.categoryList) self.categoryCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.eventCompleter = QCompleter(self.eventList) self.eventCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.roomCompleter = QCompleter(self.roomList) self.roomCompleter.setCaseSensitivity(Qt.CaseInsensitive) self.talkDetailsWidget.titleLineEdit.setCompleter(self.titleCompleter) self.talkDetailsWidget.presenterLineEdit.setCompleter(self.speakerCompleter) self.talkDetailsWidget.categoryLineEdit.setCompleter(self.categoryCompleter) self.talkDetailsWidget.eventLineEdit.setCompleter(self.eventCompleter) self.talkDetailsWidget.roomLineEdit.setCompleter(self.roomCompleter) def are_fields_enabled(self): return (self.talkDetailsWidget.titleLineEdit.isEnabled() and self.talkDetailsWidget.presenterLineEdit.isEnabled() and self.talkDetailsWidget.categoryLineEdit.isEnabled() and self.talkDetailsWidget.eventLineEdit.isEnabled() and self.talkDetailsWidget.roomLineEdit.isEnabled() and self.talkDetailsWidget.dateEdit.isEnabled() and self.talkDetailsWidget.startTimeEdit.isEnabled() and self.talkDetailsWidget.endTimeEdit.isEnabled()) def unsaved_details_exist(self): """Checks if changes have been made to new/existing talk details Looks for text in the input fields and check the enabled state of the Save Talk button If the Save Talk button is enabled, the input fields contain modified values """ return (self.talkDetailsWidget.saveButton.isEnabled() and (self.talkDetailsWidget.titleLineEdit.text() or self.talkDetailsWidget.presenterLineEdit.text() or self.talkDetailsWidget.categoryLineEdit.text() or self.talkDetailsWidget.descriptionTextEdit.toPlainText())) def enable_save(self): self.talkDetailsWidget.saveButton.setEnabled(True) def clear_new_talk_fields(self): """Removes existing data from all NewTalkWidget fields except event, room, date and time""" self.newTalkWidget.talkDetailsWidget.titleLineEdit.clear() self.newTalkWidget.talkDetailsWidget.presenterLineEdit.clear() self.newTalkWidget.talkDetailsWidget.descriptionTextEdit.clear() self.newTalkWidget.talkDetailsWidget.categoryLineEdit.clear() def remove_new_talk_placeholder_text(self): """Removes placeholder text in NewTalkWidget originally set by TalkDetailsWidget""" self.newTalkWidget.talkDetailsWidget.titleLineEdit.setPlaceholderText("") self.newTalkWidget.talkDetailsWidget.presenterLineEdit.setPlaceholderText("") self.newTalkWidget.talkDetailsWidget.categoryLineEdit.setPlaceholderText("") self.newTalkWidget.talkDetailsWidget.eventLineEdit.setPlaceholderText("") self.newTalkWidget.talkDetailsWidget.roomLineEdit.setPlaceholderText("")
class previewDlg(QMainWindow): ''' classdocs ''' def __init__(self, parent, comp, basePMCheck, model): ''' Constructor ''' QMainWindow.__init__(self, parent) self.basePMCheck = basePMCheck # self.ui = Ui_Previewself.grbPageProperty() # self.ui.setupUi(self) self.resize(1000, 700) self.setWindowTitle("Preview Dialog") self.view = QgsComposerView(self) viewLayout = QGridLayout() viewLayout.setSpacing(0) viewLayout.setMargin(0) mHorizontalRuler = QgsComposerRuler(QgsComposerRuler.Horizontal) mVerticalRuler = QgsComposerRuler(QgsComposerRuler.Vertical) mRulerLayoutFix = QWidget() mRulerLayoutFix.setAttribute(Qt.WA_NoMousePropagation) mRulerLayoutFix.setBackgroundRole(QPalette.Window) mRulerLayoutFix.setFixedSize(mVerticalRuler.rulerSize(), mHorizontalRuler.rulerSize()) viewLayout.addWidget(mRulerLayoutFix, 0, 0) viewLayout.addWidget(mHorizontalRuler, 0, 1) viewLayout.addWidget(mVerticalRuler, 1, 0) self.view.setContentsMargins(0, 0, 0, 0) self.view.setHorizontalRuler(mHorizontalRuler) self.view.setVerticalRuler(mVerticalRuler) viewLayout.addWidget(self.view, 1, 1) # self.scene = comp self.view.setZoomLevel(1.0) self.view.setComposition(comp) self.scene = self.view.composition() layout = QVBoxLayout() hLayout = QHBoxLayout() hLayout.addLayout(viewLayout) self.mapItem = self.scene.getComposerMapById(0) self.view.scale(2.8, 2.8) self.view.setPreviewModeEnabled(True) self.toolBarAction = self.addToolBar("composer action") self.actionMapRefresh = QAction(self) self.actionMapRefresh.setObjectName("actionMapRefresh") icon3 = QIcon("Resource/Refresh.png") self.actionMapRefresh.setIcon(icon3) self.actionMapRefresh.setToolTip("Refresh") # self.textItemAction.setCheckable(True) self.connect(self.actionMapRefresh, SIGNAL("triggered()"), self.actionMapRefresh_triggered) self.toolBarAction.addAction(self.actionMapRefresh) # # self.templeteCreateAction = QAction(self) # # self.templeteCreateAction.setObjectName("createTempleteAction") # # icon4 = QIcon("Resource\\templetepointer.png") # # self.templeteCreateAction.setIcon(icon4) # # self.templeteCreateAction.setToolTip("Create Templete") # # self.templeteCreateAction.setCheckable(True) # # self.connect(self.templeteCreateAction, SIGNAL("triggered()"), self.createTempleteAction) # # self.toolBar.addAction(self.templeteCreateAction) # layout.insertWidget(0, self.toolBar) # self.scene.selectedItemChanged.connect(self.selectedItemDisplay) self.view.selectedItemChanged.connect(self.selectedItemDisplay) self.view.cursorPosChanged.connect(self.cursorPosChangedEvent) # self.connect(self.view, SIGNAL("selectedItemChanged(QgsComposerItem)"),self, SLOT("selectedItemDisplay(QgsComposerItem)")) # self.scene.composerLabelAdded.connect(self.composerLabelAddedEvent) self.view.itemRemoved.connect(self.deleteItem) # self.connect( self.view, SIGNAL( "actionFinished()" ), self.setSelectionTool) #listen out for position updates from the QgsComposerView self.propertyWidget = QWidget(self) hLayout.addWidget(self.propertyWidget) self.propertyWidget.setObjectName("propertyWidget") self.propertyWidget.resize(222, 302) self.vLayout_3 = QVBoxLayout(self.propertyWidget) self.vLayout_3.setObjectName("vLayout_3") self.groupBox = QGroupBox(self.propertyWidget) self.groupBox.setObjectName("groupBox") self.horizontalLayout_2 = QHBoxLayout(self.groupBox) self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.frame = QFrame(self.groupBox) self.frame.setFrameShape(QFrame.StyledPanel) self.frame.setFrameShadow(QFrame.Raised) self.frame.setObjectName("frame") self.verticalLayout = QVBoxLayout(self.frame) self.verticalLayout.setObjectName("verticalLayout") self.label = QLabel(self.frame) self.label.setObjectName("label") self.verticalLayout.addWidget(self.label) self.labelText = QPlainTextEdit(self.frame) self.labelText.setObjectName("labelText") self.verticalLayout.addWidget(self.labelText) self.btnLabelFont = QPushButton(self.frame) self.btnLabelFont.setObjectName("btnLabelFont") self.verticalLayout.addWidget(self.btnLabelFont) self.btnLabelColor = QPushButton(self.frame) self.btnLabelColor.setObjectName("btnLabelColor") self.verticalLayout.addWidget(self.btnLabelColor) self.frame_2 = QFrame(self.frame) self.frame_2.setFrameShape(QFrame.StyledPanel) self.frame_2.setFrameShadow(QFrame.Raised) self.frame_2.setObjectName("frame_2") self.horizontalLayout = QHBoxLayout(self.frame_2) self.horizontalLayout.setObjectName("horizontalLayout") self.label_2 = QLabel(self.frame_2) self.label_2.setObjectName("label_2") self.horizontalLayout.addWidget(self.label_2) self.spinLabelRotation = QSpinBox(self.frame_2) self.spinLabelRotation.setObjectName("spinLabelRotation") self.spinLabelRotation.setMinimum(-360) self.spinLabelRotation.setMaximum(360) self.horizontalLayout.addWidget(self.spinLabelRotation) self.verticalLayout.addWidget(self.frame_2) self.chbBackgroundEnable = QCheckBox(self.frame) self.chbBackgroundEnable.setChecked(True) self.chbBackgroundEnable.setObjectName("chbBackgroundEnable") self.verticalLayout.addWidget(self.chbBackgroundEnable) self.horizontalLayout_2.addWidget(self.frame) self.vLayout_3.addWidget(self.groupBox) self.resolutionFrame = QFrame(self.frame) self.resolutionFrame.setFrameShape(QFrame.StyledPanel) self.resolutionFrame.setFrameShadow(QFrame.Raised) self.resolutionFrame.setObjectName("resolutionFrame") self.horizontalLayout4 = QHBoxLayout(self.resolutionFrame) self.horizontalLayout4.setObjectName("horizontalLayout4") self.label_resolution = QLabel(self.resolutionFrame) self.label_resolution.setObjectName("label_resolution") self.label_resolution.setText("Print Resolution (dpi):") self.horizontalLayout4.addWidget(self.label_resolution) self.spinResolution = QSpinBox(self.resolutionFrame) self.spinResolution.setObjectName("spinResolution") self.spinResolution.setMinimum(0) self.spinResolution.setMaximum(1000) self.spinResolution.setValue(300) self.horizontalLayout4.addWidget(self.spinResolution) # self.verticalLayout.addWidget(self.frame_2) self.vLayout_3.addWidget(self.resolutionFrame) self.gbTable = GroupBox(self.propertyWidget) self.gbTable.Caption = "Table" self.vLayout_3.addWidget(self.gbTable) self.mTableView = QTableView(self.gbTable) self.gbTable.Add = self.mTableView hHeder = self.mTableView.horizontalHeader() hHeder.setVisible(False) vHeder = self.mTableView.verticalHeader() vHeder.setVisible(False) # self.mTableView.setFixedHeight(70) # self.mTableView.setFixedWidth(comp.paperWidth() - 40) # self.stdItemModel = QStandardItemModel() # self. self.spaceItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.vLayout_3.addItem(self.spaceItem) self.groupBox.setTitle("Label Property") self.label.setText("Label Text:") self.btnLabelFont.setText("Label Font") self.btnLabelColor.setText("Label Color") self.label_2.setText("Label Rotation:") self.chbBackgroundEnable.setText("Background Enable") self.groupBox.setEnabled(False) self.connect(self.btnLabelFont, SIGNAL("clicked()"), self.btnLabelFontClick) self.connect(self.btnLabelColor, SIGNAL("clicked()"), self.btnLabelColorClick) self.connect(self.chbBackgroundEnable, SIGNAL("clicked()"), self.chbBackgroundEnableClick) self.labelText.textChanged.connect(self.labelTextChanged) self.spinLabelRotation.valueChanged.connect( self.spinLabelRotationValueChanged) layout.addLayout(hLayout) # self.btnBack = QPushButton() self.btnBack.setText("back") footerLayout = QHBoxLayout() footerLayout.addWidget(self.btnBack) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.buttonBox.setObjectName("buttonBox") footerLayout.addWidget(self.buttonBox) layout.addLayout(footerLayout) self.setLayout(layout) deleteItemKey = QShortcut(QKeySequence(Qt.Key_Delete), self) deleteItemKey.activated.connect(self.deleteItem) # self.btnBack.clicked.connect(self.back) self.connect(self.buttonBox, SIGNAL("accepted()"), self.acceptMethod) self.connect(self.buttonBox, SIGNAL("rejected()"), self.reject) self.btnCancel = self.buttonBox.button(QDialogButtonBox.Cancel) self.view.setCurrentTool(QgsComposerView.Select) self.btnLabelColor.setVisible(False) # self.btnBack.setVisible(False) self.chbBackgroundEnable.setVisible(False) # self.view.emit(SIGNAL("actionFinished")) # if self.scene.plotStyle() != QgsComposition.Preview: # self.scene.setPlotStyle(QgsComposition.Preview) # self.mapItem.setPreviewMode(QgsComposerMap.Render) # self.mapItem.updateCachedImage() # self.mapItem.setSelected(True) self.mComposition = comp self.composerMapItem = self.mComposition.composerMapItems()[0] self.composerMapItem.setUpdatesEnabled(True) self.mStdModel = model self.mTableView.setModel(self.mStdModel) self.mTableView.setSpan(0, 0, 1, 6) self.mTableView.setSpan(1, 0, 1, 2) self.mTableView.setSpan(2, 0, 2, 1) self.mTableView.setSpan(4, 0, 1, 2) self.mTableView.setSpan(5, 0, 1, 2) self.mTableView.setSpan(6, 0, 1, 2) self.mTableView.setSpan(0, 6, 1, 8) self.mTableView.setSpan(1, 7, 1, 4) self.mTableView.setSpan(1, 11, 1, 3) self.mTableView.setSpan(2, 7, 1, 4) self.mTableView.setSpan(2, 11, 1, 3) def acceptMethod(self): # self.mStdModel.setItem(0, QStandardItem("nnnnnnnn")) filePath = QFileDialog.getSaveFileName( self, "Save PDF File", QCoreApplication.applicationDirPath(), "pdf files(*.pdf )") if filePath == "": return self.mComposition.clearSelection() self.mComposition.setPrintResolution(self.spinResolution.value()) resultPdf = self.mComposition.exportAsPDF(filePath) if resultPdf: message = QMessageBox.information(self, "Result", "Successful export PDF") else: message = QMessageBox.information(self, "Result", "Don't export PDF") def rePresent(self, comp, model): self.mComposition = comp self.mStdModel = model self.view.setComposition(comp) self.scene = self.view.composition() def back(self): self.done(2) def spinLabelRotationValueChanged(self, rotationValue): self.selectedLabelItem.setItemRotation(rotationValue) def cursorPosChangedEvent(self, scenePointF): self.scenePoint = scenePointF # i = 100 def labelTextChanged(self): self.selectedLabelItem.beginCommand( "Label text changed", QgsComposerMergeCommand.ComposerLabelSetText) self.selectedLabelItem.blockSignals(True) self.selectedLabelItem.setText(self.labelText.toPlainText()) self.selectedLabelItem.update() self.selectedLabelItem.blockSignals(False) self.selectedLabelItem.endCommand() def chbBackgroundEnableClick(self): if self.chbBackgroundEnable.isChecked(): self.selectedLabelItem.setBackgroundEnabled(True) self.mapItem.updateCachedImage() else: self.selectedLabelItem.setBackgroundEnabled(False) self.mapItem.updateCachedImage() def btnLabelFontClick(self): dlgFont = QFontDialog(self) dlgFont.setCurrentFont(self.selectedLabelItem.font()) result = dlgFont.exec_() if result == 1: self.labelFont = dlgFont.selectedFont() else: self.labelFont = QFont() self.selectedLabelItem.setFont(self.labelFont) def btnLabelColorClick(self): dlgColor = QColorDialog(self) dlgColor.setCurrentColor(self.selectedLabelItem.fontColor()) result = dlgColor.exec_() if result == 1: self.labelColor = dlgColor.selectedColor() self.selectedLabelItem.setFontColor(self.labelColor) def createTempleteAction(self): if self.templeteCreateAction.isChecked() and self.basePMCheck: font = QFont("Arial", 13) font.setItalic(True) self.compLabel1 = QgsComposerLabel(self.scene) self.compLabel1.setFont(font) self.compLabel1.setText("South China Sea") self.compLabel1.setBackgroundEnabled(False) self.compLabel1.setItemPosition(156, 100) self.compLabel1.adjustSizeToText() self.compLabel1.setItemRotation(60) # mapitem = self.scene.composerMapItems() # mapitem[0].addItem(self.compLabel1) self.scene.addItem(self.compLabel1) self.compLabel2 = QgsComposerLabel(self.scene) self.compLabel2.setFont(font) self.compLabel2.setText("Straits Of Malacca") self.compLabel2.setBackgroundEnabled(False) self.compLabel2.setItemPosition(35, 100) self.compLabel2.adjustSizeToText() self.compLabel2.setItemRotation(60) self.scene.addItem(self.compLabel2) font.setItalic(False) self.compLabel3 = QgsComposerLabel(self.scene) self.compLabel3.setFont(font) self.compLabel3.setBackgroundEnabled(False) self.compLabel3.setText("THAILAND") self.compLabel3.setItemPosition(68, 60) self.compLabel3.adjustSizeToText() # self.compLabel3.setItemRotation(0.5) self.scene.addItem(self.compLabel3) # self.templeteCreateAction.setChecked(False) self.compLabel4 = QgsComposerLabel(self.scene) self.compLabel4.setFont(font) self.compLabel4.setBackgroundEnabled(False) self.compLabel4.setText("SINGAPORE") self.compLabel4.setItemPosition(141, 218) self.compLabel4.adjustSizeToText() # self.compLabel3.setItemRotation(0.5) self.scene.addItem(self.compLabel4) self.templeteCreateAction.setChecked(False) self.compLabel4.setSelected(True) elif self.templeteCreateAction.isChecked( ) and self.basePMCheck == False: font = QFont("Arial", 14) font.setItalic(True) self.compLabel5 = QgsComposerLabel(self.scene) self.compLabel5.setFont(font) self.compLabel5.setText("South China Sea") self.compLabel5.setBackgroundEnabled(False) self.compLabel5.setItemPosition(108, 86) self.compLabel5.adjustSizeToText() self.compLabel5.setItemRotation(-45) # mapitem = self.scene.composerMapItems() # mapitem[0].addItem(self.compLabel1) self.scene.addItem(self.compLabel5) self.compLabel6 = QgsComposerLabel(self.scene) self.compLabel6.setFont(font) self.compLabel6.setText("Sulu Sea") self.compLabel6.setBackgroundEnabled(False) self.compLabel6.setItemPosition(236, 38) self.compLabel6.adjustSizeToText() self.compLabel6.setItemRotation(45) self.scene.addItem(self.compLabel6) font.setItalic(False) self.compLabel7 = QgsComposerLabel(self.scene) self.compLabel7.setFont(font) self.compLabel7.setBackgroundEnabled(False) self.compLabel7.setText("Celebes Sea") self.compLabel7.setItemPosition(242, 112) self.compLabel7.adjustSizeToText() self.compLabel7.setItemRotation(-45) # self.compLabel3.setItemRotation(0.5) self.scene.addItem(self.compLabel7) # self.templeteCreateAction.setChecked(False) self.compLabel8 = QgsComposerLabel(self.scene) self.compLabel8.setFont(font) self.compLabel8.setBackgroundEnabled(False) self.compLabel8.setText("INDONESIA\n(Kalimantan)") self.compLabel8.setItemPosition(172, 148, 32, 16) # self.compLabel8.setHAlign(Qt.AlignHCenter) # self.compLabel8.setVAlign(Qt.AlignVCenter) # self.compLabel8.setFrameEnabled(False) # self.compLabel8.setItemPosition() # self.compLabel8.adjustSizeToText() # self.compLabl3.setItemRotation(0.5) self.scene.addItem(self.compLabel8) self.compLabel9 = QgsComposerLabel(self.scene) self.compLabel9.setFont(font) self.compLabel9.setBackgroundEnabled(False) self.compLabel9.setText("BRUNEI") self.compLabel9.setItemPosition(136, 83) self.compLabel9.adjustSizeToText() # self.compLabl3.setItemRotation(0.5) self.scene.addItem(self.compLabel9) self.templeteCreateAction.setChecked(False) pass def actionMapRefresh_triggered(self): self.view.setCurrentTool(QgsComposerView.AddRectangle) def setSelectionTool(self): self.view.deleteSelectedItems() font = QFont("Arial", 14) newLabelItem = QgsComposerLabel(self.scene) newLabelItem.setText("QGIS") newLabelItem.setFont(font) newLabelItem.setItemPosition(self.scenePoint.x(), self.scenePoint.y()) newLabelItem.adjustSizeToText() self.scene.addItem(newLabelItem) # selectItemPoint = self.scene.composerItemAt(self.scenePoint) newLabelItem.setSelected(True) self.groupBox.setEnabled(True) self.selectedLabelItem = newLabelItem # txt = self.selectedLabelItem.text() # textDoc = QTextDocument(txt) self.labelText.setPlainText(self.selectedLabelItem.text()) # self.scene.setSelectedItem(self.newLabelItem) self.view.setCurrentTool(QgsComposerView.Select) # self.selectedLabelItem = self.view.currentTool() self.textItemAction.setChecked(False) def selectedItemDisplay(self, item): if self.scene.plotStyle() != QgsComposition.Preview: self.scene.setPlotStyle(QgsComposition.Preview) self.mapItem.setPreviewMode(QgsComposerMap.Render) self.mapItem.updateCachedImage() item._class_ = QgsComposerLabel # selectedItems = self.scene.selectedComposerItems(True) # if isinstance(item, QgsComposerItem): # self.selectedLabelItem = item # if isinstance(item, QGraphicsRectItem): # self.selectedLabelItem = item if isinstance(item, QgsComposerLabel): self.selectedLabelItem = item self.groupBox.setEnabled(True) self.labelText.setPlainText(self.selectedLabelItem.text()) self.spinLabelRotation.setValue(self.selectedLabelItem.rotation()) else: self.groupBox.setEnabled(False) # print "debug" itemName = self.view.currentTool() if itemName == 5: item.setText("label") pass def deleteItem(self): self.view.deleteSelectedItems()
class DictValueDialog(QtHelper.EnhancedQDialog, Logger.ClassLogger): """ Dict dialog """ def __init__(self, parent, testParams, variables, advancedMode=False ): """ Operator to fill parameter description @param dataArgs: @type dataArgs: @param parent: @type parent: """ super(DictValueDialog, self).__init__(parent) self.advancedMode = advancedMode self.testParams = testParams self.variables = variables self.createDialog() self.createConnections() self.createActions() def createDialog (self): """ Create qt dialog """ self.buttonBox = QDialogButtonBox(self) self.buttonBox.setStyleSheet( """QDialogButtonBox { dialogbuttonbox-buttons-have-icons: 1; dialog-ok-icon: url(:/ok.png); dialog-cancel-icon: url(:/test-close-black.png); }""") self.buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) mainLayout = QVBoxLayout() self.dictTable = QTableView(self) self.model = DictTableModel(self, advancedMode=self.advancedMode) self.dictTable.setModel(self.model) self.dictTable.setFrameShape(QFrame.StyledPanel) self.dictTable.setShowGrid(True) self.dictTable.setGridStyle (Qt.DotLine) self.dictTable.setSelectionMode(QAbstractItemView.ExtendedSelection) self.dictTable.setSelectionBehavior(QAbstractItemView.SelectRows) self.dictTable.setContextMenuPolicy(Qt.CustomContextMenu) self.dictTable.verticalHeader().setVisible(False) self.dictTable.horizontalHeader().setHighlightSections(False) self.dictTable.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self.dictTable.horizontalHeader().setStretchLastSection(True) self.dictTable.setColumnWidth(COL_KEY, 200) # delegate item on advanced mode if self.advancedMode: self.dictTable.setItemDelegateForColumn( COL_KEY, ItemComboDelegate(self, COL_KEY) ) self.dictTable.setItemDelegateForColumn( COL_VALUE, ItemComboDelegate(self, COL_VALUE) ) mainLayout.addWidget(self.dictTable) mainLayout.addWidget(self.buttonBox) self.setLayout(mainLayout) self.setWindowTitle(self.tr("Dict configuration")) self.setMinimumWidth(500) self.center() def getInputs(self): """ Get test inputs """ return self.testParams.parameters.table().model.getData() def getOutputs(self): """ Get test outputs """ return self.testParams.parametersOutput.table().model.getData() def createConnections (self): """ Create qt connections """ self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.dictTable.customContextMenuRequested.connect(self.onPopupMenu) def getValue(self): """ Return value """ return self.model.getData() def createActions (self): """ Actions defined: * add * del """ self.addAction = QtHelper.createAction(self, self.tr("&Add"), self.addKey, icon = QIcon(":/test-parameter-add.png"), tip = self.tr('Add a new key') ) self.delAction = QtHelper.createAction(self, self.tr("&Delete"), self.delKey, icon = QIcon(":/test-parameter-del.png"), tip = self.tr('Delete the selected key') ) self.delAllAction = QtHelper.createAction(self, self.tr("&Delete All"), self.delKeys, icon = QIcon(":/test-parameter-del.png"), tip = self.tr('Delete the selected key') ) def addKey(self): """ Add key """ self.delAllAction.setEnabled(True) index = self.dictTable.currentIndex() if not index.isValid(): row = self.model.rowCount() else: row = index.row() data = self.model.getData() if self.advancedMode: tpl = { 'key': { 'operator': '', 'value': '', 'type': '' }, 'value': { 'operator': '', 'value': '', 'type': '' } } else: tpl = { 'key': 'my key', 'value': 'my value' } # add data to model data.insert(row + 1, tpl) self.model.reset() def clear (self): """ clear contents """ self.model.setDataModel( [] ) def delKey(self): """ Delete key """ # get selected proxy indexes indexes = self.dictTable.selectedIndexes() if not indexes: return if indexes: answer = QMessageBox.question(self, self.tr("Remove"), self.tr("Do you want to remove selected key?"), QMessageBox.Yes | QMessageBox.No) if answer == QMessageBox.Yes: self.removeValues(indexes) def removeValues(self, indexes): """ Remove values from data @param indexes: @type indexes: """ if not indexes: return # extract name, name are unique datas = self.model.getData() allNames = [] # remove duplicate index cleanIndexes = {} for index in indexes: if index.row() not in cleanIndexes: cleanIndexes[index.row()] = index #for cleanIndex in cleanIndexes.keys(): for cleanIndex in list(cleanIndexes.keys()): # for python3 support allNames.append( datas[cleanIndex]['key'] ) self.trace('Key to remove: %s' % allNames) for paramName in allNames: self.removeValue( paramName=paramName ) def removeValue(self, paramName): """ Remove one parameter according to the name passed on argument """ datas = self.model.getData() i = None for i in xrange(len(datas)): if datas[i]['key'] == paramName: break if i is not None: param = datas.pop( i ) del param self.model.reset() def delKeys(self): """ Clear all keys """ reply = QMessageBox.question(self, self.tr("Clear all keys"), self.tr("Are you sure ?"), QMessageBox.Yes | QMessageBox.No ) if reply == QMessageBox.Yes: data = self.model.getData() try: for i in xrange(len(data)): data.pop() except Exception as e: pass self.model.reset() self.delAllAction.setEnabled(False) def onPopupMenu(self, pos): """ Display menu on right click @param pos: @type pos: """ self.menu = QMenu(self.dictTable) index = self.dictTable.currentIndex() indexes = self.dictTable.selectedIndexes() if not indexes: self.menu.addAction( self.delAction ) self.menu.addAction( self.addAction ) self.menu.addSeparator() self.menu.addAction( self.delAllAction ) self.menu.addSeparator() else: self.menu.addAction( self.delAction ) self.menu.addAction( self.addAction ) self.menu.addSeparator() self.menu.addAction( self.delAllAction ) self.menu.addSeparator() self.menu.popup( self.mapToGlobal(pos) ) def loadData(self, data): """ Load data """ if isinstance(data, dict): data = [data] self.model.setDataModel( data )
class pagesPanel(QWidget): def __init__(self, parent=None): super(pagesPanel, self).__init__(parent) # The layout is very basic, the table with an Update button. mainLayout = QVBoxLayout() self.setLayout(mainLayout) hlayout = QHBoxLayout() self.updateButton = QPushButton("Update") self.insertText = QLineEdit() self.insertText.setFont(pqMsgs.getMonoFont()) self.insertButton = QPushButton("Insert") hlayout.addWidget(self.updateButton,0) hlayout.addWidget(self.insertText,1) # text gets all available room hlayout.addWidget(self.insertButton,0) mainLayout.addLayout(hlayout) self.view = QTableView() self.view.setCornerButtonEnabled(False) self.view.setWordWrap(False) self.view.setAlternatingRowColors(True) self.view.setSortingEnabled(False) self.c1Delegate = formatDelegate() self.view.setItemDelegateForColumn(1,self.c1Delegate) self.c2Delegate = actionDelegate() self.view.setItemDelegateForColumn(2,self.c2Delegate) self.c3Delegate = folioDelegate() self.view.setItemDelegateForColumn(3,self.c3Delegate) mainLayout.addWidget(self.view,1) # Set up the table model/view. self.model = myTableModel() self.view.setModel(self.model) # Connect the double-clicked signal of the view self.connect(self.view, SIGNAL("doubleClicked(QModelIndex)"), self.goToRow) # Connect the update button to the model's update method self.connect(self.updateButton, SIGNAL("clicked()"),self.model.updateFolios) # Connect the insert button to our insert method self.connect(self.insertButton, SIGNAL("clicked()"),self.insertMarkers) # This slot receives a double-click from the table view, # passing an index. If the click is in column 0, the scan number, # get the row; use it to get a text cursor from the page table # and make that the editor's cursor, thus moving to the top of that page. # Double-click on cols 1-3 initiates editing and maybe someday a # doubleclick on column 5 will do something with the proofer info. def goToRow(self,index): if index.column() == 0: tc = IMC.pageTable.getCursor(index.row()) IMC.editWidget.setTextCursor(tc) IMC.editWidget.setFocus(Qt.TabFocusReason) # This slot receives the main window's docWillChange signal. # It comes with a file path but we can ignore that. def docWillChange(self): self.model.beginResetModel() # Subroutine to reset the visual appearance of the table view, # invoked on table reset because on instantiation we have no table. def setUpTableView(self): # Header text is supplied by the table model headerData method # Here we are going to set the column widths of the first 4 # columns to a uniform 7 ens each based on the current font. # However, at least on Mac OS, the headers are rendered with a # much smaller font than the data, so we up it by 50%. hdr = self.view.horizontalHeader() pix = hdr.fontMetrics().width(QString("9999999")) hdr.resizeSection(0,pix) hdr.resizeSection(3,pix) pix += pix/2 hdr.resizeSection(1,pix) hdr.resizeSection(2,pix) self.view.resizeColumnToContents(4) # This slot receives the main window's docHasChanged signal. # Let the table view populate with all-new metadata (or empty # data if the command was File>New). def docHasChanged(self): self.model.endResetModel() self.setUpTableView() # On the Insert button being pressed, make some basic sanity checks # and get user go-ahead then insert the given text at the head of # every page. def insertMarkers(self): # Copy the text and if it is empty, complain and exit. qi = QString(self.insertText.text()) if qi.isEmpty() : pqMsgs.warningMsg("No insert text specified") return # See how many pages are involved: all the ones that aren't marked skip n = 0 for i in range(IMC.pageTable.size()): if IMC.pageTable.getAction(i) != IMC.FolioRuleSkip : n += 1 if n == 0 : # page table empty or all rows marked skip pqMsgs.warningMsg("No pages to give folios to") return m = "Insert this string at the top of {0} pages?".format(n) b = pqMsgs.okCancelMsg(QString(m),pqMsgs.trunc(qi,35)) if b : # Convert any '\n' in the text to the QT line delimiter char # we do this in the copy so the lineEdit text doesn't change qi.replace(QString(u'\\n'),QString(IMC.QtLineDelim)) # get a cursor on the edit document tc = QTextCursor(IMC.editWidget.textCursor()) tc.beginEditBlock() # start single undoable operation # Working from the end of the document backward, go to the # top of each page and insert the string for i in reversed( range( IMC.pageTable.size() ) ) : if IMC.pageTable.getAction(i) != IMC.FolioRuleSkip : # Note the page's start position and set our work cursor to it pos = IMC.pageTable.getCursor(i).position() tc.setPosition(pos) # Make a copy of the insert string replacing %f with this folio f = IMC.pageTable.getDisplay(i) qf = QString(qi) qf.replace(QString(u'%f'),f,Qt.CaseInsensitive) tc.insertText(qf) # The insertion goes in ahead of the saved cursor position so now # it points after the inserted string. Put it back where it was. IMC.pageTable.setPosition(i, pos) tc.endEditBlock() # wrap up the undo op
def set_dataset(self, data, tid=None): """Set the input dataset.""" if data is not None: if tid in self.inputs: # update existing input slot slot = self.inputs[tid] view = slot.view # reset the (header) view state. view.setModel(None) view.horizontalHeader().setSortIndicator(-1, Qt.AscendingOrder) else: view = QTableView() view.setSortingEnabled(True) view.setHorizontalScrollMode(QTableView.ScrollPerPixel) if self.select_rows: view.setSelectionBehavior(QTableView.SelectRows) header = view.horizontalHeader() header.setMovable(True) header.setClickable(True) header.setSortIndicatorShown(True) header.setSortIndicator(-1, Qt.AscendingOrder) # QHeaderView does not 'reset' the model sort column, # because there is no guaranty (requirement) that the # models understand the -1 sort column. def sort_reset(index, order): if view.model() is not None and index == -1: view.model().sort(index, order) header.sortIndicatorChanged.connect(sort_reset) view.dataset = data self.tabs.addTab(view, getattr(data, "name", "Data")) self._setup_table_view(view, data) slot = TableSlot(tid, data, table_summary(data), view) view._input_slot = slot self.inputs[tid] = slot self.tabs.setCurrentIndex(self.tabs.indexOf(view)) self.set_info(slot.summary) if isinstance(slot.summary.len, concurrent.futures.Future): def update(f): QMetaObject.invokeMethod(self, "_update_info", Qt.QueuedConnection) slot.summary.len.add_done_callback(update) elif tid in self.inputs: slot = self.inputs.pop(tid) view = slot.view view.hide() view.deleteLater() self.tabs.removeTab(self.tabs.indexOf(view)) current = self.tabs.currentWidget() if current is not None: self.set_info(current._input_slot.summary) self.tabs.tabBar().setVisible(self.tabs.count() > 1)
class FreezeTableWidget(QTableView): def __init__(self, parent=None): QTableView.__init__(self, parent) self.freezeNum = 0 def myInit(self, model, freezeNum): self.setModel(model) self.frozenTableView = QTableView(self) self.frozenTableView.setSortingEnabled(True) self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self.setSortingEnabled(True) self.setAlternatingRowColors(True) self.freezeNum = freezeNum self.init() self.connect(self.frozenTableView.horizontalHeader(), QtCore.SIGNAL("sortIndicatorChanged (int,Qt::SortOrder)"), self.fSortIndicatorChanged) self.connect(self.horizontalHeader(), QtCore.SIGNAL("sortIndicatorChanged (int,Qt::SortOrder)"), self.sortIndicatorChanged) self.connect(self.horizontalHeader(), QtCore.SIGNAL("sectionResized(int,int,int)"), self.updateSectionWidth) self.connect(self.verticalHeader(), QtCore.SIGNAL("sectionResized(int,int,int)"), self.updateSectionHeight) self.connect(self.frozenTableView.horizontalHeader(), QtCore.SIGNAL("sectionResized(int,int,int)"), self.a) self.connect(self.frozenTableView.verticalHeader(), QtCore.SIGNAL("sectionResized(int,int,int)"), self.b) self.connect(self.frozenTableView.verticalScrollBar(), QtCore.SIGNAL("valueChanged(int)"), self.verticalScrollBar().setValue) self.connect(self.verticalScrollBar(), QtCore.SIGNAL("valueChanged(int)"), self.frozenTableView.verticalScrollBar().setValue) def fSortIndicatorChanged(self, index, sortOrder): if index < self.freezeNum: self.frozenTableView.horizontalHeader().setSortIndicatorShown(True) self.horizontalHeader().setSortIndicatorShown(False) def sortIndicatorChanged(self, index, sortOrder): if index >= self.freezeNum: self.frozenTableView.horizontalHeader().setSortIndicatorShown(False) self.horizontalHeader().setSortIndicatorShown(True) def init(self): self.frozenTableView.setModel(self.model()); self.frozenTableView.setFocusPolicy(QtCore.Qt.NoFocus); self.frozenTableView.verticalHeader().hide(); #self.frozenTableView.horizontalHeader().setResizeMode(QtGui.QHeaderView.Fixed); self.viewport().stackUnder(self.frozenTableView); self.frozenTableView.setStyleSheet("QTableView { border: none;" "background-color: #8EDE21;" "selection-background-color: #999}"); self.frozenTableView.setSelectionModel(self.selectionModel()) self.frozenTableView.setSelectionMode(self.selectionMode()) self.frozenTableView.setSelectionBehavior(self.selectionBehavior()) for col in range(self.freezeNum, self.model().columnCount()): self.frozenTableView.setColumnHidden(col, True) for i in range(self.freezeNum): self.frozenTableView.setColumnWidth(self.freezeNum, self.columnWidth(self.freezeNum) ) self.frozenTableView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff); self.frozenTableView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff); self.frozenTableView.show(); self.updateFrozenTableGeometry(); self.setHorizontalScrollMode(self.ScrollPerPixel); self.setVerticalScrollMode(self.ScrollPerPixel); self.frozenTableView.setVerticalScrollMode(self.ScrollPerPixel) def a(self, logicalIndex, a, newSize): self.setColumnWidth(logicalIndex,newSize); self.updateFrozenTableGeometry() def b(self, logicalIndex, a, newSize): self.setRowHeight(logicalIndex, newSize) def updateSectionWidth(self, logicalIndex, a, newSize): #if logicalIndex==0 or logicalIndex == 1: self.frozenTableView.setColumnWidth(logicalIndex,newSize); self.updateFrozenTableGeometry() def updateSectionHeight(self, logicalIndex, a, newSize): self.frozenTableView.setRowHeight(logicalIndex, newSize); def resizeEvent(self, event): pass QTableView.resizeEvent(self, event); self.updateFrozenTableGeometry() def moveCursor(self, cursorAction, modifiers): pass current = QTableView.moveCursor(self, cursorAction, modifiers); if cursorAction == self.MoveLeft and current.column()>0 \ and self.visualRect(current).topLeft().x() < self.frozenTableView.columnWidth(0): newValue = self.horizontalScrollBar().value() + self.visualRect(current).topLeft().x() - self.frozenTableView.columnWidth(0) self.horizontalScrollBar().setValue(newValue) return current # def scrollTo(self, index, hint): # pass # #if(index.column()>0): # print 'here' #QTableView.scrollTo(self, index, hint) def updateFrozenTableGeometry(self): width = 0 for i in range(self.freezeNum): width += self.columnWidth(i) self.frozenTableView.setGeometry( self.verticalHeader().width()+self.frameWidth(), \ self.frameWidth(), width, self.viewport().height()+self.horizontalHeader().height())
class ClusterWidget(QSplitter): def __init__(self, peaks, parent=None): QSplitter.__init__(self, Qt.Vertical, parent) self.peaks = peaks self.choosenOne = [pe for pe in self.peaks if pe is not None][0] #self.peakModel = QStandardItemModel() self.identificationModel = QStandardItemModel() self.setupUi() self.setModel() self.connect(self.calcCorr, SIGNAL('pressed()'), self.setRankValue) #self.setRankValue() def setupUi(self): self.widget = MSView( MSQtCanvas(self.peaks, "peaks@%s" % str(self.peaks[0]), labels={ 'bottom': 'RT(s)', 'left': 'INTENSITY' }, flags='peak')) self.tableView = QTableView() self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.setSortingEnabled(True) self.corr = QLabel("Nan") self.calcCorr = QPushButton("r_coef:") #v = QVBoxLayout(self) self.addWidget(self.widget) self.wid = QWidget() vb = QVBoxLayout() vb.addWidget(self.calcCorr) vb.addWidget(self.corr) hb = QHBoxLayout(self.wid) #if self.choosenOne.formulas: hb.addWidget(self.tableView) #else: # hb.addWidget(QLabel("Identification not performed yet...")) hb.addLayout(vb) self.addWidget(self.wid) def setModel(self): from gui.MetBaseGui import MSStandardItem #we assume that the different peaks have the same identifiers #TODO: may have to merge several stuffs later if self.choosenOne.formulas: self.identificationModel.setHorizontalHeaderLabels( ["score", "formula", "diff mass", "names"]) for i, f in enumerate(self.choosenOne.formulas.iterkeys()): self.identificationModel.setItem( i, 0, MSStandardItem(str(self.choosenOne.formulas[f]["score"]))) self.identificationModel.setItem(i, 1, QStandardItem(str(f))) self.identificationModel.setItem( i, 2, MSStandardItem(str( self.choosenOne.formulas[f]["diffmass"]))) self.identificationModel.setItem( i, 3, QStandardItem(self.choosenOne.formulas[f]["names"])) if self.choosenOne.formulas[f]["names"] != 'Not Found': for j in xrange(4): self.identificationModel.item(i, j).setBackground( QBrush(Qt.green)) else: for j in xrange(4): self.identificationModel.item(i, j).setBackground( QBrush(Qt.red)) self.tableView.setModel(self.identificationModel) def setRankValue(self): #m = qApp.instance().model #m.pearsonIntraCalculation() #peaks =[] #for spl in m: # peaks+=[p.r_coef for p in spl.mappedPeaks if p.r_coef] #if not self.choosenOne.r_coef: self.choosenOne.pCalcBasedOnPeakShape() #from _bisect import bisect_left #x = bisect_left(sorted(peaks), self.choosenOne.r_coef) s = '<br><b>%f</b></br>' % np.round(self.choosenOne.r_coef, 4) #s+='<br><b>Rank: </b>%d</br>'%abs(len(peaks)-x) self.corr.setText(s)
class DlgCharting(QDialog): def __init__(self, parent, data): QDialog.__init__(self, parent) self.ui = Ui_ChartingBase() self.ui.setupUi(self) self.setWindowTitle("Charting Tool 2") # self.ui.btnNext.clicked.connect(self.btnNext_clicked) self.ui.btnPrevious.clicked.connect(self.btnPrevious_clicked) self.ui.btnExit.clicked.connect(self.btnExit_clicked) self.ui.txtText1.textChanged.connect(self.txtText1_textChanged) self.ui.txtText2.textChanged.connect(self.txtText2_textChanged) self.ui.txtText3.textChanged.connect(self.txtText3_textChanged) self.ui.txtText4.textChanged.connect(self.txtText4_textChanged) self.ui.txtText5.textChanged.connect(self.txtText5_textChanged) self.ui.txtText6.textChanged.connect(self.txtText6_textChanged) self.ui.txtText7.textChanged.connect(self.txtText7_textChanged) self.ui.txtText8.textChanged.connect(self.txtText8_textChanged) self.ui.txtText9.textChanged.connect(self.txtText9_textChanged) self.ui.txtText10.textChanged.connect(self.txtText10_textChanged) self.ui.txtText11.textChanged.connect(self.txtText11_textChanged) self.ui.txtText12.textChanged.connect(self.txtText12_textChanged) self.ui.txtText13.textChanged.connect(self.txtText13_textChanged) # self.btnNextAndbtnPreviewSetEnabled() self.setDataDict = None self.parentDlg = parent self.pw = None self.stdModel = None self.data = data self.renderFlag = False self.changedComposerMap = None self.tableChangedValue = None self.straightCount = self.data["StraightCount"] self.catOfAcftCount = self.data["CatOfAcftCount"][0] self.rejected.connect(self.dlgRejected) def dlgRejected(self): self.parentDlg.show() def refreshData(self, data): self.data = data def txtText1_textChanged(self): self.txt1.setText(self.ui.txtText1.text()) def txtText2_textChanged(self): self.txt2.setText(self.ui.txtText2.text()) def txtText3_textChanged(self): self.txt3.setText(self.ui.txtText3.text()) def txtText4_textChanged(self): self.txt4.setText(self.ui.txtText4.toPlainText()) def txtText5_textChanged(self): self.txt5.setText(self.ui.txtText5.toPlainText()) def txtText6_textChanged(self): self.txt6.setText(self.ui.txtText6.toPlainText()) def txtText7_textChanged(self): try: self.txt7.setText(self.ui.txtText7.toPlainText()) except: pass def txtText8_textChanged(self): self.txt8.setText(self.ui.txtText8.text()) def txtText9_textChanged(self): self.txt9.setText(self.ui.txtText9.text()) def txtText10_textChanged(self): self.txt10.setText(self.ui.txtText10.text()) def txtText11_textChanged(self): self.txt11.setText(self.ui.txtText11.text()) def txtText12_textChanged(self): self.txt12.setText(self.ui.txtText12.text()) def txtText13_textChanged(self): self.txt13.setText(self.ui.txtText13.text()) # def btnNextAndbtnPreviewSetEnabled(self): # if self.ui.stackedWidget.currentIndex() == 0: # self.ui.btnPrevious.setEnabled(False) # self.ui.frame_2.setVisible(False) # self.resize(100, 100) # # else: # self.ui.frame_2.setVisible(True) # self.ui.btnPrevious.setEnabled(True) # if self.ui.stackedWidget.currentIndex() == self.ui.stackedWidget.count() - 1: # self.ui.btnNext.setEnabled(False) # else: # self.ui.btnNext.setEnabled(True) def btnExit_clicked(self): # comp = QgsComposer(self, define._canvas) # comp.show() self.setDataDict = dict() for key, val in self.data.iteritems(): self.setDataDict.__setitem__(key, val) self.setDataDict.__setitem__("TextData", [ self.ui.txtText1.text(), self.ui.txtText2.text(), self.ui.txtText3.text(), self.ui.txtText4.toPlainText(), self.ui.txtText5.toPlainText(), self.ui.txtText6.toPlainText(), self.ui.txtText7.toPlainText(), self.ui.txtText8.text(), self.ui.txtText9.text(), self.ui.txtText10.text(), self.ui.txtText11.text(), self.ui.txtText12.text(), self.ui.txtText13.text() ]) # self.setDataDict.__setitem__("StraightCount", self.straightCount) # self.setDataDict.__setitem__("CatOfAcftCount", self.catOfAcftCount) comp = None if self.pw == None or not isinstance(self.pw, ComposerDlg): comp = self.composer(self.setDataDict) else: comp = self.composer(self.setDataDict, False) pwFlag = False if self.pw == None or not isinstance(self.pw, ComposerDlg): self.pw = ComposerDlg(self, comp, self.stdModel, self.setDataDict) pwFlag = True if not self.renderFlag: self.pw.show() if not pwFlag: self.pw.rePresent(comp, self.stdModel, self.setDataDict) self.renderFlag = False def showDlg(self): self.pw.hide() self.show() self.ui.txtText1.setText(self.txt1.text()) self.ui.txtText2.setText(self.txt2.text()) self.ui.txtText3.setText(self.txt3.text()) self.ui.txtText4.setText(self.txt4.text()) self.ui.txtText5.setText(self.txt5.text()) self.ui.txtText6.setText(self.txt6.text()) self.ui.txtText7.setText(self.txt7.text()) self.ui.txtText8.setText(self.txt8.text()) self.ui.txtText9.setText(self.txt9.text()) self.ui.txtText10.setText(self.txt10.text()) self.ui.txtText11.setText(self.txt11.text()) self.ui.txtText12.setText(self.txt12.text()) self.ui.txtText13.setText(self.txt13.text()) # def btnNext_clicked(self): # if self.ui.stackedWidget.currentIndex() + 1 < self.ui.stackedWidget.count(): # self.ui.stackedWidget.setCurrentIndex(self.ui.stackedWidget.currentIndex() + 1) # self.btnNextAndbtnPreviewSetEnabled() def btnPrevious_clicked(self): self.setVisible(False) self.parent().show() # if self.ui.stackedWidget.currentIndex() > 0: # self.ui.stackedWidget.setCurrentIndex(self.ui.stackedWidget.currentIndex() - 1) # self.btnNextAndbtnPreviewSetEnabled() def composer(self, setData, flag=True): paperWidth = setData["Width"] paperHeight = setData["Height"] mapRenderer = define._canvas.mapRenderer() # comp = None comp = QgsComposition(mapRenderer) comp.setPlotStyle(QgsComposition.Print) comp.setPaperSize(paperWidth, paperHeight) # rectangleAll = QgsComposerShape(comp) # rectangleAll.setItemPosition(3, 3, paperWidth - 3, paperHeight - 3) # rectangleAll.setShapeType(1) # comp.addItem(rectangleAll) self.txt1 = QgsComposerLabel(comp) self.txt1.setItemPosition(20, 20) self.txt1.setFrameEnabled(False) font = QFont("Arial", 10) self.txt1.setFont(font) self.txt1.setText(setData["TextData"][0]) self.txt1.adjustSizeToText() comp.addItem(self.txt1) self.txt2 = QgsComposerLabel(comp) self.txt2.setItemPosition(int(paperWidth / 2) + 10, 20) self.txt2.setFrameEnabled(False) font = QFont("Arial", 10) self.txt2.setFont(font) self.txt2.setText(setData["TextData"][1]) self.txt2.adjustSizeToText() comp.addItem(self.txt2) self.txt3 = QgsComposerLabel(comp) self.txt3.setItemPosition(paperWidth - 40, 20) self.txt3.setFrameEnabled(False) font = QFont("Arial", 10) self.txt3.setFont(font) self.txt3.setText(setData["TextData"][2]) self.txt3.adjustSizeToText() comp.addItem(self.txt3) w = int((paperWidth - 40) / 4) self.txt4 = QgsComposerLabel(comp) self.txt4.setItemPosition(20, 35) self.txt4.setFrameEnabled(False) font = QFont("Arial", 10) self.txt4.setFont(font) self.txt4.setText(setData["TextData"][3]) self.txt4.adjustSizeToText() comp.addItem(self.txt4) self.txt5 = QgsComposerLabel(comp) self.txt5.setItemPosition(20 + w, 35) self.txt5.setFrameEnabled(False) font = QFont("Arial", 10) self.txt5.setFont(font) self.txt5.setText(setData["TextData"][4]) self.txt5.adjustSizeToText() comp.addItem(self.txt5) self.txt6 = QgsComposerLabel(comp) self.txt6.setItemPosition(20 + w * 2, 35) self.txt6.setFrameEnabled(False) font = QFont("Arial", 10) self.txt6.setFont(font) self.txt6.setText(setData["TextData"][5]) self.txt6.adjustSizeToText() comp.addItem(self.txt6) self.txt7 = QgsComposerLabel(comp) self.txt7.setItemPosition(20 + w * 3, 35) self.txt7.setFrameEnabled(False) font = QFont("Arial", 10) self.txt7.setFont(font) self.txt7.setText(setData["TextData"][6]) self.txt7.adjustSizeToText() comp.addItem(self.txt7) # if flag: x, y = 20, 45 composerMap = QgsComposerMap(comp, x, y, paperWidth - 40, 150) # composerMap.setPreviewMode(QgsComposerMap.Render) # composerMap.setGridEnabled(False) #rect = composerMap.currentMapExtent () renderer = composerMap.mapRenderer() newExtent = renderer.extent() #Make sure the width/height ratio is the same as in current composer map extent. #This is to keep the map item frame and the page layout fixed currentMapExtent = composerMap.currentMapExtent() currentWidthHeightRatio = currentMapExtent.width( ) / currentMapExtent.height() newWidthHeightRatio = newExtent.width() / newExtent.height() if currentWidthHeightRatio < newWidthHeightRatio: #enlarge height of new extent, ensuring the map center stays the same newHeight = newExtent.width() / currentWidthHeightRatio deltaHeight = newHeight - newExtent.height() newExtent.setYMinimum(newExtent.yMinimum() - deltaHeight / 2) newExtent.setYMaximum(newExtent.yMaximum() + deltaHeight / 2) else: #enlarge width of new extent, ensuring the map center stays the same newWidth = currentWidthHeightRatio * newExtent.height() deltaWidth = newWidth - newExtent.width() newExtent.setXMinimum(newExtent.xMinimum() - deltaWidth / 2) newExtent.setXMaximum(newExtent.xMaximum() + deltaWidth / 2) composerMap.beginCommand("Map extent changed") composerMap.setNewExtent(newExtent) composerMap.endCommand() # composerMap.setNewScale(3500) composerMap.setFrameEnabled(True) composerMap.setFrameOutlineWidth(1.0) composerMap.setPreviewMode(QgsComposerMap.Render) composerMap.updateCachedImage() composerMap.setGridEnabled(True) composerMap.setGridPenColor(QColor(255, 255, 255, 0)) composerMap.setGridPenWidth(0.0) #composerMap.setGridStyle(QgsComposerMap.FrameAnnotationsOnly) composerMap.setGridIntervalX(1.0) composerMap.setGridIntervalY(1.0) # mySymbol1 = composerMap.gridLineSymbol () # mySymbol1.setAlpha(0) #composerMap.setGridLineSymbol(mySymbol1) composerMap.setShowGridAnnotation(True) composerMap.setGridAnnotationFormat(1) composerMap.setGridAnnotationPrecision(0) composerMap.setGridAnnotationDirection(1, 0) composerMap.setGridAnnotationDirection(1, 1) comp.addItem(composerMap) w = int((paperWidth - 40) / 3) self.txt8 = QgsComposerLabel(comp) self.txt8.setItemPosition(20, 225) self.txt8.setFrameEnabled(False) font = QFont("Arial", 10) self.txt8.setFont(font) self.txt8.setText(setData["TextData"][7]) self.txt8.adjustSizeToText() comp.addItem(self.txt8) self.txt9 = QgsComposerLabel(comp) self.txt9.setItemPosition(20 + w, 225) self.txt9.setFrameEnabled(False) font = QFont("Arial", 10) self.txt9.setFont(font) self.txt9.setText(setData["TextData"][8]) self.txt9.adjustSizeToText() comp.addItem(self.txt9) self.txt10 = QgsComposerLabel(comp) self.txt10.setItemPosition(20 + w * 2, 225) self.txt10.setFrameEnabled(False) font = QFont("Arial", 10) self.txt10.setFont(font) self.txt10.setText(setData["TextData"][9]) self.txt10.adjustSizeToText() comp.addItem(self.txt10) # profileRect = QgsComposerPicture(comp) # profileRect.setItemPosition(20, 200, paperWidth - 40, 50) # comp.addItem(profileRect) self.txt11 = QgsComposerLabel(comp) self.txt11.setItemPosition(20, paperHeight - 30) self.txt11.setFrameEnabled(False) font = QFont("Arial", 10) self.txt11.setFont(font) self.txt11.setText(setData["TextData"][10]) self.txt11.adjustSizeToText() comp.addItem(self.txt11) self.txt12 = QgsComposerLabel(comp) self.txt12.setItemPosition(20 + w, paperHeight - 30) self.txt12.setFrameEnabled(False) font = QFont("Arial", 10) self.txt12.setFont(font) self.txt12.setText(setData["TextData"][11]) self.txt12.adjustSizeToText() comp.addItem(self.txt12) self.txt13 = QgsComposerLabel(comp) self.txt13.setItemPosition(20 + w * 2, paperHeight - 30) self.txt13.setFrameEnabled(False) font = QFont("Arial", 10) self.txt13.setFont(font) self.txt13.setText(setData["TextData"][12]) self.txt13.adjustSizeToText() comp.addItem(self.txt13) # gpw = QGraphicsProxyWidget() self.tblView = QTableView() tableHeight = None tableWidth = None if self.tableChangedValue == None: self.tblView.setFixedWidth(paperWidth - 40) tableHeight = 50 tableWidth = paperWidth - 40 self.tblView.setFixedHeight(tableHeight) else: self.tblView.setFixedWidth(self.tableChangedValue["Width"]) self.tblView.setFixedHeight(self.tableChangedValue["Height"]) tableHeight = self.tableChangedValue["Height"] tableWidth = self.tableChangedValue["Width"] self.tblView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.tblView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) hHeder = self.tblView.horizontalHeader() hHeder.setVisible(False) vHeder = self.tblView.verticalHeader() vHeder.setVisible(False) # if flag: self.stdModel = QStandardItemModel() self.data.__setitem__("TableWidth", tableWidth) self.data.__setitem__("TableHeight", tableHeight) self.setTableView(self.tblView, self.stdModel, self.data) self.calcALT() self.calcTimeRate() self.gpw = QGraphicsProxyWidget() self.gpw.setWidget(self.tblView) # gpw.setWidget(tblView) if self.tableChangedValue == None: self.gpw.setPos(20, 210) font = QFont() font.setPixelSize(2) self.gpw.setFont(font) else: self.gpw.setPos(self.tableChangedValue["X"], self.tableChangedValue["Y"]) font = QFont() font.setPixelSize(self.tableChangedValue["FontSize"]) self.gpw.setFont(font) # tblView.setFrameRect(QRect(20, 210, paperWidth - 40, 50)) comp.addItem(self.gpw) self.connect(self.stdModel, SIGNAL("itemChanged(QStandardItem *)"), self.stdModel_itemChanged) return comp def setTableView(self, tblView, stdModel, data): for i in range(7): for j in range(12 + data["CatOfAcftCount"][0]): item = QStandardItem("") item.setEditable(True) item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(i, j, item) item = QStandardItem("O C A ( H )") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(0, 0, item) item = QStandardItem("C a t of A C F T") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 0, item) item = QStandardItem("S t r a i g h t-I n A p p r o a c h") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(2, 0, item) if data["Template"][0] >= 0 and data["Template"][0] <= 4: item = QStandardItem("C i r c l i n g") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(4, 0, item) item = QStandardItem( "F i n a l A p p r o a c h L O C D i s t a n c e F A F-M A P t" ) item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(0, data["CatOfAcftCount"][0] + 3, item) else: item = QStandardItem("F i n a l A p p r o a c h F A F-M A P t") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(0, data["CatOfAcftCount"][0] + 3, item) if data["Template"][0] == 5: item = QStandardItem("LPV") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(2, 0, item) item = QStandardItem("LNAV / VNAV") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(3, 0, item) item = QStandardItem("LNAV") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(4, 0, item) item = QStandardItem("C i r c l i n g") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(5, 0, item) elif data["Template"][0] == 6: item = QStandardItem("LNAV / VNAV") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(2, 0, item) item = QStandardItem("LNAV") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(3, 0, item) item = QStandardItem("C i r c l i n g") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(4, 0, item) elif data["Template"][0] == 7: item = QStandardItem("LPV") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(2, 0, item) item = QStandardItem("LNAV") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(3, 0, item) item = QStandardItem("C i r c l i n g") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(4, 0, item) elif data["Template"][0] == 8: item = QStandardItem("LNAV") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(2, 0, item) item = QStandardItem("C i r c l i n g") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(3, 0, item) elif data["Template"][0] == 9: item = QStandardItem("RNP 0.3") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(2, 0, item) item = QStandardItem("C i r c l i n g") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(3, 0, item) if data["CatOfAcftCount"][0] == 1: item = QStandardItem("A") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 3, item) elif data["CatOfAcftCount"][0] == 2: item = QStandardItem("A") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 3, item) item = QStandardItem("B") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 4, item) elif data["CatOfAcftCount"][0] == 3: item = QStandardItem("A") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 3, item) item = QStandardItem("B") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 4, item) item = QStandardItem("C") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 5, item) elif data["CatOfAcftCount"][0] == 4: item = QStandardItem("A") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 3, item) item = QStandardItem("B") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 4, item) item = QStandardItem("C") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 5, item) item = QStandardItem("D") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 6, item) elif data["CatOfAcftCount"][0] == 5: if data["CatOfAcftCount"][1] == 4: item = QStandardItem("A") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 3, item) item = QStandardItem("B") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 4, item) item = QStandardItem("C") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 5, item) item = QStandardItem("D") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 6, item) item = QStandardItem("DL") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 7, item) else: item = QStandardItem("A") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 3, item) item = QStandardItem("B") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 4, item) item = QStandardItem("C") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 5, item) item = QStandardItem("D") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 6, item) item = QStandardItem("E") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 7, item) elif data["CatOfAcftCount"][0] == 6: item = QStandardItem("A") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 3, item) item = QStandardItem("B") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 4, item) item = QStandardItem("C") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 5, item) item = QStandardItem("D") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 6, item) item = QStandardItem("DL") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 7, item) item = QStandardItem("E") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, 8, item) # item = QStandardItem("DME MX NM") # item.setTextAlignment(Qt.AlignCenter) # stdModel.setItem(1, 6, item) item = QStandardItem("DME SSA") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, data["CatOfAcftCount"][0] + 3, item) item = QStandardItem("6") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, data["CatOfAcftCount"][0] + 5, item) item = QStandardItem("5") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, data["CatOfAcftCount"][0] + 6, item) item = QStandardItem("4") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, data["CatOfAcftCount"][0] + 7, item) item = QStandardItem("3") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, data["CatOfAcftCount"][0] + 8, item) item = QStandardItem("2") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, data["CatOfAcftCount"][0] + 9, item) item = QStandardItem("1") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(1, data["CatOfAcftCount"][0] + 10, item) item = QStandardItem("A L T(HGT)") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(2, data["CatOfAcftCount"][0] + 3, item) item = QStandardItem("G S") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(3, data["CatOfAcftCount"][0] + 3, item) item = QStandardItem("kt") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(3, data["CatOfAcftCount"][0] + 5, item) item = QStandardItem("80") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(3, data["CatOfAcftCount"][0] + 6, item) item = QStandardItem("100") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(3, data["CatOfAcftCount"][0] + 7, item) item = QStandardItem("120") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(3, data["CatOfAcftCount"][0] + 8, item) item = QStandardItem("140") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(3, data["CatOfAcftCount"][0] + 9, item) item = QStandardItem("160") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(3, data["CatOfAcftCount"][0] + 10, item) item = QStandardItem("180") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(3, data["CatOfAcftCount"][0] + 11, item) item = QStandardItem("T i me") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(4, data["CatOfAcftCount"][0] + 3, item) item = QStandardItem("mi n:s") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(4, data["CatOfAcftCount"][0] + 5, item) item = QStandardItem("Rate Of D e s c e n t") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(5, data["CatOfAcftCount"][0] + 3, item) item = QStandardItem("ft/mi n") item.setTextAlignment(Qt.AlignCenter) stdModel.setItem(5, data["CatOfAcftCount"][0] + 5, item) tblView.setModel(stdModel) for i in range(7): tblView.setRowHeight(i, int(data["TableHeight"] / 7)) for j in range(12 + data["CatOfAcftCount"][0]): tblView.setColumnWidth( j, int(data["TableWidth"] / float(12 + data["CatOfAcftCount"][0]))) # tblView.setColumnWidth(0, 25) # tblView.setColumnWidth(6, 20) tblView.setSpan(0, 0, 1, data["CatOfAcftCount"][0] + 3) tblView.setSpan(1, 0, 1, 3) if data["Template"][0] >= 0 and data["Template"][0] <= 4: tblView.setSpan(2, 0, 1, 3) tblView.setSpan(2, 3, 1, data["CatOfAcftCount"][0]) tblView.setSpan(3, 0, 1, data["CatOfAcftCount"][0] + 3) tblView.setSpan(4, 0, 1, 3) tblView.setSpan(5, 0, 1, 3) tblView.setSpan(6, 0, 1, 3) else: tblView.setSpan(2, 0, 1, 3) tblView.setSpan(3, 0, 1, 3) tblView.setSpan(4, 0, 1, 3) tblView.setSpan(5, 0, 1, 3) tblView.setSpan(6, 0, 1, 3) # tblView.setSpan(data["StraightCount"] + 2, 0, 1, 3) tblView.setSpan(0, data["CatOfAcftCount"][0] + 3, 1, 9) # tblView.setSpan(1, data["CatOfAcftCount"][0] + 4, 1, 5) # tblView.setSpan(1, data["CatOfAcftCount"][0] + 9, 1, 3) # tblView.setSpan(2, data["CatOfAcftCount"][0] + 5, 1, 4) # tblView.setSpan(2, data["CatOfAcftCount"][0] + 9, 1, 3) tblView.setSpan(1, data["CatOfAcftCount"][0] + 3, 1, 2) tblView.setSpan(2, data["CatOfAcftCount"][0] + 3, 1, 2) tblView.setSpan(3, data["CatOfAcftCount"][0] + 3, 1, 2) tblView.setSpan(4, data["CatOfAcftCount"][0] + 3, 1, 2) tblView.setSpan(5, data["CatOfAcftCount"][0] + 3, 1, 2) tblView.setSpan(6, data["CatOfAcftCount"][0] + 3, 1, 2) def stdModel_itemChanged(self, item): if item.row() != 1 and item.row() != 3: return self.calcTimeRate() self.calcALT() def calcALT(self): thrAlt = Unit.ConvertFeetToMeter(self.data["ThrAltitude"]) rdhAlt = Unit.ConvertFeetToMeter(self.data["RDHAltitude"]) gradient = self.data["DescentGradient"] dx = self.data["dX"] for i in range(7): item = self.stdModel.item(1, self.data["CatOfAcftCount"][0] + 5 + i) val = 0.0 try: val = float(item.text()) except: continue dist = val * 1852 valueHgt = Unit.ConvertFeetToMeter( (dist - dx) * math.tan(Unit.ConvertDegToRad(gradient))) valueAlt = valueHgt + thrAlt + rdhAlt if valueAlt > int(valueAlt): valueAlt = int(valueAlt) + 1 if valueHgt > int(valueHgt): valueHgt = int(valueHgt) + 1 itemTemp = QStandardItem( str(valueAlt) + "\n(" + str(valueHgt) + ")") itemTemp.setTextAlignment(Qt.AlignCenter) self.stdModel.setItem(2, self.data["CatOfAcftCount"][0] + 5 + i, itemTemp) def calcTimeRate(self): for i in range(6): item = self.stdModel.item(3, self.data["CatOfAcftCount"][0] + 6 + i) val = 0.0 try: val = float(item.text()) except: continue time = (3600 * self.data["Distance"]) / val minute = int(time / 60) second = int(time % 60) timeStr = str(minute) + " : " + str(second) if second == 0: timeStr = str(minute) + " : " + "00" elif second < 10: timeStr = str(minute) + " : 0" + str(second) itemTemp = QStandardItem(timeStr) itemTemp.setTextAlignment(Qt.AlignCenter) self.stdModel.setItem(4, self.data["CatOfAcftCount"][0] + 6 + i, itemTemp) rate = int( (val * 6076.1 * (AngleGradientSlope(self.data["DescentGradient"]).Percent / float(100))) / float(60)) itemTemp = QStandardItem(str(rate)) itemTemp.setTextAlignment(Qt.AlignCenter) self.stdModel.setItem(5, self.data["CatOfAcftCount"][0] + 6 + i, itemTemp)
class DlgSelectInvoice( QDialog ): def __init__( self, parent = None ): super( DlgSelectInvoice, self ).__init__( parent ) self.billsmodel = QSqlQueryModel() query = """ SELECT * FROM ( SELECT factura.iddocumento, CONCAT_WS(' ', tdc.descripcion, factura.ndocimpreso) AS 'Numero de Factura', factura.fechacreacion AS 'Fecha', p.nombre AS 'Cliente', -SUM(axd.unidades) - IFNULL(( SELECT SUM(axddev.unidades) FROM documentos devoluciones JOIN docpadrehijos dpddev ON devoluciones.iddocumento = dpddev.idhijo JOIN articulosxdocumento axddev ON axddev.iddocumento = devoluciones.iddocumento WHERE devoluciones.idtipodoc = %d AND dpddev.idpadre = factura.iddocumento GROUP BY dpddev.idpadre ),0) as unittotal, p.idpersona, ca.valorcosto, ca.idcostoagregado, tc.tasa, tc.idtc, b.nombrebodega AS 'Bodega', b.idbodega FROM documentos factura JOIN bodegas b ON factura.idbodega = b.idbodega JOIN tiposdoc tdc ON tdc.idtipodoc = factura.idtipodoc JOIN articulosxdocumento axd ON axd.iddocumento = factura.iddocumento AND factura.idtipodoc = %d JOIN tiposcambio tc ON tc.idtc = factura.idtipocambio JOIN personasxdocumento pxd ON pxd.iddocumento = factura.iddocumento JOIN personas p ON pxd.idpersona = p.idpersona AND p.tipopersona=%d LEFT JOIN costosxdocumento cxd ON cxd.iddocumento = factura.iddocumento LEFT JOIN costosagregados ca ON cxd.idcostoagregado = ca.idcostoagregado JOIN ( SELECT dpdk.idpadre FROM documentos kardex JOIN docpadrehijos dpdk ON kardex.iddocumento = dpdk.idhijo WHERE kardex.idtipodoc = %d ) as kardex ON kardex.idpadre = factura.iddocumento GROUP BY factura.iddocumento ) as tbl WHERE unittotal > 0 """ % ( constantes.IDNC, constantes.IDFACTURA, constantes.CLIENTE, constantes.IDKARDEX ) self.billsmodel.setQuery( query ) self.setWindowTitle( "Seleccione la factura para la devolucion" ) self.filtermodel = QSortFilterProxyModel() self.filtermodel.setSourceModel( self.billsmodel ) self.filtermodel.setFilterCaseSensitivity( Qt.CaseInsensitive ) self.filtermodel.setFilterKeyColumn( -1 ) iddoc, _ndocimpreso, _fechacreacion, _nombre, total, idpersona, valorcosto, idcosto, tasacambio, idcambio, _nombrebodega, idbodega = range( 12 ) self.tblBills = QTableView() self.tblBills.setSelectionMode( QAbstractItemView.SingleSelection ) self.tblBills.setSelectionBehavior( QAbstractItemView.SelectRows ) self.tblBills.selectRow( 0 ) self.tblBills.setModel( self.filtermodel ) self.tblBills.setColumnHidden( iddoc, True ) self.tblBills.setColumnHidden( idpersona, True ) self.tblBills.setColumnHidden( total, True ) self.tblBills.setColumnHidden( valorcosto, True ) self.tblBills.setColumnHidden( idcosto, True ) self.tblBills.setColumnHidden( idcambio, True ) self.tblBills.setColumnHidden( tasacambio, True ) self.tblBills.setColumnHidden( idbodega, True ) self.tblBills.horizontalHeader().setStretchLastSection( True ) self.tblBills.resizeColumnsToContents() buttonbox = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel ) self.txtSearch = QLineEdit() formlayout = QFormLayout() formlayout.addRow( "&Buscar", self.txtSearch ) layout = QVBoxLayout() layout.addWidget( self.tblBills ) layout.addLayout( formlayout ) layout.addWidget( buttonbox ) self.setLayout( layout ) self.setMinimumWidth( 400 ) buttonbox.accepted.connect( self.accept ) buttonbox.rejected.connect( self.reject ) self.txtSearch.textChanged[unicode].connect( self.updateFilter ) #FIXME: Que pasa cuando no hay facturas? # def exec_( self ): # if self.billsmodel.rowCount() == 0: # QMessageBox.critical( None, # self.trUtf8( "Llantera Esquipulas: Inventario" ), # self.trUtf8( """No hay facturas a las cuales hacer devoluciones""" ), # QMessageBox.StandardButtons( \ # QMessageBox.Ok ) ) # self.reject() # else: # QDialog.exec_( self ) def updateFilter( self, str ): self.filtermodel.setFilterWildcard( str )
class GmApp(QMainWindow): def __init__(self): super(QMainWindow, self).__init__() self.setWindowTitle("GuloMail by GulonSoft") self.setWindowIcon(QIcon("g-square.png")) self.createActions() self.createStatusBar() self.createMenus() self.createToolbars() self.createWidgets() self.createLayouts() def createActions(self): self.newAction = QAction("&New", self, shortcut=QKeySequence.New, statusTip="New") self.sendReceiveAction = QAction("Send / &Receive", self, shortcut="F9", statusTip="Send / Receive") self.printAction = QAction("&Print...", self, shortcut="Ctrl+P", statusTip="Print") self.quitAction = QAction("&Quit", self, shortcut="Ctrl+Q", statusTip="Quit", triggered=self.close) self.copyAction = QAction("&Copy", self, statusTip="Copy", shortcut=QKeySequence.Copy) self.deleteAction = QAction("&Delete", self, statusTip="Delete Message") self.nextAction = QAction("Next &Unread Message", self, shortcut="Ctrl+]", statusTip="Next unread message") self.previousAction = QAction("P&revious Unread Message", self, shortcut="Ctrl+[", statusTip="Previous unread message") self.replyAction = QAction("&Reply", self, shortcut="Ctrl+R", statusTip="Reply to sender", triggered=self.reply) self.replyToAllAction = QAction("Reply to &All", self, shortcut="Ctrl+Shift+R", statusTip="Reply to all", triggered=self.replyToAll) self.forwardAction = QAction("&Forward", self, shortcut="Ctrl+F", statusTip="Forward") self.junkAction = QAction("Junk", self, shortcut="Ctrl+J", statusTip="Mark as Junk") self.notJunkAction = QAction("Not junk", self, shortcut="Shift+Ctrl+J", statusTip="Mark as Not Junk") self.contentsAction = QAction("&Contents", self, statusTip="Help Contents", shortcut="F1", triggered=self.helpContents) self.aboutAction = QAction("&About", self, statusTip="About GuloMail", triggered=self.about) self.cancelAction = QAction("&Cancel", self, statusTip="Cancel") def createStatusBar(self): self.statusBar() def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAction) self.fileMenu.addAction(self.sendReceiveAction) self.fileMenu.addAction(self.printAction) self.fileMenu.addAction(self.quitAction) self.editMenu = self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.copyAction) self.editMenu.addAction(self.deleteAction) self.viewMenu = self.menuBar().addMenu("&View") self.folderMenu = self.menuBar().addMenu("F&older") self.messageMenu = self.menuBar().addMenu("&Message") self.goToMenu = self.messageMenu.addMenu("&Go To") self.goToMenu.addAction(self.nextAction) self.goToMenu.addAction(self.previousAction) self.messageMenu.addAction(self.replyAction) self.messageMenu.addAction(self.replyToAllAction) self.messageMenu.addAction(self.forwardAction) self.markAsMenu = self.messageMenu.addMenu("Mar&k as...") self.markAsMenu.addAction(self.junkAction) self.markAsMenu.addAction(self.notJunkAction) self.searchMenu = self.menuBar().addMenu("&Search") self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.contentsAction) self.helpMenu.addAction(self.aboutAction) def createToolbars(self): self.toolbar = self.addToolBar('Main Toolbar') self.toolbar.setMovable(False) self.toolbar.addAction(self.newAction) self.toolbar.addSeparator() self.toolbar.addAction(self.sendReceiveAction) self.toolbar.addSeparator() self.toolbar.addAction(self.replyAction) self.toolbar.addAction(self.replyToAllAction) self.toolbar.addAction(self.forwardAction) self.toolbar.addSeparator() self.toolbar.addAction(self.printAction) self.toolbar.addAction(self.deleteAction) self.toolbar.addAction(self.junkAction) self.toolbar.addAction(self.notJunkAction) self.toolbar.addAction(self.cancelAction) self.toolbar.addSeparator() self.toolbar.addAction(self.previousAction) self.toolbar.addAction(self.nextAction) def createWidgets(self): ## Message Table self.table = QTableView() self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.setGridStyle(Qt.NoPen) self.model = QStandardItemModel(8, 3, self) self.model.setHeaderData(0, Qt.Horizontal, "From") self.model.setHeaderData(1, Qt.Horizontal, "Subject") self.model.setHeaderData(2, Qt.Horizontal, "Received") self.table.setModel(self.model) self.selectionModel = QItemSelectionModel(self.model) self.selectionModel.SelectionFlag = 0x0020 self.table.setSelectionModel(self.selectionModel) self.table.horizontalHeader().setStretchLastSection(True) self.table.verticalHeader().setVisible(False) self.table.setSortingEnabled(True) self.table.setAlternatingRowColors(True) ## Folder Tree View self.folderTree = QTreeWidget() self.folderTree.setColumnCount(1) self.folderTree.setHeaderLabel(QString('Folders')) self.treeItem = QTreeWidgetItem() self.treeItem.setText(0, 'Folders') self.inbox = QTreeWidgetItem() self.inbox.setText(0, 'Inbox') self.deletedItems = QTreeWidgetItem() self.deletedItems.setText(0, 'Deleted Items') self.drafts = QTreeWidgetItem() self.drafts.setText(0, 'Drafts') self.junk = QTreeWidgetItem() self.junk.setText(0, 'Junk') self.outbox = QTreeWidgetItem() self.outbox.setText(0, 'Outbox') self.sent = QTreeWidgetItem() self.sent.setText(0, 'Sent') self.treeItem.addChild(self.inbox) self.treeItem.addChild(self.deletedItems) self.treeItem.addChild(self.drafts) self.treeItem.addChild(self.junk) self.treeItem.addChild(self.outbox) self.treeItem.addChild(self.sent) self.folderTree.addTopLevelItem(self.treeItem) self.folderTree.expandAll() self.folderTree.setAnimated(True) self.folderTree.setMaximumWidth(150) ## Temp. placeholders self.textEdit = QTextEdit() self.textEdit2 = QTextEdit() def createLayouts(self): self.mainSplitter = QSplitter() self.setCentralWidget(self.mainSplitter) self.mainSplitter.addWidget(self.folderTree) self.messageSplitter = QSplitter(Qt.Vertical) self.messageSplitter.addWidget(self.table) self.messageSplitter.addWidget(self.textEdit2) self.mainSplitter.addWidget(self.messageSplitter) def helpContents(self): print "Help" def reply(self): print "Reply" def replyToAll(self): print "Reply To All" def about(self): text = QString("GuloMail v0.1\n\n") text.append( "GuloMail is a freeware email client written in Python using PyQt4 (Python bindings for Nokia's Qt)\n\n" ) text.append(QChar(0x00A9)) text.append("GulonSoft 2010\nhttp://www.gulon.co.uk/") QMessageBox.about(self, "About GuloMail", text)