def load_menu(self): self.store_list_menu.clear() icon = QIcon() icon.addFile(I('donate.png'), QSize(16, 16)) for n, p in sorted(self.gui.istores.items(), key=lambda x: x[0].lower()): if p.base_plugin.affiliate: self.store_list_menu.addAction(icon, n, partial(self.open_store, p)) else: self.store_list_menu.addAction(n, partial(self.open_store, p))
def __init__(self): QWidget.__init__(self) # define periodic table widget for element selection self.periodicTableWidget = widgets.PeriodicTableDialog() # initial molecule Zmatrix (can be empty) # self.inp = [] self.inp = [['H'], ['O', 1, 0.9], ['O', 2, 1.4, 1, 105.], ['H', 3, 0.9, 2, 105., 1, 120.]] self.atomList = [] self.highList = [] self.labelList = [] self.fast = False # define & initialize ZMatModel that will contain Zmatrix data self.ZMatModel = QStandardItemModel(len(self.inp), 7, self) self.ZMatTable = QTableView(self) self.ZMatTable.setModel(self.ZMatModel) self.ZMatTable.setFixedWidth(325) #self.ZMatTable.installEventFilter(self) #self.ZMatModel.installEventFilter(self) self.ZMatModel.setHorizontalHeaderLabels(['atom','','bond','','angle','','dihedral']) for j, width in enumerate([40, 22, 65, 22, 65, 22, 65]): self.ZMatTable.setColumnWidth(j, width) # populate the ZMatModel self.populateZMatModel() #define Menu bar menus and their actions self.menuBar = QMenuBar(self) fileMenu = self.menuBar.addMenu('&File') editMenu = self.menuBar.addMenu('&Edit') viewMenu = self.menuBar.addMenu('&View') measureMenu = self.menuBar.addMenu('&Measure') helpMenu = self.menuBar.addMenu('&Help') readZmatAction = QAction('&Read &ZMat', self) readZmatAction.setShortcut('Ctrl+O') readZmatAction.setStatusTip('Read Zmat from file') readZmatAction.triggered.connect(self.readZmat) fileMenu.addAction(readZmatAction) readXYZAction = QAction('&Read &XYZ', self) readXYZAction.setShortcut('Ctrl+Shift+O') readXYZAction.setStatusTip('Read XYZ from file') readXYZAction.triggered.connect(self.readXYZ) fileMenu.addAction(readXYZAction) readGaussianAction = QAction('&Read &Gaussian log', self) readGaussianAction.setShortcut('Ctrl+G') readGaussianAction.setStatusTip('Read Gaussian log file') readGaussianAction.triggered.connect(self.readGaussian) fileMenu.addAction(readGaussianAction) writeZmatAction = QAction('&Write &ZMat', self) writeZmatAction.setShortcut('Ctrl+S') writeZmatAction.setStatusTip('Write Zmat to file') writeZmatAction.triggered.connect(self.writeZmat) fileMenu.addAction(writeZmatAction) writeXYZAction = QAction('&Write &XYZ', self) writeXYZAction.setShortcut('Ctrl+Shift+S') writeXYZAction.setStatusTip('Write XYZ from file') writeXYZAction.triggered.connect(self.writeXYZ) fileMenu.addAction(writeXYZAction) exitAction = QAction('&Exit', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Exit application') exitAction.triggered.connect(qApp.quit) fileMenu.addAction(exitAction) addRowAction = QAction('&Add &row', self) addRowAction.setShortcut('Ctrl+R') addRowAction.setStatusTip('Add row to ZMatrix') addRowAction.triggered.connect(self.addRow) editMenu.addAction(addRowAction) deleteRowAction = QAction('&Delete &row', self) deleteRowAction.setShortcut('Ctrl+Shift+R') deleteRowAction.setStatusTip('Delete row from ZMatrix') deleteRowAction.triggered.connect(self.deleteRow) editMenu.addAction(deleteRowAction) addAtomAction = QAction('&Add &atom', self) addAtomAction.setShortcut('Ctrl+A') addAtomAction.setStatusTip('Add atom to ZMatrix') addAtomAction.triggered.connect(self.buildB) editMenu.addAction(addAtomAction) drawModeMenu = QMenu('Draw mode', self) viewMenu.addMenu(drawModeMenu) fastDrawAction = QAction('&Fast draw', self) fastDrawAction.triggered.connect(self.fastDraw) normalDrawAction = QAction('&Normal draw', self) normalDrawAction.triggered.connect(self.normalDraw) drawModeMenu.addAction(normalDrawAction) drawModeMenu.addAction(fastDrawAction) clearHighlightsAction = QAction('&Clear selection', self) clearHighlightsAction.setShortcut('Ctrl+C') clearHighlightsAction.setStatusTip('Clear highlighted atoms') clearHighlightsAction.triggered.connect(self.clearHighlights) viewMenu.addAction(clearHighlightsAction) clearLabelsAction = QAction('&Clear labels', self) clearLabelsAction.setShortcut('Ctrl+Alt+C') clearLabelsAction.setStatusTip('Clear labels') clearLabelsAction.triggered.connect(self.clearLabels) viewMenu.addAction(clearLabelsAction) clearUpdateViewAction = QAction('&Clear selection and labels', self) clearUpdateViewAction.setShortcut('Ctrl+Shift+C') clearUpdateViewAction.setStatusTip('Clear highlighted atoms and labels') clearUpdateViewAction.triggered.connect(self.clearUpdateView) viewMenu.addAction(clearUpdateViewAction) self.showGaussAction = QAction('Show &Gaussian geometry optimization', self) self.showGaussAction.setShortcut('Ctrl+G') self.showGaussAction.setStatusTip('Show Gaussian geometry optimization plots for energy, force and displacement.') self.showGaussAction.setEnabled(False) self.showGaussAction.triggered.connect(self.showGauss) viewMenu.addAction(self.showGaussAction) self.showFreqAction = QAction('Show &IR frequency plot', self) self.showFreqAction.setShortcut('Ctrl+I') self.showFreqAction.setStatusTip('Show Gaussian calculated IR frequency plot.') self.showFreqAction.setEnabled(False) self.showFreqAction.triggered.connect(self.showFreq) viewMenu.addAction(self.showFreqAction) measureDistanceAction = QAction('&Measure &distance', self) measureDistanceAction.setShortcut('Ctrl+D') measureDistanceAction.setStatusTip('Measure distance between two atoms') measureDistanceAction.triggered.connect(self.measureDistanceB) measureMenu.addAction(measureDistanceAction) measureAngleAction = QAction('&Measure &angle', self) measureAngleAction.setShortcut('Ctrl+Shift+D') measureAngleAction.setStatusTip('Measure angle between three atoms') measureAngleAction.triggered.connect(self.measureAngleB) measureMenu.addAction(measureAngleAction) aboutAction = QAction('&About', self) aboutAction.setStatusTip('About this program...') aboutAction.triggered.connect(self.about) helpMenu.addAction(aboutAction) aboutQtAction = QAction('&About Qt', self) aboutQtAction.setStatusTip('About Qt...') aboutQtAction.triggered.connect(self.aboutQt) helpMenu.addAction(aboutQtAction) # define GL widget that displays the 3D molecule model self.window = widgets.MyGLView() self.window.installEventFilter(self) self.window.setMinimumSize(500, 500) #self.window.setBackgroundColor((50, 0, 10)) self.updateView() self.gaussianPlot = GraphicsLayoutWidget() self.gaussianPlot.resize(750, 250) self.gaussianPlot.setWindowTitle('Gaussian geometry optimization') #self.gaussianPlot.setAspectLocked(True) #self.gaussianPlot.addLayout(rowspan=3, colspan=1) self.FreqModel = QStandardItemModel(1, 3, self) self.freqTable = QTableView(self) self.freqTable.setModel(self.FreqModel) self.freqTable.setMinimumWidth(240) self.freqTable.installEventFilter(self) self.FreqModel.installEventFilter(self) self.FreqModel.setHorizontalHeaderLabels(['Frequency','IR Intensity','Raman Intensity']) for j, width in enumerate([80, 80, 80]): self.freqTable.setColumnWidth(j, width) self.freqWidget = QWidget() self.freqWidget.setWindowTitle('IR frequency plot & table') self.freqWidget.resize(800, 400) self.freqWidget.layout = QHBoxLayout(self.freqWidget) self.freqWidget.layout.setSpacing(1) self.freqWidget.layout.setContentsMargins(1, 1, 1, 1) self.freqPlot = GraphicsLayoutWidget() self.freqWidget.layout.addWidget(self.freqPlot) self.freqWidget.layout.addWidget(self.freqTable) self.freqTable.clicked.connect(self.freqCellClicked) # define other application parts self.statusBar = QStatusBar(self) self.fileDialog = QFileDialog(self) # define application layout self.layout = QVBoxLayout(self) self.layout.setSpacing(1) self.layout.setContentsMargins(1, 1, 1, 1) self.layout1 = QHBoxLayout() self.layout1.setSpacing(1) self.layout1.addWidget(self.ZMatTable) self.layout1.addWidget(self.window) self.layout.addWidget(self.menuBar) self.layout.addLayout(self.layout1) self.layout.addWidget(self.statusBar) self.adjustSize() self.setWindowTitle('Moldy') iconPath = 'icon.png' icon = QIcon(iconPath) icon.addFile(iconPath, QSize(16, 16)) icon.addFile(iconPath, QSize(24, 24)) icon.addFile(iconPath, QSize(32, 32)) icon.addFile(iconPath, QSize(48, 48)) icon.addFile(iconPath, QSize(256, 256)) self.setWindowIcon(icon) # start monitoring changes in the ZMatModel self.ZMatModel.dataChanged.connect(self.clearUpdateView)
class Matches(QAbstractItemModel): HEADERS = [_('Enabled'), _('Name'), _('No DRM'), _('Headquarters'), _('Affiliate'), _('Formats')] HTML_COLS = [1] def __init__(self, plugins): QAbstractItemModel.__init__(self) self.NO_DRM_ICON = QIcon(I('ok.png')) self.DONATE_ICON = QIcon() self.DONATE_ICON.addFile(I('donate.png'), QSize(16, 16)) self.all_matches = plugins self.matches = plugins self.filter = '' self.search_filter = SearchFilter(self.all_matches) self.sort_col = 1 self.sort_order = Qt.AscendingOrder def get_plugin(self, index): row = index.row() if row < len(self.matches): return self.matches[row] else: return None def search(self, filter): self.filter = filter.strip() if not self.filter: self.matches = self.all_matches else: try: self.matches = list(self.search_filter.parse(self.filter)) except: self.matches = self.all_matches self.layoutChanged.emit() self.sort(self.sort_col, self.sort_order) def enable_all(self): for i in xrange(len(self.matches)): index = self.createIndex(i, 0) data = QVariant(True) self.setData(index, data, Qt.CheckStateRole) def enable_none(self): for i in xrange(len(self.matches)): index = self.createIndex(i, 0) data = QVariant(False) self.setData(index, data, Qt.CheckStateRole) def enable_invert(self): for i in xrange(len(self.matches)): self.toggle_plugin(self.createIndex(i, 0)) def toggle_plugin(self, index): new_index = self.createIndex(index.row(), 0) data = QVariant(is_disabled(self.get_plugin(index))) self.setData(new_index, data, Qt.CheckStateRole) def index(self, row, column, parent=QModelIndex()): return self.createIndex(row, column) def parent(self, index): if not index.isValid() or index.internalId() == 0: return QModelIndex() return self.createIndex(0, 0) def rowCount(self, *args): return len(self.matches) def columnCount(self, *args): return len(self.HEADERS) def headerData(self, section, orientation, role): if role != Qt.DisplayRole: return NONE text = '' if orientation == Qt.Horizontal: if section < len(self.HEADERS): text = self.HEADERS[section] return QVariant(text) else: return QVariant(section+1) def data(self, index, role): row, col = index.row(), index.column() result = self.matches[row] if role in (Qt.DisplayRole, Qt.EditRole): if col == 1: return QVariant('<b>%s</b><br><i>%s</i>' % (result.name, result.description)) elif col == 3: return QVariant(result.headquarters) elif col == 5: return QVariant(', '.join(result.formats).upper()) elif role == Qt.DecorationRole: if col == 2: if result.drm_free_only: return QVariant(self.NO_DRM_ICON) if col == 4: if result.affiliate: return QVariant(self.DONATE_ICON) elif role == Qt.CheckStateRole: if col == 0: if is_disabled(result): return Qt.Unchecked return Qt.Checked elif role == Qt.ToolTipRole: if col == 0: if is_disabled(result): return QVariant('<p>' + _('This store is currently disabled and cannot be used in other parts of calibre.') + '</p>') else: return QVariant('<p>' + _('This store is currently enabled and can be used in other parts of calibre.') + '</p>') elif col == 1: return QVariant('<p>%s</p>' % result.description) elif col == 2: if result.drm_free_only: return QVariant('<p>' + _('This store only distributes ebooks without DRM.') + '</p>') else: return QVariant('<p>' + _('This store distributes ebooks with DRM. It may have some titles without DRM, but you will need to check on a per title basis.') + '</p>') elif col == 3: return QVariant('<p>' + _('This store is headquartered in %s. This is a good indication of what market the store caters to. However, this does not necessarily mean that the store is limited to that market only.') % result.headquarters + '</p>') elif col == 4: if result.affiliate: return QVariant('<p>' + _('Buying from this store supports the calibre developer: %s.') % result.author + '</p>') elif col == 5: return QVariant('<p>' + _('This store distributes ebooks in the following formats: %s') % ', '.join(result.formats) + '</p>') return NONE def setData(self, index, data, role): if not index.isValid(): return False row, col = index.row(), index.column() if col == 0: if data.toBool(): enable_plugin(self.get_plugin(index)) else: disable_plugin(self.get_plugin(index)) self.dataChanged.emit(self.index(index.row(), 0), self.index(index.row(), self.columnCount() - 1)) return True def flags(self, index): if index.column() == 0: return QAbstractItemModel.flags(self, index) | Qt.ItemIsUserCheckable return QAbstractItemModel.flags(self, index) def data_as_text(self, match, col): text = '' if col == 0: text = 'b' if is_disabled(match) else 'a' elif col == 1: text = match.name elif col == 2: text = 'a' if getattr(match, 'drm_free_only', True) else 'b' elif col == 3: text = getattr(match, 'headquarters', '') elif col == 4: text = 'a' if getattr(match, 'affiliate', False) else 'b' return text def sort(self, col, order, reset=True): self.sort_col = col self.sort_order = order if not self.matches: return descending = order == Qt.DescendingOrder self.matches.sort(None, lambda x: sort_key(unicode(self.data_as_text(x, col))), descending) if reset: self.reset()
class Matches(QAbstractItemModel): HEADERS = [ _('Enabled'), _('Name'), _('No DRM'), _('Headquarters'), _('Affiliate'), _('Formats') ] HTML_COLS = [1] def __init__(self, plugins): QAbstractItemModel.__init__(self) self.NO_DRM_ICON = QIcon(I('ok.png')) self.DONATE_ICON = QIcon() self.DONATE_ICON.addFile(I('donate.png'), QSize(16, 16)) self.all_matches = plugins self.matches = plugins self.filter = '' self.search_filter = SearchFilter(self.all_matches) self.sort_col = 1 self.sort_order = Qt.AscendingOrder def get_plugin(self, index): row = index.row() if row < len(self.matches): return self.matches[row] else: return None def search(self, filter): self.filter = filter.strip() if not self.filter: self.matches = self.all_matches else: try: self.matches = list(self.search_filter.parse(self.filter)) except: self.matches = self.all_matches self.layoutChanged.emit() self.sort(self.sort_col, self.sort_order) def enable_all(self): for i in xrange(len(self.matches)): index = self.createIndex(i, 0) data = QVariant(True) self.setData(index, data, Qt.CheckStateRole) def enable_none(self): for i in xrange(len(self.matches)): index = self.createIndex(i, 0) data = QVariant(False) self.setData(index, data, Qt.CheckStateRole) def enable_invert(self): for i in xrange(len(self.matches)): self.toggle_plugin(self.createIndex(i, 0)) def toggle_plugin(self, index): new_index = self.createIndex(index.row(), 0) data = QVariant(is_disabled(self.get_plugin(index))) self.setData(new_index, data, Qt.CheckStateRole) def index(self, row, column, parent=QModelIndex()): return self.createIndex(row, column) def parent(self, index): if not index.isValid() or index.internalId() == 0: return QModelIndex() return self.createIndex(0, 0) def rowCount(self, *args): return len(self.matches) def columnCount(self, *args): return len(self.HEADERS) def headerData(self, section, orientation, role): if role != Qt.DisplayRole: return NONE text = '' if orientation == Qt.Horizontal: if section < len(self.HEADERS): text = self.HEADERS[section] return QVariant(text) else: return QVariant(section + 1) def data(self, index, role): row, col = index.row(), index.column() result = self.matches[row] if role in (Qt.DisplayRole, Qt.EditRole): if col == 1: return QVariant('<b>%s</b><br><i>%s</i>' % (result.name, result.description)) elif col == 3: return QVariant(result.headquarters) elif col == 5: return QVariant(', '.join(result.formats).upper()) elif role == Qt.DecorationRole: if col == 2: if result.drm_free_only: return QVariant(self.NO_DRM_ICON) if col == 4: if result.affiliate: return QVariant(self.DONATE_ICON) elif role == Qt.CheckStateRole: if col == 0: if is_disabled(result): return Qt.Unchecked return Qt.Checked elif role == Qt.ToolTipRole: if col == 0: if is_disabled(result): return QVariant('<p>' + _( 'This store is currently disabled and cannot be used in other parts of calibre.' ) + '</p>') else: return QVariant('<p>' + _( 'This store is currently enabled and can be used in other parts of calibre.' ) + '</p>') elif col == 1: return QVariant('<p>%s</p>' % result.description) elif col == 2: if result.drm_free_only: return QVariant( '<p>' + _('This store only distributes ebooks without DRM.') + '</p>') else: return QVariant('<p>' + _( 'This store distributes ebooks with DRM. It may have some titles without DRM, but you will need to check on a per title basis.' ) + '</p>') elif col == 3: return QVariant('<p>' + _( 'This store is headquartered in %s. This is a good indication of what market the store caters to. However, this does not necessarily mean that the store is limited to that market only.' ) % result.headquarters + '</p>') elif col == 4: if result.affiliate: return QVariant('<p>' + _( 'Buying from this store supports the calibre developer: %s.' ) % result.author + '</p>') elif col == 5: return QVariant('<p>' + _( 'This store distributes ebooks in the following formats: %s' ) % ', '.join(result.formats) + '</p>') return NONE def setData(self, index, data, role): if not index.isValid(): return False col = index.column() if col == 0: if data.toBool(): enable_plugin(self.get_plugin(index)) else: disable_plugin(self.get_plugin(index)) self.dataChanged.emit(self.index(index.row(), 0), self.index(index.row(), self.columnCount() - 1)) return True def flags(self, index): if index.column() == 0: return QAbstractItemModel.flags(self, index) | Qt.ItemIsUserCheckable return QAbstractItemModel.flags(self, index) def data_as_text(self, match, col): text = '' if col == 0: text = 'b' if is_disabled(match) else 'a' elif col == 1: text = match.name elif col == 2: text = 'a' if getattr(match, 'drm_free_only', True) else 'b' elif col == 3: text = getattr(match, 'headquarters', '') elif col == 4: text = 'a' if getattr(match, 'affiliate', False) else 'b' return text def sort(self, col, order, reset=True): self.sort_col = col self.sort_order = order if not self.matches: return descending = order == Qt.DescendingOrder self.matches.sort( None, lambda x: sort_key(unicode(self.data_as_text(x, col))), descending) if reset: self.reset()