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)
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()
class MobileWidget(QWidget): """ Mobile widget """ RefreshScreen = pyqtSignal() RefreshAutomatic = pyqtSignal(bool) TapOn = pyqtSignal(int, int) def __init__(self, parent=None): """ Constructor """ super(MobileWidget, self).__init__(parent) self.origWidth = 0 self.origHeight = 0 self.imagePath = None self.createActions() self.createWidget() self.createToolbar() self.center() def createActions(self): """ Create qt actions """ self.refreshAction = QtHelper.createAction(self, self.tr("&Refresh"), self.refreshScreen, icon=None) self.refreshAction.setEnabled(False) self.copyAction = QtHelper.createAction(self, self.tr("&Copy"), self.copyItem, icon=None) def createWidget(self): """ Create qt widget """ self.screenResolutionLabel = QLabel(self) self.screenTapLabel = QLabel(self) mobileLayout = QVBoxLayout() self.mobileDockToolbar = QToolBar(self) self.mobileDockToolbar.setStyleSheet("QToolBar { border: 0px }") self.mobileDockToolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.mobileImageLabel = QLabel(self) self.mobileImageLabel.setMouseTracking(True) self.mobileImageLabel.installEventFilter(self) self.mobileImageLabel.setScaledContents(True) self.mobileImageLabel.mousePressEvent = self.pixelSelect self.refreshCheckbox = QCheckBox("Automatic Refresh", self) self.refreshCheckbox.setEnabled(False) self.refreshCheckbox.stateChanged.connect(self.onRefreshChanged) self.clickCheckbox = QCheckBox("Enable Tap", self) self.clickCheckbox.setEnabled(False) self.model = DomModel(QDomDocument(), self) self.mobileTreeView = QTreeView(self) self.mobileTreeView.setMinimumWidth(300) self.mobileTreeView.setModel(self.model) self.mobileTreeView.clicked.connect(self.onTreeViewClicked) header = ["Attribute", "Value"] self.tableModel = MyTableModel(self, [], header) self.mobileTableView = QTableView(self) self.mobileTableView.setSelectionMode( QAbstractItemView.SingleSelection) self.mobileTableView.setModel(self.tableModel) self.mobileTableView.setContextMenuPolicy(Qt.CustomContextMenu) self.mobileTableView.customContextMenuRequested.connect( self.onContextMenuEvent) self.mobileTableView.setMinimumWidth(300) mobileViewLayout = QHBoxLayout() mobileViewLayout.addWidget(self.mobileImageLabel) mobileViewLayout.addWidget(self.mobileTreeView) mobileViewLayout.addWidget(self.mobileTableView) mobileLayout.addWidget(self.mobileDockToolbar) mobileLayout.addLayout(mobileViewLayout) self.setLayout(mobileLayout) def createToolbar(self): """ Create qt toolbar """ self.mobileDockToolbar.setObjectName("Toolbar") self.mobileDockToolbar.addWidget(self.refreshCheckbox) self.mobileDockToolbar.addWidget(self.clickCheckbox) self.mobileDockToolbar.addSeparator() self.mobileDockToolbar.addAction(self.refreshAction) self.mobileDockToolbar.addSeparator() self.mobileDockToolbar.addWidget(self.screenResolutionLabel) self.mobileDockToolbar.addSeparator() self.mobileDockToolbar.addWidget(self.screenTapLabel) self.mobileDockToolbar.addSeparator() self.mobileDockToolbar.setIconSize(QSize(16, 16)) def center(self): """ Center the dialog """ qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def eventFilter(self, srcEvent, event): """ On event filtering """ if srcEvent == self.mobileImageLabel: if event.type() == QEvent.MouseMove: x = event.pos().x() y = event.pos().y() pixmap = self.mobileImageLabel.pixmap() if pixmap is not None: x_scaled = int((self.origWidth * x) / pixmap.width()) y_scaled = int((self.origHeight * y) / pixmap.height()) self.mobileImageLabel.setToolTip("%sx%s" % (x_scaled, y_scaled)) return False def onContextMenuEvent(self, event): """ On context menu event """ menu = QMenu(self) menu.addAction(self.copyAction) menu.popup(QCursor.pos()) def copyItem(self): """ Copy the item """ indexes = self.mobileTableView.selectedIndexes() if len(indexes): data = self.tableModel.mylist[indexes[0].row()][ indexes[0].column()] clipboard = QApplication.clipboard() clipboard.setText(data) def onTreeViewClicked(self, qindex): """ On click in the treeview """ item = qindex.internalPointer() attributes = [] node = item.node() attributeMap = node.attributes() nodeName = node.nodeName() bounds_str = None for i in range(0, attributeMap.count()): attribute = attributeMap.item(i) attributes.append((attribute.nodeName(), attribute.nodeValue())) if attribute.nodeName() == 'bounds': bounds_str = attribute.nodeValue() self.tableModel.mylist = attributes if sys.version_info > (3, ): self.tableModel.beginResetModel() self.tableModel.endResetModel() else: self.tableModel.reset() self.mobileTableView.resizeColumnsToContents() self.mobileTableView.resizeRowsToContents() # redraw image with rectangle if bounds_str is not None: xy = bounds_str.split('][')[0].split('[')[1] wh = bounds_str.split('][')[1].split(']')[0] x, y = xy.split(',') w, h = wh.split(',') # get label size pixmap = self.mobileImageLabel.pixmap() xlabel = pixmap.width() ylabel = pixmap.height() # resize the rectangle y_scaled = (pixmap.height() * int(y)) / self.origHeight x_scaled = (pixmap.width() * int(x)) / self.origWidth h_scaled = (pixmap.height() * (int(h) - int(y))) / self.origHeight w_scaled = (pixmap.width() * (int(w) - int(x))) / self.origWidth # finally reload self.reloadScreen(x=int(x_scaled), y=int(y_scaled), w=int(w_scaled), h=int(h_scaled)) def onDeviceReady(self): """ On device ready """ self.refreshAction.setEnabled(True) self.refreshCheckbox.setEnabled(True) self.clickCheckbox.setEnabled(True) def refreshScreen(self): """ Refresh the screen """ self.RefreshScreen.emit() def onRefreshChanged(self, state): """ On refresh changed """ if state == Qt.Checked: self.RefreshAutomatic.emit(True) else: self.RefreshAutomatic.emit(False) def pixelSelect(self, event): """ Select pixel to click """ position = QPoint(event.pos().x(), event.pos().y()) x = event.pos().x() y = event.pos().y() pixmap = self.mobileImageLabel.pixmap() x_scaled = int((self.origWidth * x) / pixmap.width()) y_scaled = int((self.origHeight * y) / pixmap.height()) self.screenTapLabel.setText("Tap on (%s,%s)" % (x_scaled, y_scaled)) if self.clickCheckbox.isChecked(): self.TapOn.emit(x_scaled, y_scaled) def drawRectangle(self, x=0, y=0, w=0, h=0): """ Draw a rectangle """ self.mobileImageLabel.update() pixmap = self.mobileImageLabel.pixmap() if pixmap is not None: p = QPainter(pixmap) pen = QPen(Qt.red, 2, Qt.SolidLine) p.setPen(pen) p.drawRect(x, y, w, h) p.end() def reloadScreen(self, x, y, w, h): """ Reload the screen """ if self.imagePath is not None: self.updateScreen(filename=self.imagePath, xmlPath='', x=x, y=y, w=w, h=h, reloadMode=True) def updateScreen(self, filename, xmlPath, x=0, y=0, w=0, h=0, reloadMode=False): """ Update the screen """ self.imagePath = filename if not reloadMode: self.tableModel.mylist = [] self.tableModel.beginResetModel() self.tableModel.endResetModel() pixmap = QPixmap(filename) if pixmap is not None: self.origWidth = pixmap.width() self.origHeight = pixmap.height() self.screenResolutionLabel.setText( "Resolution=%sx%s" % (self.origWidth, self.origHeight)) #portrait if self.origWidth < self.origHeight: pixmap = pixmap.scaledToHeight(Settings.getInt( 'MobileAndroid', 'resolution-screen-height'), mode=Qt.SmoothTransformation) self.mobileImageLabel.setPixmap(pixmap) else: pixmap = pixmap.scaledToWidth(Settings.getInt( 'MobileAndroid', 'resolution-screen-width'), mode=Qt.SmoothTransformation) self.mobileImageLabel.setPixmap(pixmap) self.drawRectangle(x=x, y=y, w=w, h=h) self.resize(pixmap.width(), pixmap.height()) # convert xml to dict if len(xmlPath): f = QFile(xmlPath) if f.open(QIODevice.ReadOnly): document = QDomDocument() if document.setContent(f): newModel = DomModel(document, self) self.mobileTreeView.setModel(newModel) self.mobileTreeView.expandAll() self.mobileTreeView.resizeColumnToContents(0) f.close()
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 FormItem(QStandardItem): def __init__(self, name, fields, setup): super(FormItem, self).__init__(name) fields = [("Name", str, name)] + fields self.name = lambda: str(self.text()) self.names, _, _ = zip(*fields) self.dtypes = {} self.widgets = {} self.method_names = [] self.val_items = {} self.expr_items = {} self.group_items = {} self.setup = setup self.params_model = QStandardItemModel() self.params_model.itemChanged.connect(self.update_name) self.params_model.setHorizontalHeaderLabels(["Name", "Formula", "Evaluated"]) self.params_widget = QTableView() self.params_widget.setModel(self.params_model) self.params_widget.setItemDelegate(FormDelegate(self.params_model, self.widgets)) self.params_widget.verticalHeader().hide() for name, item_type, default in fields: self.add_field(name, item_type, default) self.params_widget.resizeRowsToContents() self.context_menu = ActionsMenu([]) self.params_model.itemChanged.connect(self.notify_group_item_children) def notify_group_item_children(self, item): method_name = method_style(self.params_model.item(item.row(), 0).text()) if method_name in self.group_items: current_item = self.dtypes[method_name](item.text()) previous_item = self.dtypes[method_name](self.group_items[method_name]) self.group_items[method_name] = current_item current_item.register_dependency(self) previous_item.unregister_dependency(self) def add_field(self, word_name, item_type, value): word_name = word_style(word_name) method_name = method_style(word_name) if item_type is int: self.dtypes[method_name] = int self.widgets[word_name] = lambda: IntVarLineEdit(self.setup) elif item_type is float: self.dtypes[method_name] = float self.widgets[word_name] = lambda: VarLineEdit(self.setup) elif isinstance(item_type, bool): self.dtypes[method_name] = bool self.widgets[word_name] = QCheckBox elif isinstance(item_type, (list, tuple)): self.dtypes[method_name] = str self.widgets[word_name] = \ lambda grp=item_type, **kwargs: MyComboBox(grp, **kwargs) elif isinstance(item_type, GroupItem): group = item_type value = group.items_list()[0].text() self.dtypes[method_name] = lambda i_name, grp=group: grp.item_from_name(i_name) self.widgets[word_name] = \ lambda grp=group, **kwargs: ItemsComboBox(grp, **kwargs) self.group_items[method_name] = value group.item_from_name(value).register_dependency(self) self.expr_items[method_name] = QStandardItem(str(value)) self.val_items[method_name] = ConstantItem("") self.params_model.appendRow([ConstantItem(word_name), self.expr_items[method_name], self.val_items[method_name]]) self.method_names.append(method_name) def set_name(self, name): self.setText(name) self.params_model.item(0, 1).setText(name) def update_name(self): self.setText(self.params_model.item(0, 1).text()) def eval_item(self, item): if item in self.method_names: dtype = self.dtypes[item] text = self.val_items[item].text() if text == "": text = self.expr_items[item].text() return dtype(text) else: raise AttributeError(item) def __getattr__(self, item): return self.eval_item(item)
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, 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