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 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)
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)
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 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 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 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 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 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 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)