class MainWidget(QWidget): """ MainWidget class Main widget for the main window """ def __init__(self, parent): super(MainWidget, self).__init__(parent) self.layout = QVBoxLayout(self) self.load_button = QPushButton("Load data") self.load_button.clicked.connect(self.scrape_data) self.layout.addWidget(self.load_button) self.status_label = QLabel() self.layout.addWidget(self.status_label) self.list_widget = QListWidget() self.list_widget.itemClicked.connect(self.item_clicked) self.layout.addWidget(self.list_widget) # Load the data from the database self.load_data() self.setLayout(self.layout) def scrape_data(self): """ Scrape the data and load it into the list widget """ scrape_and_save() self.load_data() self.status_label.setText("Data loaded") def load_data(self): """ Load the data from the database into the list widget """ self.list_widget.clear() data = Database.load_data_from_db() for item in data: self.list_widget.addItem(item.date + " : " + item.title + " - " + item.image) def item_clicked(self, item): """ When a user clicks on the item in the list widget get the url for the item image and open it in the browser :param item: List widget item """ text = item.text() image = text.split(' - ') image = image[1] import webbrowser webbrowser.open(image)
class NapalmInterfaces(QWidget): napalm_actions = ( 'Interfaces', 'Interface IP', 'Interfaces counters', ) @update_paths def __init__(self, node, controller): super().__init__() self.node = node action_label = QLabel('Action') object_label = QLabel('Object') self.object_list = QListWidget() self.object_list.setSortingEnabled(True) self.object_list.itemSelectionChanged.connect(self.text_update) self.action_list = QListWidget() self.action_list.setSortingEnabled(True) self.action_list.itemSelectionChanged.connect(self.text_update) self.action_list.addItems(self.napalm_actions) self.properties_edit = QConsoleEdit() self.properties_edit.setMinimumSize(300, 300) layout = QGridLayout() layout.addWidget(object_label, 0, 0) layout.addWidget(self.object_list, 1, 0) layout.addWidget(action_label, 0, 1) layout.addWidget(self.action_list, 1, 1) layout.addWidget(self.properties_edit, 2, 0, 1, 2) self.setLayout(layout) def update(self): self.object_list.clear() if 'Interfaces' in self.node.napalm_data: self.object_list.addItems(self.node.napalm_data['Interfaces']) def text_update(self): action = self.action_list.currentItem() object = self.object_list.currentItem() if action and object: self.properties_edit.clear() # we display a dictionnary with the following format: # property1: value1 # property2: value2 action, object = action.text(), object.text() value = str_dict(self.node.napalm_data[action][object]) self.properties_edit.insertPlainText(value)
class MetricsWindowTab(QWidget): def __init__(self, parent=None): super().__init__(parent) self.name = self.tr("Metrics Window") self.inputTextLabel = QLabel(self.tr("Default text:"), self) self.inputTextList = QListWidget(self) self.inputTextList.setDragDropMode(QAbstractItemView.InternalMove) self.addItemButton = QPushButton("+", self) self.addItemButton.clicked.connect(self.addItem) self.removeItemButton = QPushButton("−", self) self.removeItemButton.clicked.connect(self.removeItem) layout = QGridLayout(self) l = 0 layout.addWidget(self.inputTextLabel, l, 0, 1, 3) l += 1 layout.addWidget(self.inputTextList, l, 0, 1, 3) l += 1 layout.addWidget(self.addItemButton, l, 0) layout.addWidget(self.removeItemButton, l, 1) self.setLayout(layout) self.readSettings() def addItem(self): item = QListWidgetItem(self.inputTextList) item.setFlags(item.flags() | Qt.ItemIsEditable) self.inputTextList.setCurrentItem(item) self.inputTextList.editItem(item) self.removeItemButton.setEnabled(True) def removeItem(self): i = self.inputTextList.currentRow() self.inputTextList.takeItem(i) if not self.inputTextList.count(): self.removeItemButton.setEnabled(False) def readSettings(self): self.inputTextList.clear() entries = settings.metricsWindowComboBoxItems() for entry in entries: item = QListWidgetItem(entry, self.inputTextList) item.setFlags(item.flags() | Qt.ItemIsEditable) if not len(entries): self.removeItemButton.setEnabled(False) def writeSettings(self): entries = [] for i in range(self.inputTextList.count()): item = self.inputTextList.item(i) entries.append(item.text()) settings.setMetricsWindowComboBoxItems(entries)
class AddFriendDialog(QDialog): def __init__(self, client_socket): super().__init__() self.client_socket = client_socket self.client_socket.recv_user_search.connect(self.recvUserSearch) self.selected_user = None self.initUI() def initUI(self): self.grid = QGridLayout(self) self.search_box_label = QLabel("Search:") self.grid.addWidget(self.search_box_label, 0, 0, 1, 1) self.search_box = QLineEdit() self.grid.addWidget(self.search_box, 0, 1, 1, 2) self.search_button = QPushButton("Search") self.search_button.pressed.connect(self.searchUser) self.grid.addWidget(self.search_button, 0, 3, 1, 1) self.search_result = QListWidget() self.grid.addWidget(self.search_result, 1, 0, 2, 2) #TODO get user avatars to work self.add_friend_button = QPushButton("Add Friend") self.add_friend_button.pressed.connect(self.addFriend) self.grid.addWidget(self.add_friend_button, 1, 2, 1, 2) self.cancel_button = QPushButton("Cancel") self.cancel_button.pressed.connect(self.cancel) self.grid.addWidget(self.cancel_button, 2, 2, 1, 2) def searchUser(self): self.client_socket.searchUser(self.search_box.text()) def recvUserSearch(self, found_users): self.search_result.clear() for user in found_users: self.search_result.addItem(QListWidgetItem(user)) def addFriend(self): self.selected_user = self.search_result.selectedItems()[0].text() config.friends[self.selected_user] = {} self.close() def cancel(self): self.close()
class LogWidget(QWidget): def __init__(self): super().__init__() self.initUI() self.show() def initUI(self): self.btnclear = QPushButton("Clear messages", self) self.btnclear.clicked.connect(self._clearClicked) self.lwmessages = QListWidget(self) for _, msgtype, msgtext in Log.getLogMessages(): self.addLogItem(msgtype, msgtext) self.hboxlayout = QHBoxLayout() self.hboxlayout.addWidget(self.btnclear) self.hboxlayout.addStretch() self.vboxlayout = QVBoxLayout() self.vboxlayout.addLayout(self.hboxlayout) self.vboxlayout.addWidget(self.lwmessages) self.setLayout(self.vboxlayout) # Make sure this widget listens to new logevents Log.setNewMessageCallBack(self._newMessageAddedToLog) def _clearClicked(self): self.lwmessages.clear() Log.clearMessages() def _newMessageAddedToLog(self, msgtype, msgtext): self.addLogItem(msgtype, msgtext) def addLogItem(self, msgtype, msgtext): if msgtype == Log.INFO: icon = QIcon('images/information.png') elif msgtype == Log.WARNING: icon = QIcon('images/warning.png') else: icon = QIcon('images/error.png') item = QListWidgetItem(icon, msgtext) self.lwmessages.addItem(item)
class SessionManager(QMainWindow): def __init__(self, parent=None): QListWidget.__init__(self, parent) self.setWindowTitle(tr("Saved Sessions")) self.setWindowFlags(Qt.Dialog) hideAction = QAction(self) hideAction.setShortcuts(["Esc", "Ctrl+W"]) hideAction.triggered.connect(self.hide) self.addAction(hideAction) self.sessionList = QListWidget(self) self.sessionList.itemActivated.connect(self.loadSession) self.setCentralWidget(self.sessionList) self.toolBar = QToolBar(self) self.toolBar.setMovable(False) self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu) self.addToolBar(Qt.BottomToolBarArea, self.toolBar) self.loadButton = QPushButton(tr("&Load"), self) self.loadButton.clicked.connect(lambda: self.loadSession(self.sessionList.currentItem())) self.toolBar.addWidget(self.loadButton) self.saveButton = QPushButton(tr("&Save"), self) self.saveButton.clicked.connect(saveSessionManually) self.saveButton.clicked.connect(self.refresh) self.toolBar.addWidget(self.saveButton) deleteAction = QAction(self) deleteAction.setShortcut("Del") deleteAction.triggered.connect(self.delete) self.addAction(deleteAction) def refresh(self): self.sessionList.clear() if os.path.exists(settings.session_folder): sessions = os.listdir(settings.session_folder) for session in sessions: self.sessionList.addItem(session) def delete(self): if self.sessionList.hasFocus(): try: os.remove(os.path.join(settings.session_folder, self.sessionList.currentItem().text())) except: pass self.refresh() def show(self): self.refresh() QMainWindow.show(self) def loadSession(self, item): if os.path.exists(settings.session_folder): loadSession(os.path.join(settings.session_folder, item.text())) self.hide()
class TabGroup(QWidget, itab_item.ITabItem): def __init__(self, project, name, actions): super(TabGroup, self).__init__() vbox = QVBoxLayout(self) self.actions = actions self.project = project self.ID = self.project self.name = name self.tabs = [] self.listWidget = QListWidget() hbox = QHBoxLayout() btnExpand = QPushButton(_translate("TabGroup", "Expand this Files")) btnExpandAll = QPushButton(_translate("TabGroup", "Expand all Groups")) hbox.addWidget(btnExpandAll) hbox.addSpacerItem(QSpacerItem(20, 20, QSizePolicy.Expanding)) hbox.addWidget(btnExpand) vbox.addLayout(hbox) vbox.addWidget(self.listWidget) btnExpand.clicked['bool'].connect(self.expand_this) btnExpandAll.clicked['bool'].connect(self.actions.deactivate_tabs_groups) def add_widget(self, widget): self.tabs.append(widget) self.listWidget.addItem(widget.ID) def expand_this(self): self.actions.group_tabs_together() for tab in self.tabs: tabName = file_manager.get_basename(tab.ID) self.actions.ide.mainContainer.add_tab(tab, tabName) index = self.actions.ide.mainContainer._tabMain.indexOf(self) self.actions.ide.mainContainer._tabMain.removeTab(index) self.tabs = [] self.listWidget.clear() def only_expand(self): for tab in self.tabs: tabName = file_manager.get_basename(tab.ID) self.actions.ide.mainContainer.add_tab(tab, tabName) index = self.actions.ide.mainContainer._tabMain.indexOf(self) self.actions.ide.mainContainer._tabMain.removeTab(index) self.tabs = [] self.listWidget.clear()
class AdremoverSettingsPanel(SettingsPanel): def __init__(self, parent=None): super(AdremoverSettingsPanel, self).__init__(parent) filterEntryRow = custom_widgets.LineEditRow(tr("Add filter:"), self) self.filterEntry = filterEntryRow.lineEdit self.filterEntry.returnPressed.connect(self.addFilter) self.layout().addWidget(filterEntryRow) self.addFilterButton = QPushButton(tr("Add")) self.addFilterButton.clicked.connect(self.addFilter) filterEntryRow.layout().addWidget(self.addFilterButton) # Ad Remover filter list. self.filterList = QListWidget(self) self.layout().addWidget(self.filterList) self.removeFilterButton = QPushButton(tr("Remove")) self.removeFilterButton.clicked.connect(lambda: self.removeFilter(True)) self.layout().addWidget(self.removeFilterButton) self.removeAction = QAction(self) self.removeAction.setShortcut("Del") self.removeAction.triggered.connect(self.removeFilter) self.addAction(self.removeAction) def removeFilter(self, forceFocus=False): if self.filterList.hasFocus() or forceFocus: self.filterList.takeItem(self.filterList.row(self.filterList.currentItem())) def addFilter(self): self.filterList.addItem(self.filterEntry.text()) self.filterEntry.clear() def loadSettings(self): settings.load_adremover_filters() self.filterList.clear() for f in settings.adremover_filters: self.filterList.addItem(f) def saveSettings(self): settings.adremover_filters = [self.filterList.item(f).text() for f in range(0, self.filterList.count())] settings.save_adremover_filters()
class JavaScriptExceptionsPanel(SettingsPanel): def __init__(self, parent=None): super(JavaScriptExceptionsPanel, self).__init__(parent) domainEntryRow = custom_widgets.LineEditRow(tr("Add domain:"), self) self.domainEntry = domainEntryRow.lineEdit self.domainEntry.returnPressed.connect(self.addDomain) self.layout().addWidget(domainEntryRow) self.addDomainButton = QPushButton(tr("Add")) self.addDomainButton.clicked.connect(self.addDomain) domainEntryRow.layout().addWidget(self.addDomainButton) self.domainList = QListWidget(self) self.layout().addWidget(self.domainList) self.removeDomainButton = QPushButton(tr("Remove")) self.removeDomainButton.clicked.connect(lambda: self.removeDomain(True)) self.layout().addWidget(self.removeDomainButton) self.removeAction = QAction(self) self.removeAction.setShortcut("Del") self.removeAction.triggered.connect(self.removeDomain) self.addAction(self.removeAction) def removeDomain(self, forceFocus=False): if self.domainList.hasFocus() or forceFocus: self.domainList.takeItem(self.domainList.row(self.domainList.currentItem())) def addDomain(self): self.domainList.addItem(self.domainEntry.text()) self.domainEntry.clear() def loadSettings(self): settings.js_exceptions = settings.setting_to_list("content/JavaScriptExceptions") self.domainList.clear() for f in settings.js_exceptions: self.domainList.addItem(f) def saveSettings(self): settings.js_exceptions = [self.domainList.item(f).text() for f in range(0, self.domainList.count())] settings.settings.setValue("content/JavaScriptExceptions", settings.js_exceptions) settings.settings.sync()
class BWPassengerWindow(QMdiSubWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setBaseSize(400, 400) self.centralwidget = QWidget(self) self.setWidget(self.centralwidget) layout = QHBoxLayout(self.centralwidget) self.passengerlist = QListWidget(self.centralwidget) layout.addWidget(self.passengerlist) self.setWindowTitle("Passengers") def reset(self): self.passengerlist.clearSelection() self.passengerlist.clear() def add_passenger(self, passenger_name, passenger_id): item = BWEntityEntry(passenger_id, passenger_name) self.passengerlist.addItem(item) def set_title(self, entityname): self.setWindowTitle("Passengers - {0}".format(entityname))
class GstMediaSettings(SettingsSection): Name = 'Media Settings' def __init__(self, size, cue=None, parent=None): super().__init__(size, cue=cue, parent=parent) self._pipe = '' self._conf = {} self._check = False self.glayout = QGridLayout(self) self.listWidget = QListWidget(self) self.glayout.addWidget(self.listWidget, 0, 0) self.pipeButton = QPushButton('Change Pipe', self) self.glayout.addWidget(self.pipeButton, 1, 0) self.elements = QStackedWidget(self) self.glayout.addWidget(self.elements, 0, 1, 2, 1) self.glayout.setColumnStretch(0, 2) self.glayout.setColumnStretch(1, 5) self.listWidget.currentItemChanged.connect(self.__change_page) self.pipeButton.clicked.connect(self.__edit_pipe) def set_configuration(self, conf): # Get the media section of the cue configuration if conf is not None: conf = conf.get('media', {}) # Activate the layout, so we can get the right widgets size self.glayout.activate() # Create a local copy of the configuration self._conf = deepcopy(conf) # Create the widgets sections = sections_by_element_name() for element in conf.get('pipe', '').split('!'): widget = sections.get(element) if widget is not None: widget = widget(self.elements.size(), element, self) widget.set_configuration(self._conf['elements']) self.elements.addWidget(widget) item = QListWidgetItem(widget.NAME) self.listWidget.addItem(item) self.listWidget.setCurrentRow(0) def get_configuration(self): conf = {'elements': {}} for el in self.elements.children(): if isinstance(el, SettingsSection): conf['elements'].update(el.get_configuration()) # If in check mode the pipeline is not returned if not self._check: conf['pipe'] = self._conf['pipe'] return {'media': conf} def enable_check(self, enable): self._check = enable for element in self.elements.children(): if isinstance(element, SettingsSection): element.enable_check(enable) def __change_page(self, current, previous): if not current: current = previous self.elements.setCurrentIndex(self.listWidget.row(current)) def __edit_pipe(self): # Backup the settings self._conf.update(self.get_configuration()['media']) # Show the dialog dialog = GstPipeEdit(self._conf.get('pipe', ''), parent=self) if dialog.exec_() == dialog.Accepted: # Reset the view for _ in range(self.elements.count()): self.elements.removeWidget(self.elements.widget(0)) self.listWidget.clear() # Reload with the new pipeline self._conf['pipe'] = dialog.get_pipe() self.set_configuration({'media': self._conf}) self.enable_check(self._check)
class StartWindow(QWidget): def __init__(self, model=None): super().__init__() # zwraca klase rodzica i wywoluje jego konstruktor self.model = model self.interface() def interface(self): #1-liniowe pola edycyjne self.featuresEdt = QLineEdit() self.featuresEdt.setText("1") self.sizeSetEdt = QLineEdit() self.sizeSetEdt.setText("10") self.paramsEdt = QLineEdit() self.paramsEdt.setText("1") # przyciski self.addFeaturesBtn = QPushButton("&AddFeatures", self) self.createSetBtn = QPushButton("&Create", self) self.addParamsBtn = QPushButton("Add&Params", self) self.findParams = QPushButton("&FindParams", self) self.resetBtn = QPushButton("&Reset", self) self.addFeaturesBtn.clicked.connect(self.addFeaturesClick) self.createSetBtn.clicked.connect(self.createSetClick) self.addParamsBtn.clicked.connect(self.addParamsClick) self.findParams.clicked.connect(self.findParamsClick) self.resetBtn.clicked.connect(self.resetClick) # etykiety self.featuresLabel = QLabel("Features: ", self) self.setLabel = QLabel("Set: ", self) self.paramsLabel = QLabel("Params: ", self) self.matchingLabel = QLabel("Maching: ", self) # ListWidget self.featuresListWidget = QListWidget() self.setWidget = QListWidget() self.paramsListWidget = QListWidget() self.findParamsListWidget = QListWidget() # uklad tabelaryczny: self.tab_layout = QGridLayout() self.tab_layout.addWidget(self.featuresEdt, 0, 0) self.tab_layout.addWidget(self.sizeSetEdt, 0, 1) self.tab_layout.addWidget(self.paramsEdt, 0, 2) self.tab_layout.addWidget(self.resetBtn, 0, 3) self.tab_layout.addWidget(self.addFeaturesBtn, 1, 0) self.tab_layout.addWidget(self.createSetBtn, 1, 1) self.tab_layout.addWidget(self.addParamsBtn, 1, 2) self.tab_layout.addWidget(self.findParams, 1, 3) self.tab_layout.addWidget(self.featuresLabel, 2, 0) self.tab_layout.addWidget(self.setLabel, 2, 1) self.tab_layout.addWidget(self.paramsLabel, 2, 2) self.tab_layout.addWidget(self.matchingLabel, 2, 3) self.tab_layout.addWidget(self.featuresListWidget, 3, 0) self.tab_layout.addWidget(self.setWidget, 3, 1) self.tab_layout.addWidget(self.paramsListWidget, 3, 2) self.tab_layout.addWidget(self.findParamsListWidget, 3, 3) # przypisanie utworzonego ukladu do okna self.setLayout(self.tab_layout) self.showMaximized() self.setWindowTitle("Projekt - dopasowanie zbiorow") self.show() def addFeaturesClick(self): self.model.listoffeatures.addToList(self.featuresEdt.text()) #print(self.model.listoffeatures.list) l = len(self.model.listoffeatures.list) - 1 self.featuresListWidget.insertItem(l, self.model.listoffeatures.list[-1]) def createSetClick(self): self.setWidget.clear() self.model.set.createSet(int(self.sizeSetEdt.text()), model.listoffeatures.list) print(model.set.set) for a in model.set.set: self.setWidget.addItem(str(a)) def addParamsClick(self): self.model.listOfParams.addToList(self.paramsEdt.text()) # print(self.model.listoffeatures.list) l = len(self.model.listOfParams.list) - 1 self.paramsListWidget.insertItem(l, self.model.listOfParams.list[-1]) print(self.model.listOfParams.list) def findParamsClick(self): self.model.set.findParams(self.model.listOfParams.list) for i, a in enumerate(self.model.set.listofResults): self.findParamsListWidget.insertItem(i, str(a)) def resetClick(self): self.model.resetmodel() self.clearLayout(self.tab_layout) def clearLayout(self, layout): self.featuresListWidget.clear() self.setWidget.clear() self.paramsListWidget.clear() self.findParamsListWidget.clear()
class QuestionManagerDlg(TopicManagerDlg): _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(QuestionManagerDlg, cls).__new__(cls, *args, **kwargs) return cls._instance def __init__(self, parent): super(QuestionManagerDlg, self).__init__(parent) self.btnAddL = QPushButton('Add') self.btnRemoveL = QPushButton('Remove') self.btnRemoveL.setEnabled(False) self.LangBox.addWidget(self.btnAddL) self.LangBox.addWidget(self.btnRemoveL) self.btnAddT = QPushButton('Add') self.btnRemoveT = QPushButton('Remove') self.btnRemoveT.setEnabled(False) self.topicBox.addWidget(self.btnAddT) self.topicBox.addWidget(self.btnRemoveT) lblQuestions = QLabel('Select a question.') self.lstQuestions = QListWidget() self.lstQuestions.setSelectionMode(QAbstractItemView.ExtendedSelection) self.btnRemoveQ = QPushButton('Remove') self.btnRemoveQ.setEnabled(False) _layout3 = QVBoxLayout() _layout3.addWidget(lblQuestions) _layout3.addWidget(self.lstQuestions) _layout3.addWidget(self.btnRemoveQ) self.layout.addLayout(_layout3) self.setLayout(self.layout) self.lstLangs.itemClicked.connect(self.selectLang) self.lstTopics.itemClicked.connect(self.selectTopic) self.lstQuestions.itemClicked.connect(self.onSelectQuestion) self.btnAddL.clicked.connect(self.onAddL) self.btnRemoveL.clicked.connect(self.onRemoveL) self.btnAddT.clicked.connect(self.onAddT) self.btnRemoveT.clicked.connect(self.onRemoveT) self.btnRemoveQ.clicked.connect(self.onRemoveQ) def selectLang(self, item): ''' show topics that are related with selected language. :param item: language :return: QListWidgetItem ''' self.btnRemoveL.setEnabled(True) _lang = item.text() lang = session.query(Language).filter(Language.name == _lang).first() if not lang: return topics = lang.topics.all() self.lstTopics.clear() for topic in topics: item = QListWidgetItem() item.setText(topic.title) item.setStatusTip(str(topic.id)) self.lstTopics.addItem(item) self.lstQuestions.clear() def selectTopic(self, item): self.btnRemoveT.setEnabled(True) _topic = item.text() topic = session.query(Topic).filter(Topic.title == _topic).first() questions = topic.questions.all() self.lstQuestions.clear() for q in questions: item = QListWidgetItem() item.setText(q.text) item.setStatusTip(str(q.id)) self.lstQuestions.addItem(item) def onSelectQuestion(self, item): ''' Set the button 'Remove question' to enabled. ''' self.btnRemoveQ.setEnabled(True) def onAddL(self): ''' Add new language. ''' lang, ok = QInputDialog.getText(self, 'add language', 'Input language name') if ok and lang and lang.strip(): if self.lstLangs.findItems(lang, Qt.MatchFixedString): QMessageBox.information(self, 'Error', '{} exists already.'.format(lang)) return l = Language(name=lang) session.add(l) session.commit() item = QListWidgetItem() item.setText(l.name) item.setStatusTip(str(l.id)) self.lstLangs.addItem(item) def onRemoveL(self): ''' remove selected langauge and realted topics and questions. ''' answer = QMessageBox.question(self, 'Remove Language', "This operation will remove this language and it's topics.") if answer == QMessageBox.No: return row = self.lstLangs.currentRow() id = self.lstLangs.currentItem().statusTip() record = session.query(Language).filter(Language.id == id) if record: record.delete(synchronize_session=False) self.lstLangs.takeItem(row) self.lstTopics.clear() ts = session.query(Topic).filter(Topic.lang_id == id).all() for t in ts: qs = session.query(Question).filter(Question.topic_id == t.id).all() for q in qs: session.delete(q) session.delete(t) session.commit() self.btnRemoveL.setEnabled(False) # @pyqtSlot(Topic) def _finishAddQuestions(self, t): item = QListWidgetItem() item.setText(t.title) item.setStatusTip(str(t.id)) self.lstTopics.addItem(item) session.commit() print('finished') # @pyqtSlot(Question) def _appendQuestion(self, q): print('q: ', q) item = QListWidgetItem() item.setText(q.text) item.setStatusTip(str(q.id)) self.lstQuestions.addItem(item) session.add(q) def onAddT(self): ''' Add new topic. ''' lang = self.lstLangs.currentItem() if not lang: return lang = lang.text() url, ok = QInputDialog.getText(self, 'add topic', 'Input url for {}'.format(lang)) if ok and lang and url and url.strip(): try: thread = Worker(lang, url, self) thread.update.connect(self._appendQuestion) thread.finish.connect(self._finishAddQuestions) thread.start() except FileExistsError: QMessageBox.information(self, 'Error', 'This topic exists already.') except ValueError: QMessageBox.information(self, 'Error', 'cannot access the url.') def onRemoveT(self): answer = QMessageBox.question(self, 'Remove Topic', "This operation will remove this topic and it's questions.") if answer == QMessageBox.No: return row = self.lstTopics.currentRow() id = self.lstTopics.currentItem().statusTip() record = session.query(Topic).filter(Topic.id == id) if record: record.delete(synchronize_session=False) self.lstTopics.takeItem(row) self.lstQuestions.clear() qs = session.query(Question).filter(Question.topic_id == id).all() for q in qs: session.delete(q) session.commit() self.btnRemoveT.setEnabled(False) def onRemoveQ(self): ''' Remove a selected question from database. ''' for item in self.lstQuestions.selectedItems(): id = item.statusTip() self.lstQuestions.setCurrentItem(item) row = self.lstQuestions.currentRow() record = session.query(Question).filter(Question.id == id) if record: record.delete(synchronize_session=False) self.lstQuestions.takeItem(row) session.commit() self.btnRemoveQ.setEnabled(False)
class Form(QDialog): def __init__(self, parent=None): super(Form, self).__init__(parent) self.mutex = QMutex() self.fileCount = 0 self.filenamesForWords = collections.defaultdict(set) self.commonWords = set() self.lock = QReadWriteLock() self.path = QDir.homePath() pathLabel = QLabel("Indexing path:") self.pathLabel = QLabel() self.pathLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) self.pathButton = QPushButton("Set &Path...") self.pathButton.setAutoDefault(False) findLabel = QLabel("&Find word:") self.findEdit = QLineEdit() findLabel.setBuddy(self.findEdit) commonWordsLabel = QLabel("&Common words:") self.commonWordsListWidget = QListWidget() commonWordsLabel.setBuddy(self.commonWordsListWidget) filesLabel = QLabel("Files containing the &word:") self.filesListWidget = QListWidget() filesLabel.setBuddy(self.filesListWidget) filesIndexedLabel = QLabel("Files indexed") self.filesIndexedLCD = QLCDNumber() self.filesIndexedLCD.setSegmentStyle(QLCDNumber.Flat) wordsIndexedLabel = QLabel("Words indexed") self.wordsIndexedLCD = QLCDNumber() self.wordsIndexedLCD.setSegmentStyle(QLCDNumber.Flat) commonWordsLCDLabel = QLabel("Common words") self.commonWordsLCD = QLCDNumber() self.commonWordsLCD.setSegmentStyle(QLCDNumber.Flat) self.statusLabel = QLabel("Click the 'Set Path' " "button to start indexing") self.statusLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) topLayout = QHBoxLayout() topLayout.addWidget(pathLabel) topLayout.addWidget(self.pathLabel, 1) topLayout.addWidget(self.pathButton) topLayout.addWidget(findLabel) topLayout.addWidget(self.findEdit, 1) leftLayout = QVBoxLayout() leftLayout.addWidget(filesLabel) leftLayout.addWidget(self.filesListWidget) rightLayout = QVBoxLayout() rightLayout.addWidget(commonWordsLabel) rightLayout.addWidget(self.commonWordsListWidget) middleLayout = QHBoxLayout() middleLayout.addLayout(leftLayout, 1) middleLayout.addLayout(rightLayout) bottomLayout = QHBoxLayout() bottomLayout.addWidget(filesIndexedLabel) bottomLayout.addWidget(self.filesIndexedLCD) bottomLayout.addWidget(wordsIndexedLabel) bottomLayout.addWidget(self.wordsIndexedLCD) bottomLayout.addWidget(commonWordsLCDLabel) bottomLayout.addWidget(self.commonWordsLCD) bottomLayout.addStretch() layout = QVBoxLayout() layout.addLayout(topLayout) layout.addLayout(middleLayout) layout.addLayout(bottomLayout) layout.addWidget(self.statusLabel) self.setLayout(layout) self.walkers = [] self.completed = [] self.pathButton.clicked.connect(self.setPath) self.findEdit.returnPressed.connect(self.find) self.setWindowTitle("Page Indexer") def stopWalkers(self): for walker in self.walkers: if isAlive(walker) and walker.isRunning(): walker.stop() for walker in self.walkers: if isAlive(walker) and walker.isRunning(): walker.wait() self.walkers = [] self.completed = [] def setPath(self): self.stopWalkers() self.pathButton.setEnabled(False) path = QFileDialog.getExistingDirectory(self, "Choose a Path to Index", self.path) if not path: self.statusLabel.setText("Click the 'Set Path' " "button to start indexing") self.pathButton.setEnabled(True) return self.statusLabel.setText("Scanning directories...") QApplication.processEvents() # Needed for Windows self.path = QDir.toNativeSeparators(path) self.findEdit.setFocus() self.pathLabel.setText(self.path) self.statusLabel.clear() self.filesListWidget.clear() self.fileCount = 0 self.filenamesForWords = collections.defaultdict(set) self.commonWords = set() nofilesfound = True files = [] index = 0 for root, dirs, fnames in os.walk(str(self.path)): for name in [ name for name in fnames if name.endswith((".htm", ".html")) ]: files.append(os.path.join(root, name)) if len(files) == 1000: self.processFiles(index, files[:]) files = [] index += 1 nofilesfound = False if files: self.processFiles(index, files[:]) nofilesfound = False if nofilesfound: self.finishedIndexing() self.statusLabel.setText("No HTML files found in the given path") def processFiles(self, index, files): thread = walker.Walker(index, self.lock, files, self.filenamesForWords, self.commonWords, self) thread.indexed[str, int].connect(self.indexed) thread.finished[bool, int].connect(self.finished) thread.finished.connect(thread.deleteLater) self.walkers.append(thread) self.completed.append(False) thread.start() thread.wait(300) # Needed for Windows def find(self): word = str(self.findEdit.text()) if not word: try: self.mutex.lock() self.statusLabel.setText("Enter a word to find in files") finally: self.mutex.unlock() return try: self.mutex.lock() self.statusLabel.clear() self.filesListWidget.clear() finally: self.mutex.unlock() word = word.lower() if " " in word: word = word.split()[0] try: self.lock.lockForRead() found = word in self.commonWords finally: self.lock.unlock() if found: try: self.mutex.lock() self.statusLabel.setText("Common words like '{0}' " "are not indexed".format(word)) finally: self.mutex.unlock() return try: self.lock.lockForRead() files = self.filenamesForWords.get(word, set()).copy() finally: self.lock.unlock() if not files: try: self.mutex.lock() self.statusLabel.setText("No indexed file contains " "the word '{0}'".format(word)) finally: self.mutex.unlock() return files = [ QDir.toNativeSeparators(name) for name in sorted(files, key=str.lower) ] try: self.mutex.lock() self.filesListWidget.addItems(files) self.statusLabel.setText( "{0} indexed files contain the word '{1}'".format( len(files), word)) finally: self.mutex.unlock() def indexed(self, fname, index): try: self.mutex.lock() self.statusLabel.setText(fname) self.fileCount += 1 count = self.fileCount finally: self.mutex.unlock() if count % 25 == 0: try: self.lock.lockForRead() indexedWordCount = len(self.filenamesForWords) commonWordCount = len(self.commonWords) finally: self.lock.unlock() try: self.mutex.lock() self.filesIndexedLCD.display(count) self.wordsIndexedLCD.display(indexedWordCount) self.commonWordsLCD.display(commonWordCount) finally: self.mutex.unlock() elif count % 101 == 0: try: self.lock.lockForRead() words = self.commonWords.copy() finally: self.lock.unlock() try: self.mutex.lock() self.commonWordsListWidget.clear() self.commonWordsListWidget.addItems(sorted(words)) finally: self.mutex.unlock() def finished(self, completed, index): done = False if self.walkers: self.completed[index] = True if all(self.completed): try: self.mutex.lock() self.statusLabel.setText("Finished") done = True finally: self.mutex.unlock() else: try: self.mutex.lock() self.statusLabel.setText("Finished") done = True finally: self.mutex.unlock() if done: self.finishedIndexing() def reject(self): if not all(self.completed): self.stopWalkers() self.finishedIndexing() else: self.accept() def closeEvent(self, event=None): self.stopWalkers() def finishedIndexing(self): self.filesIndexedLCD.display(self.fileCount) self.wordsIndexedLCD.display(len(self.filenamesForWords)) self.commonWordsLCD.display(len(self.commonWords)) self.pathButton.setEnabled(True) QApplication.processEvents() # Needed for Windows
class MainWindow(QMainWindow): htmlReady = pyqtSignal(str) def __init__(self, app): QMainWindow.__init__(self) self.install_directory = os.getcwd() self.app = app self.book = None self.last_book = "" self.filename = "" self._part_is_new = False self.tread_running = False self.initTheme() self.createUi() self.createMenus() self.createStatusBar() self.readSettings() self.text_edit.textChanged.connect(self.textChanged) def initTheme(self): settings = QSettings(QSettings.IniFormat, QSettings.UserScope, QCoreApplication.organizationName(), QCoreApplication.applicationName()) self.theme = settings.value("theme", "Fusion") hilite_color = settings.value( "hiliteColor", self.palette().highlight().color().name()) self.changeStyle(self.theme, hilite_color) def showEvent(self, event): if self.last_book: self.loadBook(self.last_book) def changeStyle(self, theme, hilite_color): self.theme = theme if theme == "DarkFusion": QApplication.setStyle(DarkFusion(hilite_color)) else: QApplication.setStyle(QStyleFactory.create(theme)) pal = self.app.palette() pal.setColor(QPalette.Highlight, QColor(hilite_color)) self.app.setPalette(pal) def createUi(self): self.content = Expander("Content", ":/images/parts.svg") self.images = Expander("Images", ":/images/images.svg") self.settings = Expander("Settings", ":/images/settings.svg") self.setWindowTitle(QCoreApplication.applicationName() + " " + QCoreApplication.applicationVersion()) vbox = QVBoxLayout() vbox.addWidget(self.content) vbox.addWidget(self.images) vbox.addWidget(self.settings) vbox.addStretch() self.content_list = QListWidget() self.content_list.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) content_box = QVBoxLayout() content_box.addWidget(self.content_list) self.item_edit = QLineEdit() self.item_edit.setMaximumHeight(0) self.item_edit.editingFinished.connect(self.editItemFinished) self.item_anim = QPropertyAnimation(self.item_edit, "maximumHeight".encode("utf-8")) content_box.addWidget(self.item_edit) button_layout = QHBoxLayout() plus_button = FlatButton(":/images/plus.svg") self.edit_button = FlatButton(":/images/edit.svg") self.trash_button = FlatButton(":/images/trash.svg") self.up_button = FlatButton(":/images/up.svg") self.down_button = FlatButton(":/images/down.svg") self.trash_button.enabled = False self.up_button.enabled = False self.down_button.enabled = False button_layout.addWidget(plus_button) button_layout.addWidget(self.up_button) button_layout.addWidget(self.down_button) button_layout.addWidget(self.edit_button) button_layout.addWidget(self.trash_button) content_box.addLayout(button_layout) self.content.addLayout(content_box) plus_button.clicked.connect(self.addPart) self.trash_button.clicked.connect(self.dropPart) self.up_button.clicked.connect(self.partUp) self.down_button.clicked.connect(self.partDown) self.edit_button.clicked.connect(self.editPart) self.image_list = QListWidget() self.image_list.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) image_box = QVBoxLayout() image_box.addWidget(self.image_list) image_button_layout = QHBoxLayout() image_plus_button = FlatButton(":/images/plus.svg") self.image_trash_button = FlatButton(":/images/trash.svg") self.image_trash_button.enabled = False image_button_layout.addWidget(image_plus_button) image_button_layout.addWidget(self.image_trash_button) image_box.addLayout(image_button_layout) self.images.addLayout(image_box) image_plus_button.clicked.connect(self.addImage) self.image_trash_button.clicked.connect(self.dropImage) scroll_content = QWidget() scroll_content.setLayout(vbox) scroll = QScrollArea() scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) scroll.setWidget(scroll_content) scroll.setWidgetResizable(True) scroll.setMaximumWidth(200) scroll.setMinimumWidth(200) self.navigationdock = QDockWidget("Navigation", self) self.navigationdock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.navigationdock.setWidget(scroll) self.navigationdock.setObjectName("Navigation") self.addDockWidget(Qt.LeftDockWidgetArea, self.navigationdock) self.splitter = QSplitter() self.text_edit = MarkdownEdit() self.text_edit.setFont(QFont("Courier", 11)) self.preview = QWebEngineView() self.preview.setMinimumWidth(300) self.setWindowTitle(QCoreApplication.applicationName()) self.splitter.addWidget(self.text_edit) self.splitter.addWidget(self.preview) self.setCentralWidget(self.splitter) self.content.expanded.connect(self.contentExpanded) self.images.expanded.connect(self.imagesExpanded) self.settings.expanded.connect(self.settingsExpanded) self.settings.clicked.connect(self.openSettings) self.content_list.currentItemChanged.connect(self.partSelectionChanged) self.image_list.currentItemChanged.connect(self.imageSelectionChanged) self.image_list.itemDoubleClicked.connect(self.insertImage) self.text_edit.undoAvailable.connect(self.undoAvailable) self.text_edit.redoAvailable.connect(self.redoAvailable) self.text_edit.copyAvailable.connect(self.copyAvailable) QApplication.clipboard().dataChanged.connect(self.clipboardDataChanged) def undoAvailable(self, value): self.undo_act.setEnabled(value) def redoAvailable(self, value): self.redo_act.setEnabled(value) def copyAvailable(self, value): self.copy_act.setEnabled(value) self.cut_act.setEnabled(value) def clipboardDataChanged(self): md = QApplication.clipboard().mimeData() self.paste_act.setEnabled(md.hasText()) def openSettings(self): dlg = Settings(self.book) dlg.exec() if dlg.saved: self.setWindowTitle(QCoreApplication.applicationName() + " - " + self.book.name) def addPart(self): self.item_edit.setText("") self.item_edit.setFocus() self.item_anim.setStartValue(0) self.item_anim.setEndValue(23) self.item_anim.start() self._part_is_new = True def addItem(self): text = self.item_edit.text() if text: if not self.book.getPart(text): self.book.addPart(text) self.loadBook(self.last_book) def updateItem(self): text = self.item_edit.text() if text: if not self.book.getPart(text): self.book.updatePart( self.content_list.currentItem().data(1).name, text) self.loadBook(self.last_book) def editItemFinished(self): if self._part_is_new: self.addItem() else: self.updateItem() self.item_anim.setStartValue(23) self.item_anim.setEndValue(0) self.item_anim.start() def editPart(self): item = self.content_list.currentItem().data(1).name self.item_edit.setText(item) self.item_edit.setFocus() self.item_anim.setStartValue(0) self.item_anim.setEndValue(23) self.item_anim.start() self._part_is_new = False def dropPart(self): item = self.content_list.currentItem().data(1).name msgBox = QMessageBox() msgBox.setText("You are about to delete the part <i>" + item + "</i>") msgBox.setInformativeText("Do you really want to delete the item?") msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel) msgBox.setDefaultButton(QMessageBox.Cancel) ret = msgBox.exec() if ret == QMessageBox.Yes: self.book.dropPart(item) self.loadBook(self.last_book) def addImage(self): fileName = "" dialog = QFileDialog() dialog.setFileMode(QFileDialog.AnyFile) dialog.setNameFilter("Image Files(*.png *.jpg *.bmp *.gif);;All (*)") dialog.setWindowTitle("Load Image") dialog.setOption(QFileDialog.DontUseNativeDialog, True) dialog.setAcceptMode(QFileDialog.AcceptOpen) if dialog.exec_(): fileName = dialog.selectedFiles()[0] del dialog if not fileName: return base = os.path.basename(fileName) if not os.path.exists( os.path.join(self.book.source_path, "images", base)): copy(fileName, os.path.join(self.book.source_path, "images")) item = QListWidgetItem() item.setText(Path(fileName).name) item.setData( 1, os.path.join(self.book.source_path, "images", Path(fileName).name)) self.image_list.addItem(item) def dropImage(self): item = self.image_list.currentItem() image = item.data(1) filename = os.path.join(self.book.source_path, "parts", image) os.remove(filename) self.loadImages() def loadImages(self): self.image_list.clear() for root, dir, files in os.walk( os.path.join(self.book.source_path, "images")): for file in files: filename = os.path.join(self.book.source_path, "images", Path(file).name) item = QListWidgetItem() item.setToolTip("Doubleclick image to insert into text") item.setText(Path(file).name) item.setData(1, filename) self.image_list.addItem(item) def partUp(self): pos = self.content_list.currentRow() item = self.content_list.takeItem(pos) self.content_list.insertItem(pos - 1, item) self.content_list.setCurrentRow(pos - 1) self.book.partUp(item.data(1).name) def partDown(self): pos = self.content_list.currentRow() item = self.content_list.takeItem(pos) self.content_list.insertItem(pos + 1, item) self.content_list.setCurrentRow(pos + 1) self.book.partDown(item.data(1).name) def partSelectionChanged(self, item): if item: part = item.data(1) self.filename = os.path.join(self.book.source_path, "parts", part.src) with open(self.filename, "r") as f: self.text_edit.setText(f.read()) self.trash_button.enabled = True self.up_button.enabled = self.content_list.currentRow() > 0 self.down_button.enabled = self.content_list.currentRow( ) < self.content_list.count() - 1 self.edit_button.enabled = True else: self.text_edit.setText("") self.trash_button.enabled = False self.up_button.enabled = False self.down_button.enabled = False self.edit_button.enabled = False def imageSelectionChanged(self, item): if item: self.image_trash_button.enabled = True else: self.image_trash_button.enabled = False def contentExpanded(self, value): if value: self.images.setExpanded(False) self.settings.setExpanded(False) def imagesExpanded(self, value): if value: self.content.setExpanded(False) self.settings.setExpanded(False) def appearanceExpanded(self, value): if value: self.content.setExpanded(False) self.images.setExpanded(False) self.settings.setExpanded(False) def settingsExpanded(self, value): if value: self.content.setExpanded(False) self.images.setExpanded(False) def closeEvent(self, event): self.writeSettings() event.accept() def createMenus(self): new_icon = QIcon(QPixmap(":/images/new.svg")) open_icon = QIcon(QPixmap(":/images/open.svg")) book_icon = QIcon(QPixmap(":/images/book.svg")) bold_icon = QIcon(QPixmap(":/images/bold.svg")) italic_icon = QIcon(QPixmap(":/images/italic.svg")) image_icon = QIcon(QPixmap(":/images/image.svg")) table_icon = QIcon(QPixmap(":/images/table.svg")) new_act = QAction(new_icon, "&New", self) new_act.setShortcuts(QKeySequence.New) new_act.setStatusTip("Create a new ebook project") new_act.triggered.connect(self.newFile) new_act.setToolTip("Create new ebook project") open_act = QAction(open_icon, "&Open", self) open_act.setShortcuts(QKeySequence.Open) open_act.setStatusTip("Open an existing ebook project") open_act.triggered.connect(self.open) open_act.setToolTip("Open an existing ebook project") book_act = QAction(book_icon, "&Create Book", self) book_act.setShortcuts(QKeySequence.SaveAs) book_act.setStatusTip("Create an ebook") book_act.triggered.connect(self.create) book_act.setToolTip("Create an ebook") pdf_act = QAction("Create &PDF", self) pdf_act.setStatusTip("Create PDF") pdf_act.setToolTip("Create PDF") pdf_act.triggered.connect(self.pdfExport) settings_act = QAction("&Settings", self) settings_act.setStatusTip("Open settings dialog") settings_act.triggered.connect(self.settingsDialog) settings_act.setToolTip("Open settings dialog") exit_act = QAction("E&xit", self) exit_act.setShortcuts(QKeySequence.Quit) exit_act.setStatusTip("Exit the application") exit_act.triggered.connect(self.close) self.undo_act = QAction("Undo", self) self.undo_act.setShortcut(QKeySequence.Undo) self.undo_act.setEnabled(False) self.undo_act.triggered.connect(self.doUndo) self.redo_act = QAction("Redo", self) self.redo_act.setShortcut(QKeySequence.Redo) self.redo_act.setEnabled(False) self.undo_act.triggered.connect(self.doRedo) self.cut_act = QAction("Cu&t", self) self.cut_act.setShortcut(QKeySequence.Cut) self.cut_act.triggered.connect(self.doCut) self.cut_act.setEnabled(False) self.copy_act = QAction("&Copy", self) self.copy_act.setShortcut(QKeySequence.Copy) self.copy_act.triggered.connect(self.doCopy) self.copy_act.setEnabled(False) self.paste_act = QAction("&Paste", self) self.paste_act.setShortcut(QKeySequence.Paste) self.paste_act.triggered.connect(self.doPaste) self.paste_act.setEnabled(False) bold_act = QAction(bold_icon, "Bold", self) bold_act.setShortcut(Qt.CTRL + Qt.Key_B) bold_act.triggered.connect(self.bold) italic_act = QAction(italic_icon, "Italic", self) italic_act.setShortcut(Qt.CTRL + Qt.Key_I) italic_act.triggered.connect(self.italic) image_act = QAction(image_icon, "Image", self) image_act.setShortcut(Qt.CTRL + Qt.Key_G) image_act.triggered.connect(self.insertImage) image_act.setToolTip("Insert an image") table_act = QAction(table_icon, "Table", self) table_act.setShortcut(Qt.CTRL + Qt.Key_T) table_act.triggered.connect(self.insertTable) table_act.setToolTip("Insert a table") about_act = QAction("&About", self) about_act.triggered.connect(self.about) about_act.setStatusTip("Show the application's About box") file_menu = self.menuBar().addMenu("&File") file_menu.addAction(new_act) file_menu.addAction(open_act) file_menu.addAction(book_act) file_menu.addAction(pdf_act) file_menu.addSeparator() file_menu.addAction(settings_act) file_menu.addSeparator() file_menu.addAction(exit_act) edit_menu = self.menuBar().addMenu("&Edit") edit_menu.addAction(self.undo_act) edit_menu.addAction(self.redo_act) edit_menu.addSeparator() edit_menu.addAction(self.cut_act) edit_menu.addAction(self.copy_act) edit_menu.addAction(self.paste_act) format_menu = self.menuBar().addMenu("&Format") format_menu.addAction(bold_act) format_menu.addAction(italic_act) insert_menu = self.menuBar().addMenu("&Insert") insert_menu.addAction(image_act) insert_menu.addAction(table_act) help_menu = self.menuBar().addMenu("&Help") help_menu.addAction(about_act) file_tool_bar = self.addToolBar("File") file_tool_bar.addAction(new_act) file_tool_bar.addAction(open_act) file_tool_bar.addAction(book_act) format_tool_bar = self.addToolBar("Format") format_tool_bar.addAction(bold_act) format_tool_bar.addAction(italic_act) insert_toolbar = self.addToolBar("Insert") insert_toolbar.addAction(image_act) insert_toolbar.addAction(table_act) def doUndo(self): self.text_edit.undo() def doRedo(self): self.text_edit.redo() def doCut(self): self.text_edit.cut() def doCopy(self): self.text_edit.copy() def doPaste(self): self.text_edit.paste() def insertImage(self): if not self.book: QMessageBox.warning(self, QCoreApplication.applicationName(), "You have to load or create a book first!") return if not self.filename: QMessageBox.warning( self, QCoreApplication.applicationName(), "You have to select part from the book content first!") return if self.image_list.count() == 0: QMessageBox.warning( self, QCoreApplication.applicationName(), "You have to add an image to the image list first!") return if not self.image_list.currentItem(): QMessageBox.warning( self, QCoreApplication.applicationName(), "You have to select an image from the image list first!") return item = self.image_list.currentItem() filename = item.text() cursor = self.text_edit.textCursor() pos = cursor.position() base = filename.split(".")[0].replace("_", "-") cursor.insertText("![" + base + "](../images/" + filename + " \"" + base + "\")") cursor.setPosition(pos) self.text_edit.setTextCursor(cursor) def insertTable(self): cursor = self.text_edit.textCursor() pos = cursor.position() cursor.insertText( "| alignLeft | alignCenter | unAligned | alignRight |\n" "| :--- | :---: | --- | ---: |\n" "| cell a | cell b | cell c | cell d |\n" "| cell e | cell f | cell g | cell h |\n") cursor.setPosition(pos) self.text_edit.setTextCursor(cursor) def createStatusBar(self): self.statusBar().showMessage("Ready") def about(self): QMessageBox.about( self, "About " + QCoreApplication.applicationName(), "EbookCreator\nVersion: " + QCoreApplication.applicationVersion() + "\n(C) Copyright 2019 Olaf Japp. All rights reserved.\n\nThis program is provided AS IS with NO\nWARRANTY OF ANY KIND, INCLUDING THE\nWARRANTY OF DESIGN, MERCHANTABILITY AND\nFITNESS FOR A PATICULAR PURPOSE." ) def newFile(self): dlg = ProjectWizard(self.install_directory, parent=self) dlg.loadBook.connect(self.loadBook) dlg.show() def open(self): fileName = "" dialog = QFileDialog() dialog.setFileMode(QFileDialog.AnyFile) dialog.setNameFilter("EbookCreator (book.qml);;All (*)") dialog.setWindowTitle("Load Ebook") dialog.setOption(QFileDialog.DontUseNativeDialog, True) dialog.setAcceptMode(QFileDialog.AcceptOpen) dialog.setDirectory(os.path.join(self.install_directory, "sources")) if dialog.exec_(): fileName = dialog.selectedFiles()[0] del dialog if not fileName: return self.loadBook(fileName) def writeSettings(self): settings = QSettings(QSettings.IniFormat, QSettings.UserScope, QCoreApplication.organizationName(), QCoreApplication.applicationName()) settings.setValue("geometry", self.saveGeometry()) settings.setValue("lastBook", self.last_book) def readSettings(self): settings = QSettings(QSettings.IniFormat, QSettings.UserScope, QCoreApplication.organizationName(), QCoreApplication.applicationName()) geometry = settings.value("geometry", QByteArray()) self.last_book = settings.value("lastBook") if not geometry: availableGeometry = QApplication.desktop().availableGeometry(self) self.resize(availableGeometry.width() / 3, availableGeometry.height() / 2) self.move((availableGeometry.width() - self.width()) / 2, (availableGeometry.height() - self.height()) / 2) else: self.restoreGeometry(geometry) def bold(self): if not self.filename: QMessageBox.warning( self, QCoreApplication.applicationName(), "You have to select part from the book content first!") return cursor = self.text_edit.textCursor() pos = cursor.position() if not cursor.hasSelection(): cursor.select(QTextCursor.WordUnderCursor) cursor.insertText("**" + cursor.selectedText() + "**") cursor.setPosition(pos + 2) self.text_edit.setTextCursor(cursor) def italic(self): if not self.filename: QMessageBox.warning( self, QCoreApplication.applicationName(), "You have to select part from the book content first!") return cursor = self.text_edit.textCursor() pos = cursor.position() if not cursor.hasSelection(): cursor.select(QTextCursor.WordUnderCursor) cursor.insertText("*" + cursor.selectedText() + "*") cursor.setPosition(pos + 1) self.text_edit.setTextCursor(cursor) def create(self): filename = "" dialog = QFileDialog() dialog.setFileMode(QFileDialog.AnyFile) dialog.setNameFilter("ePub3 (*.epub);;All (*)") dialog.setWindowTitle("Create Ebook") dialog.setOption(QFileDialog.DontUseNativeDialog, True) dialog.setAcceptMode(QFileDialog.AcceptSave) dialog.setDirectory(self.install_directory) dialog.setDefaultSuffix("epub") if dialog.exec_(): filename = dialog.selectedFiles()[0] del dialog if not filename: return QApplication.setOverrideCursor(Qt.WaitCursor) createEpub(filename, self.book, self) QApplication.restoreOverrideCursor() def loadStatusChanged(self, status): if status == 1: self.book = self.component.create() if self.book is not None: self.book.setFilename(self.last_book) self.book.setWindow(self) else: for error in self.component.errors(): print(error.toString()) return self.content_list.clear() for part in self.book.parts: item = QListWidgetItem() item.setText(part.name) item.setData(1, part) self.content_list.addItem(item) self.loadImages() self.setWindowTitle(QCoreApplication.applicationName() + " - " + self.book.name) self.content.setExpanded(True) self.content_list.setCurrentRow(0) elif status == 3: for error in self.component.errors(): print(error.toString()) return def loadBook(self, filename): self.last_book = filename self.filename = "" engine = QQmlEngine() self.component = QQmlComponent(engine) self.component.statusChanged.connect(self.loadStatusChanged) self.component.loadUrl(QUrl.fromLocalFile(filename)) def settingsDialog(self): dlg = SettingsDialog(self.theme, self.palette().highlight().color().name(), parent=self) dlg.exec() if dlg.theme != self.theme or dlg.hilite_color != self.palette( ).highlight().color().name(): settings = QSettings(QSettings.IniFormat, QSettings.UserScope, QCoreApplication.organizationName(), QCoreApplication.applicationName()) settings.setValue("theme", dlg.theme) settings.setValue("hiliteColor", dlg.hilite_color) msgBox = QMessageBox() msgBox.setText("Please restart the app to change the theme!") msgBox.exec() def textChanged(self): if self.filename: with open(self.filename, "w") as f: f.write(self.text_edit.toPlainText()) self.lock = Lock() with self.lock: if not self.tread_running: self.tread_running = True self.htmlReady.connect(self.previewReady) thread = Thread(target=self.createHtml, args=(self.text_edit.toPlainText(), )) thread.daemon = True thread.start() def previewReady(self, html): self.preview.setHtml( html, baseUrl=QUrl( Path(os.path.join(self.book.source_path, "parts", "index.html")).as_uri())) self.htmlReady.disconnect() with self.lock: self.tread_running = False def createHtml(self, text): html = "<html>\n<head>\n" html += "<link href=\"../css/pastie.css\" rel=\"stylesheet\" type=\"text/css\"/>\n" html += "<link href=\"../css/stylesheet.css\" rel=\"stylesheet\" type=\"text/css\"/>\n" html += "</head>\n<body>\n" html += markdown(text, html4tags=False, extras=[ "fenced-code-blocks", "wiki-tables", "tables", "header-ids" ]) html += "\n</body>\n</html>" html = addLineNumbers(html) self.htmlReady.emit(html) def pdfExport(self): p = PdfExport("test.pdf", self.book, self.statusBar())
class MainProcess(MainProcessUI): def __init__(self): super(MainProcess, self).__init__() # use for convert self.__elev_ptn = re.compile(r"(.*),(.*)") self.__file_ptn = re.compile(r"FG-GML-(.*)-(.*)-(.*)-.*(A|B|C)-.*.xml") self.__sp_ptn = re.compile( r"<gml:startPoint>(.*) (.*)</gml:startPoint>") self.__lc_ptn = re.compile( r"<gml:lowerCorner>.* (.*)</gml:lowerCorner>") self.__uc_ptn = re.compile( r"<gml:upperCorner>(.*) .*</gml:upperCorner>") self.__load_cnt = 0 self.__cnt = 0 self.__sp = 0 self.__missing = False self.__lat_for_file0 = set() self.__lon_for_file0 = set() # lat self.__lat_index = 0 self.__lat_diff = 0.008333333 # lon self.__lon_index = 0 # Later: I will support 10m DEM and more self.__width = 225 self.__height = 150 self.__size = self.__width * self.__height self.__db_dir, self.__xml_dir = Ds().getDir() #self.lc_lats, self.lc_lons, self.uc_lats, self.uc_lons = [], [], [], [] #self.__getLcNumArray() self.__que = deque() # DnD self.setAcceptDrops(True) # path list self.__xmlPathList = [] self.FileList = QListWidget() self.initUI() def onClicked(self): if len(self.__xmlPathList) == 0: return # start sub_process self.notifier = Notifier() self.thread = Thread(self.notifier, "convert") self.notifier.moveToThread(self.thread) self.notifier.notify.connect(self.__clickedStart, type=Qt.DirectConnection) self.thread.start() self.thread.finished.connect(self.__finishSubProcess) def __clickedStart(self): table_tmp = 0 cnt = 0 check_file_tmp = -1 xmlPathList = self.__xmlPathList[:] for index, xml_path in enumerate(xmlPathList): match_file = Search(self.__file_ptn, basename(xml_path)) # When the same file of DEM5A and DEM5B exists in the list check_for_DEM_x = Group(match_file, 1) + '-' + Group( match_file, 2) + '-' + Group(match_file, 3) if index + 1 != len( xmlPathList) and check_for_DEM_x in xmlPathList[index + 1]: if self.__checkNextFileDEMType(xmlPathList[index + 1]): continue table = Group(match_file, 1) + Group(match_file, 2) if table != table_tmp: if self.__lat_for_file0 and self.__lon_for_file0: self.__MinLatLonIntoDB(min(self.__lat_for_file0), min(self.__lon_for_file0)) table_tmp = table self.__convertReset() check_file_tmp = -1 cnt = 0 check_file = int(Group(match_file, 3)) check_file_diff = check_file - check_file_tmp if check_file_diff > 1: self.__missing = True check_file_tmp = check_file conn = sqlite3.connect(self.__db_dir + "testterrain6.db") cur = conn.cursor() sql = cur.execute self.__table_name = "fg" + table sql(""" CREATE TABLE IF NOT EXISTS {} (elevation double(5, 2), lat_index int, lon_index int, lc_lat_num int, lc_lon_num int, uc_lat_num int, uc_lon_num int);""".format(self.__table_name)) query = """INSERT INTO {} (elevation, lat_index, lon_index, lc_lat_num, lc_lon_num, uc_lat_num, uc_lon_num) VALUES (?, ?, ?, ?, ?, ?, ?);""".format(self.__table_name) cnt += check_file_diff if self.__missing: for _ in range(check_file_diff - 1): elevation, lats, lons, lc_lats, lc_lons, uc_lats, uc_lons = self.__GetMissing( ) dataset = [ x for x in zip(elevation, lats, lons, lc_lats, lc_lons, uc_lats, uc_lons) ] cur.executemany(query, dataset) conn.commit() self.__missing = False self.__getStartPoint(xml_path) elevation, lats, lons, lc_lats, lc_lons, uc_lats, uc_lons = self.__convert( xml_path) dataset = [ x for x in zip(elevation, lats, lons, lc_lats, lc_lons, uc_lats, uc_lons) ] cur.executemany(query, dataset) conn.commit() if xml_path == xmlPathList[-1]: self.__MinLatLonIntoDB(min(self.__lat_for_file0), min(self.__lon_for_file0)) match = Search(self.__file_ptn, xml_path) file_name = int(Group(match, 3)) if file_name != 99: for _ in range(99 - file_name): elevation, lats, lons, lc_lats, lc_lons, uc_lats, uc_lons = self.__GetMissing( ) dataset = [ x for x in zip(elevation, lats, lons, lc_lats, lc_lons, uc_lats, uc_lons) ] cur.executemany(query, dataset) conn.commit() cur.close() conn.close() print(cnt) def __finishSubProcess(self): #QMessageBox.information(self, "Message", "Finished convert", QMessageBox.Ok) print("fin") def __checkNextFileDEMType(self, next_file): match_file = self.__file_ptn.search(os.path.basename(next_file)) DEM_type = match_file.group(4) if DEM_type in ('A', 'B', 'C'): return True return False def __GetMissing(self): elev = [SEALEVEL - 1000] * self.__size self.__convertLoad() lc_lats, lc_lons, uc_lats, uc_lons = self.__getLcUcNumArray() lats = [self.__lat_index] * self.__size lons = [self.__lon_index] * self.__size self.__lon_index += 1 return (elev, lats, lons, lc_lats, lc_lons, uc_lats, uc_lons) def __convertReset(self): self.__load_cnt = 0 self.__cnt = 0 self.__lat_index = 0 self.__lon_index = 0 self.__lat_for_file0 = set() self.__lon_for_file0 = set() def __convert(self, filename): with open(filename, "r", encoding="utf-8_sig") as f: elevations = [] for line in f.readlines(): lc_match = self.__lc_ptn.search(line) if lc_match: lc_lon = float(lc_match.group(1)) self.__lon_for_file0.add(lc_lon) lc_match = 0 uc_match = self.__uc_ptn.search(line) if uc_match: uc_lat = float(uc_match.group(1)) lc_lat = uc_lat - self.__lat_diff self.__lat_for_file0.add(lc_lat) self.__MinLatLonIntoDB(lc_lat, lc_lon) uc_match = 0 self.__convertLoad() el_match = self.__elev_ptn.search(line) if el_match: typ, data = line.split(",") data = float(data) if typ in (u"データなし", u"海水面", u"内水面"): data = -1000.0 elevations.append(data) lc_lats, lc_lons, uc_lats, uc_lons = self.__getLcUcNumArray() new_elevations = self.__adjustArray(elevations) lats = [self.__lat_index] * self.__size lons = [self.__lon_index] * self.__size #print(self.lat_index, self.lon_index, self.load_cnt) self.__lon_index += 1 f.close() return (new_elevations, lats, lons, lc_lats, lc_lons, uc_lats, uc_lons) def __convertLoad(self): if self.__load_cnt >= 10: self.__cnt += 1 self.__lat_index += 1 self.__load_cnt = 0 self.__lon_index = 0 self.__load_cnt += 1 def __getLcUcNumArray(self): lc_lats, lc_lons, uc_lats, uc_lons = [], [], [], [] lat_num = self.__height + self.__height * self.__cnt lon_num = (self.__load_cnt - 1) * self.__width #print(lat_num, lon_num) cnt = 0 while cnt != self.__size: if lon_num > self.__load_cnt * self.__width - 1: lon_num = (self.__load_cnt - 1) * self.__width lat_num -= 1 lc_lats.append(lat_num - 1) lc_lons.append(lon_num) uc_lats.append(lat_num) uc_lons.append(lon_num + 1) lon_num += 1 cnt += 1 return (lc_lats, lc_lons, uc_lats, uc_lons) def __getStartPoint(self, filename): with open(filename, "r", encoding="utf-8_sig") as f: while True: line = f.readline() sp_match = self.__sp_ptn.search(line) if sp_match: sp_lon, sp_lat = int(sp_match.group(1)), int( sp_match.group(2)) self.__sp = sp_lat * self.__width + sp_lon return def __adjustArray(self, array): return [-1000.0] * self.__sp + array + (self.__size - self.__sp - len(array)) * [-1000.0] def __MinLatLonIntoDB(self, lc_lat, lc_lon): conn = sqlite3.connect(self.__db_dir + "latlon.db") cur = conn.cursor() sql = cur.execute if self.__inTable(conn, cur): cur.close() conn.close() return sql("CREATE TABLE IF NOT EXISTS {}(lat double(3, 9), lon double(3, 9))" .format(self.__table_name)) sql("INSERT INTO {} (lat, lon) VALUES('{}', '{}')".format( self.__table_name, lc_lat, lc_lon)) conn.commit() cur.close() conn.close() def __inTable(self, conn, cur): cur.execute("select * from sqlite_master where type = 'table';") while True: v = cur.fetchone() if v == None: break if self.__table_name in v: return True return False def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dropEvent(self, event): urls = event.mimeData().urls() for url in urls: path = adjustSep(url.toLocalFile()) tmp = path.split('.') if path in self.__xmlPathList: QMessageBox.information(self, 'Warning', 'This file already in.', QMessageBox.Ok) continue if len(tmp) != 1: if inExtension(path): self.FileList.addItem(basename(path)) self.__xmlPathList.append(path) else: self.__addDir(tmp[0]) def __addDir(self, item): for roots, dirs, files in os.walk(item): for f in files: if inExtension(f): self.FileList.addItem(basename(f)) self.__xmlPathList.append(adjustSep(roots + '/' + f)) if len(dirs) != 0: for d in dirs: self.__que.append(d) return self.__addDir(self.__que.popleft()) try: if len(self.__que) != 0: return self.__addDir(self.__que.popleft()) except: return def clickedClear(self): self.FileList.clear() self.__xmlPathList = [] def clickedExit(self): exit() def clickedAdd(self): filename, ok = QFileDialog.getOpenFileNames(self, "Open File", self.__xml_dir, filter="xml file (*.xml)") # if clicked cancel if not ok: return for f in filename: f = adjustSep(f) if f in self.__xmlPathList: continue self.FileList.addItem(basename(f)) self.__xmlPathList.append(self.replaceSep(f)) def clickedSort(self): self.__xmlPathList.sort(key=lambda x: basename(x)) self.FileList.sortItems() def clickedDelete(self): try: row = self.FileList.row(self.FileList.selectedItems()[0]) self.__xmlPathList.pop(row) self.FileList.takeItem(row) except: pass
class class_search(QLineEdit): get_api_doc_signal = pyqtSignal(str) def __init__(self): super().__init__() # 设置下拉列表的属性 sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) p = self.geometry() self.lv_class = QListWidget() self.lv_class.setParent(self) self.lv_class.setAttribute(Qt.WA_ShowWithoutActivating) self.lv_class.setSizePolicy(sizePolicy) self.lv_class.setFixedSize(QSize(500, 500)) self.lv_class.setWindowFlags(Qt.Tool | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) self.textChanged.connect(self.on_le_class_currentTextChanged) self.adding_lv_class_flag = False def on_le_class_currentTextChanged(self): cur_class = self.text() if len(cur_class) < 3: return # self.lv_class.setFixedSize(QSize(500,500)) p = self.geometry() self.lv_class.move(QPoint(p.x(), p.y() + 50)) result_list = [] for c in self.class_list: if cur_class.lower() in c["name"].lower(): result_list.append(c) self.popup_class_search_result(result_list) # 弹出类的索引列表 def popup_class_search_result(self, result_list): path_list = [item["path"] for item in result_list] if path_list: self.lv_class.setVisible(True) self.adding_lv_class_flag = True self.lv_class.clear() # 弹窗默认选中空白项,避免on_lv_class_currentItemChanged总是莫名选中选中第一项的bug blank_item = QListWidgetItem("") self.lv_class.addItem(blank_item) self.lv_class.setCurrentItem(blank_item) self.lv_class.addItems(path_list) self.adding_lv_class_flag = False # 查询选中的类的文档 def get_doc(self): if not self.adding_lv_class_flag: cur_item = self.lv_class.currentItem() # print("previous",previous.text()) # if not cur_item : # print("currentText",self.lv_class.currentText()) if cur_item and cur_item.text() != "": print("cur_item.text():" + cur_item.text()) self.get_api_doc_signal.emit(cur_item.text()) # self.lv_class.setFixedSize(QSize(500,0)) self.lv_class.setVisible(False) def keyReleaseEvent(self, event): key = event.key() if key == Qt.Key_Down: self.lv_class.setCurrentRow(self.lv_class.currentRow() + 1) elif key == Qt.Key_Up: self.lv_class.setCurrentRow(self.lv_class.currentRow() - 1) elif key == Qt.Key_Home: self.lv_class.setCurrentRow(1) elif key == Qt.Key_End: self.lv_class.setCurrentRow(self.lv_class.count() - 1) elif key == Qt.Key_PageUp: row = self.lv_class.currentRow() - 5 if row > -1: self.lv_class.setCurrentRow(row) elif key == Qt.Key_PageDown: row = self.lv_class.currentRow() + 5 if row < self.lv_class.count(): self.lv_class.setCurrentRow(row) elif key == Qt.Key_Right or key == Qt.Key_Return: self.get_doc() elif key == Qt.Key_Escape: self.lv_class.setVisible(False)
class DriverWindow(QWidget): def __init__(self): super().__init__() # layouts groupbox_hdd_info = QGroupBox('HDD info') groupbox_system_info = QGroupBox('System info') groupbox_send_data_info = QGroupBox('Send') groupbox_app_info = QGroupBox('App info') grid_hdd_info = QGridLayout() grid_system_info = QGridLayout() grid_send_data_info = QGridLayout() grid_app_info = QGridLayout() groupbox_hdd_info.setLayout(grid_hdd_info) groupbox_system_info.setLayout(grid_system_info) groupbox_send_data_info.setLayout(grid_send_data_info) groupbox_app_info.setLayout(grid_app_info) grid_layout = QGridLayout() grid_layout.addWidget(groupbox_hdd_info) grid_layout.addWidget(groupbox_system_info) grid_layout.addWidget(groupbox_send_data_info) grid_layout.addWidget(groupbox_app_info) # driver name self.driver_name_label = QLabel('Driver name') self.driver_name_text = QLineEdit() self.driver_name_text.setPlaceholderText('enter your name') # car name self.car_name_label = QLabel('Car name') self.car_name_text = QLineEdit() self.car_name_text.setText(my_hdd.car_name) self.car_name_text.setReadOnly(True) # HDD id self.hdd_id_label = QLabel('HDD Serial Number') self.hdd_id_text = QLineEdit() self.hdd_id_text.setText(my_hdd.hdd_serial_number) self.hdd_id_text.setReadOnly(True) # number of sessions self.count_sessions_label = QLabel('Number of sessions') self.count_sessions_text = QLineEdit() self.count_sessions_text.setText(str(my_hdd.number_of_session)) self.count_sessions_text.setReadOnly(True) # sessions range # start_date self.start_date_label = QLabel('First & Last Session') self.start_date_text = QLineEdit() self.start_date_text.setText(my_hdd.start_date) self.start_date_text.setReadOnly(True) ##end date self.end_date_label = QLabel('Last Session') self.end_date_text = QLineEdit() self.end_date_text.setText(my_hdd.end_date) self.end_date_text.setReadOnly(True) # list of sessions self.sessions_list_label = QLabel('sessions') self.sessions_list_text = QListWidget() self.sessions_list_text.addItems([x for x in my_hdd.session_list]) # sessions_list_text.setReadOnly(True) # AWB number self.airwaybill_label = QLabel('AWB name') self.airwaybill_text = QLineEdit() self.airwaybill_text.setPlaceholderText( 'enter AWB number if you have it') # code self.generated_code_label = QLabel('Generated code') self.generated_code_text = QLineEdit() self.generated_code = code_generator( my_hdd.car_name, current_date_for_gc.replace('_', '-'), 3) self.generated_code_text.setText(self.generated_code) self.generated_code_text.setReadOnly(True) # vpn self.vpn_label = QLabel('VPN') self.vpn_connection_label = QLabel('checking...') # hdd status health self.hdd_health_status_label = QLabel('HDD Health status') self.check_hdd_health_status_label = QLabel('Add hdd to check') self.notes = QPlainTextEdit() self.notes.setPlaceholderText("driver's notes") # hdds # 1 self.hdd_1_label = QLabel() self.hdd_1_hddid_label = QLabel() self.hdd_1_start_date_label = QLabel() self.hdd_1_end_date_label = QLabel() self.hdd_1_num_sessions_label = QLabel() self.hdd_1_icon_label = QLabel() # 2 self.hdd_2_label = QLabel() self.hdd_2_hddid_label = QLabel() self.hdd_2_start_date_label = QLabel() self.hdd_2_end_date_label = QLabel() self.hdd_2_num_sessions_label = QLabel() self.hdd_2_icon_label = QLabel() # 3 self.hdd_3_label = QLabel() self.hdd_3_hddid_label = QLabel() self.hdd_3_start_date_label = QLabel() self.hdd_3_end_date_label = QLabel() self.hdd_3_num_sessions_label = QLabel() self.hdd_3_icon_label = QLabel() # 4 self.hdd_4_number = QLabel() self.hdd_4_label = QLabel() self.hdd_4_hddid_label = QLabel() self.hdd_4_start_date_label = QLabel() self.hdd_4_end_date_label = QLabel() self.hdd_4_num_sessions_label = QLabel() self.hdd_4_icon_label = QLabel() # 5 self.hdd_5_number = QLabel() self.hdd_5_label = QLabel() self.hdd_5_hddid_label = QLabel() self.hdd_5_start_date_label = QLabel() self.hdd_5_end_date_label = QLabel() self.hdd_5_num_sessions_label = QLabel() self.hdd_5_icon_label = QLabel() # version self.version = QLabel('Version') self.version_label = QLabel(version) # add_button add_button = QPushButton('Add new HDD to the shipment', self) add_button.setIcon(QtGui.QIcon('images/HDD-512.png')) add_button.setIconSize(QtCore.QSize(50, 50)) add_button.clicked.connect(self.add_new_hdd) add_button.setToolTip('Add ndew Hdd to the queue') add_button.setStyleSheet('color:blue') add_button.setStyleSheet("background-color:#B7D9FF") # button button = QPushButton('Send HDD information', self) button.setIcon(QtGui.QIcon('images/send.png')) button.setIconSize(QtCore.QSize(65, 65)) button.clicked.connect(self.show_popup) button.setToolTip('Send information to database') button.setStyleSheet('color:green') button.setStyleSheet("background-color:#CCFFCC;") self.message_window = QMessageBox() self.message_window.setWindowTitle('Info') self.txt_review = QLineEdit() self.txt_review.setPlaceholderText('enter your opinion') # # GRID # # grid_layout = QGridLayout() # grid_layout.setSpacing(3) # # # Drivers name grid_hdd_info.addWidget(self.driver_name_label, 1, 0) # column 1, row 0 grid_hdd_info.addWidget(self.driver_name_text, 1, 1) # # # Car name grid_hdd_info.addWidget(self.car_name_label, 2, 0) # column 1, row 0 grid_hdd_info.addWidget(self.car_name_text, 2, 1) # # # HDD ID grid_hdd_info.addWidget(self.hdd_id_label, 3, 0) grid_hdd_info.addWidget(self.hdd_id_text, 3, 1) # column 2, row 1 to column 5 row 1 # # # number of sessions grid_hdd_info.addWidget(self.count_sessions_label, 4, 0) grid_hdd_info.addWidget(self.count_sessions_text, 4, 1) # column 2, row 1 to column 5 row 1 # # # sessions range grid_hdd_info.addWidget(self.start_date_label, 5, 0) grid_hdd_info.addWidget(self.start_date_text, 5, 1) grid_hdd_info.addWidget(self.end_date_label, 6, 0) grid_hdd_info.addWidget(self.end_date_text, 6, 1) # # # awb number grid_hdd_info.addWidget(self.airwaybill_label, 7, 0) grid_hdd_info.addWidget(self.airwaybill_text, 7, 1) # generated code grid_hdd_info.addWidget(self.generated_code_label, 8, 0) grid_hdd_info.addWidget(self.generated_code_text, 8, 1) # # list of sessions grid_hdd_info.addWidget(self.sessions_list_text, 1, 3, 8, 3) # hdd health status grid_hdd_info.addWidget(self.hdd_health_status_label, 9, 0) grid_hdd_info.addWidget(self.check_hdd_health_status_label, 9, 1) # vpn grid_system_info.addWidget(self.vpn_label, 0, 0) grid_system_info.addWidget(self.vpn_connection_label, 0, 1, 1, 3) # notes grid_system_info.addWidget(self.notes, 1, 0, 1, 4) # # # hdds grid_send_data_info.addWidget(self.hdd_1_label, 1, 0) grid_send_data_info.addWidget(self.hdd_1_hddid_label, 1, 2) grid_send_data_info.addWidget(self.hdd_1_start_date_label, 1, 4) grid_send_data_info.addWidget(self.hdd_1_end_date_label, 1, 5) grid_send_data_info.addWidget(self.hdd_1_num_sessions_label, 1, 8) grid_send_data_info.addWidget(self.hdd_1_icon_label, 1, 9) grid_send_data_info.addWidget(self.hdd_2_label, 2, 0) grid_send_data_info.addWidget(self.hdd_2_hddid_label, 2, 2) grid_send_data_info.addWidget(self.hdd_2_start_date_label, 2, 4) grid_send_data_info.addWidget(self.hdd_2_end_date_label, 2, 5) grid_send_data_info.addWidget(self.hdd_2_num_sessions_label, 2, 8) grid_send_data_info.addWidget(self.hdd_2_icon_label, 2, 9) grid_send_data_info.addWidget(self.hdd_3_label, 3, 0) grid_send_data_info.addWidget(self.hdd_3_hddid_label, 3, 2) grid_send_data_info.addWidget(self.hdd_3_start_date_label, 3, 4) grid_send_data_info.addWidget(self.hdd_3_end_date_label, 3, 5) grid_send_data_info.addWidget(self.hdd_3_num_sessions_label, 3, 8) grid_send_data_info.addWidget(self.hdd_3_icon_label, 3, 9) grid_send_data_info.addWidget(self.hdd_4_label, 4, 0) grid_send_data_info.addWidget(self.hdd_4_hddid_label, 4, 2) grid_send_data_info.addWidget(self.hdd_4_start_date_label, 4, 4) grid_send_data_info.addWidget(self.hdd_4_end_date_label, 4, 5) grid_send_data_info.addWidget(self.hdd_4_num_sessions_label, 4, 8) grid_send_data_info.addWidget(self.hdd_4_icon_label, 4, 9) grid_send_data_info.addWidget(self.hdd_5_label, 5, 0) grid_send_data_info.addWidget(self.hdd_5_hddid_label, 5, 2) grid_send_data_info.addWidget(self.hdd_5_start_date_label, 5, 4) grid_send_data_info.addWidget(self.hdd_5_end_date_label, 5, 5) grid_send_data_info.addWidget(self.hdd_5_num_sessions_label, 5, 8) grid_send_data_info.addWidget(self.hdd_5_icon_label, 5, 9) # # # version # grid_app_info.addWidget(self.version, 0, 0) grid_app_info.addWidget(self.version_label, 0, 1, 1, 3) # # # button grid_send_data_info.addWidget(add_button, 0, 0, 1, 10) grid_send_data_info.addWidget(button, 8, 0, 1, 10) # creating hdd's labels self.hdd_labels = [ [ self.hdd_1_label, self.hdd_1_hddid_label, self.hdd_1_start_date_label, self.hdd_1_end_date_label, self.hdd_1_num_sessions_label, self.hdd_1_icon_label ], [ self.hdd_2_label, self.hdd_2_hddid_label, self.hdd_2_start_date_label, self.hdd_2_end_date_label, self.hdd_2_num_sessions_label, self.hdd_2_icon_label ], [ self.hdd_3_label, self.hdd_3_hddid_label, self.hdd_3_start_date_label, self.hdd_3_end_date_label, self.hdd_3_num_sessions_label, self.hdd_3_icon_label ], [ self.hdd_4_label, self.hdd_4_hddid_label, self.hdd_4_start_date_label, self.hdd_4_end_date_label, self.hdd_4_num_sessions_label, self.hdd_4_icon_label ], [ self.hdd_5_label, self.hdd_5_hddid_label, self.hdd_5_start_date_label, self.hdd_5_end_date_label, self.hdd_5_num_sessions_label, self.hdd_5_icon_label ] ] # Qtimer timer = QTimer(self) timer.timeout.connect(self.refresh_hdd) timer.start(1200) timer2 = QTimer(self) timer2.timeout.connect(self.check_vpn_connection) timer2.start(10000) self.setLayout(grid_layout) self.setGeometry( 500, # x 400, # y 600, 640) self.setWindowTitle('HDD tracker') self.setWindowIcon(QtGui.QIcon('send.png')) hdds = [] def check_vpn_connection(self): check_vpn(self.vpn_connection_label) def refresh_hdd(self): find_disks() new_hdd = create_hdd_object() if len(new_hdd.session_list) == 0: self.sessions_list_text.clear() self.car_name_text.setStyleSheet('color:red') self.start_date_text.setStyleSheet('color:red') self.end_date_text.setStyleSheet('color:red') self.hdd_id_text.setStyleSheet('color:red') self.count_sessions_text.setStyleSheet('color:red') self.count_sessions_text.setText(str(new_hdd.number_of_session)) self.car_name_text.setText(str(new_hdd.car_name)) self.hdd_id_text.setText('') self.start_date_text.setText(str(new_hdd.start_date)) self.end_date_text.setText(str(new_hdd.end_date)) self.sessions_list_text.clear() self.sessions_list_text.addItems([x for x in new_hdd.session_list]) self.generated_code_text.setText(self.generated_code) else: try: obj = parase_crystaldisk() except FileNotFoundError: logging.info(f'{current_date}No DiskInfo.txt of file is empty') self.car_name_text.setStyleSheet('color:darkgreen') self.start_date_text.setStyleSheet('color:darkgreen') self.end_date_text.setStyleSheet('color:darkgreen') self.generated_code_text.setStyleSheet('color:darkgreen') self.hdd_id_text.setStyleSheet('color:darkgreen') self.count_sessions_text.setStyleSheet('color:darkgreen') self.generated_code_text.setStyleSheet('color:blue') self.count_sessions_text.setText(str(new_hdd.number_of_session)) self.car_name_text.setText(str(new_hdd.car_name)) self.hdd_id_text.setText( str(obj['disks'][len(obj['disks']) - 1] ['Serial Number'])) # added last element from disk's list self.start_date_text.setText(str(new_hdd.start_date)) self.end_date_text.setText(str(new_hdd.end_date)) self.sessions_list_text.clear() self.sessions_list_text.addItems([x for x in new_hdd.session_list]) if self.generated_code == 'no hdd': self.generated_code = code_generator( new_hdd.car_name, current_date_for_gc.replace('_', '-'), 3) self.generated_code_text.setText(self.generated_code) print(self.generated_code) print(current_date) number_of_hdd = 0 # creating new shipment template new_shipment = { 'id': None, 'status': 'prepared', 'create_date': current_date, "DHL_data": { "awb": "-", "event_date": "-", "event_desc": "-", "event_signatory": "-", "event_time": "-", "ref_id": "-", "ship_date": "-", "ship_to": "-", "shipper_name": "-", "status_code": "-" }, "self_delivery_data": { "location": "-", "comment": "-" }, 'driver': '-', 'disks': [], "previous_status": "-", "status_history": { "prepared": current_date, "sent": "-", "self_delivered": "-", "delivered": "-", "received": "-" }, "_rid": "FNx-AOmVdYQjAAAAAAAAAA==", "_self": "dbs/FNx-AA==/colls/FNx-AOmVdYQ=/docs/FNx-AOmVdYQjAAAAAAAAAA==/", "_etag": "\"85005be0-0000-0d00-0000-5fa95b4a0000\"", "_attachments": "attachments/", "_ts": 1604934474 } @pyqtSlot() def add_new_hdd(self): filePath = f'{__location__}\DiskInfo.txt' modificationTime = get_last_file_modified_data(filePath) # executing CrystalDiskInfo logging.info(f'\n{current_date}\nExecuting Cristal Disk info') subprocess.run([ "powershell", "start", f"'{__location__}\DiskInfo64.exe'", "-ArgumentList", "/CopyExit ", "-Verb", "Runas" ]) logging.info(f'\n{current_date}\nExecuting Cristal Disk Info done') modificationTimeNew = get_last_file_modified_data(filePath) # comparing last modification date to make sure that file is already updated while modificationTime == modificationTimeNew: modificationTimeNew = get_last_file_modified_data(filePath) print(Fore.YELLOW + "Waiting for DiskInfo.txt update") time.sleep(0.5) print('') print(Fore.GREEN + 'Success') time.sleep(0.5) print(Fore.GREEN + "DiskInfo.txt has been updated") obj = parase_crystaldisk() logging.info( f'\n{current_date}\nDiskInfo.txt has been updated\nObject: {obj}') new_hdd = create_hdd_object() self.new_shipment['id'] = self.generated_code self.new_shipment['driver'] = self.driver_name_text.text() new_disk = { 'carname': new_hdd.car_name, 'hdd_serial_number': obj['disks'][len(obj['disks']) - 1]['Serial Number'], 'health_status': '-', 'sessions_from': new_hdd.start_date, 'sessions_to': new_hdd.end_date, 'sessions': new_hdd.session_list } try: new_disk['health_status'] = obj['disks'][len(obj['disks']) - 1]['Health Status'] heatlh_status(self.check_hdd_health_status_label, obj['disks'][len(obj['disks']) - 1]['Health Status']) except: pass if new_disk not in self.new_shipment[ 'disks'] and new_disk['carname'] != 'no hdd': print(Fore.GREEN + 'HDD has been just added to the shipment\n') self.new_shipment['disks'].append(new_disk) self.hdd_labels[self.number_of_hdd][0].setText(new_hdd.car_name) self.hdd_labels[self.number_of_hdd][0].setStyleSheet( 'background-color: #00ff00') self.hdd_labels[self.number_of_hdd][1].setText( new_disk['hdd_serial_number']) self.hdd_labels[self.number_of_hdd][1].setStyleSheet( 'background-color: #00ff00') self.hdd_labels[self.number_of_hdd][2].setText(new_hdd.start_date) self.hdd_labels[self.number_of_hdd][2].setStyleSheet( 'background-color: #00ff00') self.hdd_labels[self.number_of_hdd][3].setText(new_hdd.end_date) self.hdd_labels[self.number_of_hdd][3].setStyleSheet( 'background-color: #00ff00') self.hdd_labels[self.number_of_hdd][4].setText( str(new_hdd.number_of_session)) self.hdd_labels[self.number_of_hdd][4].setStyleSheet( 'background-color: #00ff00') self.hdd_labels[self.number_of_hdd][4].setAlignment( QtCore.Qt.AlignCenter) self.hdd_labels[self.number_of_hdd][5].setPixmap( (QtGui.QPixmap('images/hdd.png'))) self.number_of_hdd += 1 print(f"Reading data from: {obj['disks'][1]['Drive Letter']}") logging.info( f'\n{current_date}\nAdded new disk to the shipment\nNew disk: {new_disk}\n' ) else: print(Fore.RED + 'Wrong') print(Fore.RED + "Error you cannot add HDD") logging.info(f'\n{current_date}\nCannot add HDD') self.message_window.setText( 'HDD already exists in the shipment or no HDD') x = self.message_window.exec() @pyqtSlot() def show_popup(self): res = QMessageBox.question(self, 'MessageBox', 'Are you sure?', QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel) if res == QMessageBox.Yes: self.on_click() else: print('No') @pyqtSlot() def on_click(self): if len(self.driver_name_text.text()) == 0: self.message_window.setText('Add driver name') x = self.message_window.exec() else: try: print(Fore.GREEN + 'Sending') self.new_shipment['driver'] = self.driver_name_text.text() _, scode = send_to_heimdall(self.new_shipment) logging.info( f'\n{current_date}\nShipement has been saved to db\nShipement: {self.new_shipment}\n' ) self.message_window.setText( f'Success! Your code: {self.generated_code}') x = self.message_window.exec() save_last_ship_to_file( self.new_shipment['disks'][0]['carname'], current_date, self.generated_code) print(Fore.GREEN + "Success") print(Fore.GREEN + "Shipment has been added to DB") print(Fore.GREEN + "Ship's info has been added to lastship.txt as well") print(Fore.WHITE + "DONT FORGET YOUR CODE!") except: scode = '400' logging.info(f'\n{current_date}\nCan send data to db') self.message_window.setText( 'No connection or shipement exists in database') x = self.message_window.exec()
class MainWin(QWidget): def __init__(self) -> None: super().__init__() self.setWindowTitle(win_title) self.resize(*win_size) self.save_dir = "Modified" self.create_widgets() self.layout_widgets() self.connects() def create_widgets(self): """Создаем виджеты для приложения""" self.lb_image = QLabel("Здесь будет картинка") self.btn_dir = QPushButton("Папка") self.lw_files = QListWidget() self.btn_left = QPushButton("Лево") self.btn_right = QPushButton("Право") self.btn_flip = QPushButton("Зеркало") self.btn_sharp = QPushButton("Резкость") self.btn_bw = QPushButton("Ч/б") def layout_widgets(self): """ Привязка виджетов к линиям и главному окну""" row = QHBoxLayout() col1 = QVBoxLayout() col2 = QVBoxLayout() col1.addWidget(self.btn_dir) col1.addWidget(self.lw_files) col2.addWidget(self.lb_image, 95) row_tools = QHBoxLayout() row_tools.addWidget(self.btn_left) row_tools.addWidget(self.btn_right) row_tools.addWidget(self.btn_flip) row_tools.addWidget(self.btn_sharp) row_tools.addWidget(self.btn_bw) col2.addLayout(row_tools) row.addLayout(col1, 20) row.addLayout(col2, 80) self.setLayout(row) def chooseWorkdir(self): """Функция выбора рабочей папки""" self.workdir = QFileDialog.getExistingDirectory() def filter(self): """Функция отбора имён файлов по расширениям""" self.filenames = [] for filename in os.listdir(self.workdir): for ext in extensions: if filename.lower().endswith(ext): self.filenames.append(filename) def showFilenamesList(self): """Функция-обработчик нажатия на кнопку «Папка»""" self.chooseWorkdir() if self.workdir: self.filter() self.lw_files.clear() self.lw_files.addItems(sorted(self.filenames)) def loadImage(self): """Метод открывает файл и создает объект Image""" self.image_path = os.path.join(self.workdir, self.filename) self.image = Image.open(self.image_path) def showImage(self): self.lb_image.hide() pixmapimage = QPixmap(self.image_path) w, h = self.lb_image.width(), self.lb_image.height() pixmapimage = pixmapimage.scaled(w, h, Qt.KeepAspectRatio) self.lb_image.setPixmap(pixmapimage) self.lb_image.show() def showChosenImage(self): """Функция показывает картинку при выборе файла""" if self.lw_files.selectedItems(): self.filename = self.lw_files.selectedItems()[0].text() self.loadImage() self.showImage() def createModified(self): path = os.path.join(self.workdir, self.save_dir) if not (os.path.exists(path) and os.path.isdir(path)): os.mkdir(path) def saveImage(self): """сохраняет копию файла в подпапке Modified""" self.createModified() new_image_path = os.path.join(self.workdir, self.save_dir, self.filename) self.image.save(new_image_path) def do_bw(self): self.image = self.image.convert('L') self.saveImage() self.image_path = os.path.join(self.workdir, self.save_dir, self.filename) self.showImage() def connects(self): """Метод для привязки событий к обработчикам""" self.btn_dir.clicked.connect(self.showFilenamesList) self.lw_files.itemClicked.connect(self.showChosenImage) self.btn_bw.clicked.connect(self.do_bw)
class VictimWidget(AsyncWidget): on_host_click = pyqtSignal(Host) def __init__(self, interface: Interface, parent=None): super().__init__(parent) self.interface = interface self.list_elements = [] self.setup() def setup(self): self.create_title() self.create_list() self.create_clear_button() self.create_layout() def create_title(self): self.title = QLabel('Victims') self.title.setAlignment(Qt.AlignmentFlag.AlignCenter) def create_list(self): self.host_list = QListWidget() self.host_list.itemDoubleClicked.connect( lambda item: self.on_host_click.emit( item.data(Qt.ItemDataRole.UserRole))) def create_clear_button(self): self.clear_button = QPushButton('Clear') self.clear_button.setIcon(QIcon('assets/clear.svg')) self.clear_button.clicked.connect(self.host_list.clear) self.clear_button.clicked.connect(lambda: self.list_elements.clear()) def create_layout(self): layout = QVBoxLayout(self) layout.addWidget(self.title) layout.addWidget(self.clear_button) layout.addWidget(self.host_list) layout.setAlignment(Qt.AlignmentFlag.AlignCenter) def update_list(self): # remove duplicates self.list_elements = list(set(self.list_elements)) self.list_elements = sort_hosts(self.list_elements) self.host_list.clear() for host in self.list_elements: item = QListWidgetItem(self.host_list) item.setData(Qt.ItemDataRole.DisplayRole, host.ip_address) item.setData(Qt.ItemDataRole.UserRole, host) def get_hosts(self): return self.list_elements def set_hosts(self, hosts: list[Host]): self.list_elements = hosts self.update_list() def add_host(self, host: Host): self.list_elements.append(host) self.update_list() hosts = property(get_hosts, set_hosts)
def clear(self): self.__rowCode.clear() QListWidget.clear(self)
class GuiTabTemplate(QWidget): """General tab which enables import of DICOM files but also a set of distinct options such as viewing the metadata or displaying images in an external viewer and renaming folders""" def __init__(self, parent=None): super(GuiTabTemplate, self).__init__(parent) self.selected_subj_Gen = '' self.wdirTemplate = os.path.join(ROOTDIR, 'ext', 'templates') # General settings/variables/helper files needed needed at some point self.cfg = Configuration.load_config(ROOTDIR) if os.path.isdir(self.cfg['folders']['nifti']): self.niftidir = self.cfg['folders']['nifti'] else: self.niftidir = FileOperations.set_wdir_in_config(self.cfg, foldername='nifti', init=True) self.cfg['folders']['rootdir'] = ROOTDIR Configuration.save_config(ROOTDIR, self.cfg) self.lay = QHBoxLayout(self) self.tab = QWidget() # Customize tab # ============================== Tab 1 - General ============================== self.tab.layout = QHBoxLayout() self.tab.setLayout(self.tab.layout) # ------------------------- Upper left part (Folder) ------------------------- # self.FolderboxTab = QGroupBox("Directory (Templates)") self.HBoxUpperLeftTab = QVBoxLayout(self.FolderboxTab) self.dirTemplates = QLabel('wDIR: {}'.format(self.wdirTemplate)) self.HBoxUpperLeftTab.addWidget(self.dirTemplates) self.btnChangeWdir = QPushButton('Change working directory') self.btnChangeWdir.setDisabled(True) self.btnReloadFilesTab = QPushButton('Reload files') self.btnReloadFilesTab.clicked.connect(self.run_reload_files) self.HBoxUpperLeftTab.addWidget(self.btnChangeWdir) self.HBoxUpperLeftTab.addWidget(self.btnReloadFilesTab) # ------------------------- Lower left part (Processing) ------------------------- # self.ActionsTab = QGroupBox("Functions") self.HBoxLowerLeftTab = QVBoxLayout(self.ActionsTab) self.btn_new_default = QPushButton('Set new \ndefault') # self.btn_subj_details.setToolTip(setToolTips.subjectDetails()) TODO: new ToolTip needed self.btn_new_default.clicked.connect(self.redefineDefault) self.btn_viewer = QPushButton('View selected \nTemplate in viewer') # self.btn_viewer.setToolTip(setToolTips.displayFolderContent()) TODO: new ToolTip needed self.btn_viewer.clicked.connect(self.view_template) self.create_SST = QPushButton('Create Study-specific\ntemplate') # self.btn_renaming.setToolTip(setToolTips.renameFolders()) TODO: new ToolTip needed self.create_SST.clicked.connect(self.create_StudySpecificTemplate) self.HBoxLowerLeftTab.addWidget(self.btn_viewer) self.HBoxLowerLeftTab.addWidget(self.btn_new_default) self.HBoxLowerLeftTab.addWidget(self.create_SST) # -------------------- Right part (Subject list) ----------------------- # self.listbox = QGroupBox('Available subjects') self.HBoxUpperRightTab = QVBoxLayout(self.listbox) self.availableTemplates = QListWidget() self.availableTemplates.setSelectionMode(QAbstractItemView.ExtendedSelection) self.availableTemplates.itemSelectionChanged.connect(self.change_list_item) itemsTab = set(FileOperations.list_files_in_folder(self.wdirTemplate)) self.add_available_templates(self.availableTemplates, itemsTab) self.HBoxUpperRightTab.addWidget(self.availableTemplates) # Combine all Boxes for General Tab Layout self.LeftboxTab = QGroupBox() self.HBoxTabLeft = QVBoxLayout(self.LeftboxTab) self.HBoxTabLeft.addWidget(self.FolderboxTab) self.HBoxTabLeft.addStretch() self.HBoxTabLeft.addWidget(self.ActionsTab) self.tab.layout.addWidget(self.LeftboxTab) self.tab.layout.addWidget(self.listbox) self.lay.addWidget(self.tab) # ------------------------- Start with the functions for lists and buttons in this tab ------------------------- # def run_reload_files(self): """Reloads files, e.g. after renaming them""" self.cfg = Configuration.load_config(self.cfg['folders']['rootdir']) self.availableTemplates.clear() itemsTab = set(FileOperations.list_files_in_folder(self.wdirTemplate)) self.add_available_templates(self.availableTemplates, itemsTab) def change_list_item(self): """function intended to provide the item which is selected. As different tabs have a similar functioning, it is coded in a way that the sender is identified""" if self.sender() == self.availableTemplates: items = self.availableTemplates.selectedItems() self.selected_subj_Gen = [] for i in range(len(items)): self.selected_subj_Gen.append(str(self.availableTemplates.selectedItems()[i].text())) def add_available_templates(self, sending_list, items, msg="yes"): """adds the available templates in the working directory into the items list; an error message is dropped if none available""" if len(items) == 0 and msg == "yes": buttonReply = QMessageBox.question(self, "No templates in folder", "There are no templates available " "in the directory: {}. Please make sure that at least the default " "ones are in this directory! Retry?".format(os.path.join(ROOTDIR, 'ext', 'templates')), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if buttonReply == QMessageBox.Yes: self.run_reload_files() else: sending_list.addItems(list(items)) myFont = QtGui.QFont() myFont.setItalic(True) out = sending_list.findItems(os.path.basename(self.cfg['folders']['default_template']), QtCore.Qt.MatchExactly) out[0].setFont(myFont) def redefineDefault(self): """redefines which template is set as default on the right list and in the cfg-file""" if not self.selected_subj_Gen: Output.msg_box(text="No template selected. Please indicate new default one.", title="No data selected") return elif len(self.selected_subj_Gen) > 1: Output.msg_box(text="Please select only one image as default.", title="Too many templates selected") return else: default_template = [FileOperations.return_full_filename(self.wdirTemplate, x) for x in self.selected_subj_Gen] self.cfg['folders']['default_template'] = default_template[0] Configuration.save_config(ROOTDIR, self.cfg) self.run_reload_files() def create_StudySpecificTemplate(self): """Renames all folders with a similar prefix; After that manual reloading is necessary""" print('not yet implemented') def view_template(self): """this function opens a list dialog and enables selecting NIFTI files for e.g. check the content (identical function as in GUITabPreprocessANTs.py.""" if not self.selected_subj_Gen: Output.msg_box(text="No image selected. Please indicate image(s) to load.", title="No templates selected") return else: template_list = [FileOperations.return_full_filename(self.wdirTemplate, x) for x in self.selected_subj_Gen] Imaging.load_imageviewer('itk-snap', template_list) # to-date, only itk-snap available. could be changed
class ViewWidget(QWidget): tab_active = pyqtSignal() def __init__(self, iface, dock_widget: QDockWidget) -> None: super().__init__() self.iface = iface self.dock_widget = dock_widget self.vbox = QVBoxLayout() self.create_variable_selector() self.create_time_selector() self.create_extra_dim_selector() self.create_interp_input() self.create_dataset_selector() self.setLayout(self.vbox) self.datasets = {} # type: Dict[str, Dataset] self.selected_dataset = None # type: Optional[str] self.selected_variable = {} # type: Dict[str,str] self.selected_time = {} # type: Dict[str,int] self.selected_extra_dim = {} # type: Dict[Tuple[str,str],int] self.pause_replace_layer = False def create_variable_selector(self) -> None: self.variable_selector = QListWidget() self.variable_selector.currentItemChanged.connect( self.on_variable_selected) hbox = QHBoxLayout() hbox.addWidget(self.variable_selector) self.vbox.addLayout(hbox) def create_time_selector(self) -> None: self.time_label = QLabel('Time: N/A') self.time_selector = QSlider(Qt.Horizontal) self.time_selector.setSingleStep(1) self.time_selector.setPageStep(1) self.time_selector.setMinimum(0) self.time_selector.valueChanged.connect(self.on_time_selected) self.vbox.addWidget(self.time_label) self.vbox.addWidget(self.time_selector) def create_extra_dim_selector(self) -> None: self.extra_dim_label = QLabel('N/A:') self.extra_dim_selector = QComboBox() self.extra_dim_selector.currentIndexChanged.connect( self.on_extra_dim_selected) hbox = QHBoxLayout() hbox.addWidget(self.extra_dim_label) hbox.addWidget(self.extra_dim_selector) hbox.setContentsMargins(0, 0, 0, 0) self.extra_dim_container = QWidget() self.extra_dim_container.setLayout(hbox) self.extra_dim_container.setHidden(True) self.vbox.addWidget(self.extra_dim_container) def create_interp_input(self) -> None: grid = QGridLayout() self.interp_vert_selector = add_grid_combobox(grid, 0, 'Vertical Variable') self.interp_input = add_grid_lineedit(grid, 1, 'Desired Level', QDoubleValidator( 0.0, 10000.0, 50), required=True) self.interp_input.returnPressed.connect(self.on_interp_btn_clicked) btn = QPushButton('Interpolate') btn.clicked.connect(self.on_interp_btn_clicked) grid.addWidget(btn, 2, 1) self.interp_container = QGroupBox('Interpolate Vertical Level') self.interp_container.setCheckable(True) self.interp_container.setChecked(False) self.interp_container.toggled.connect(self.on_interp_toggled) self.interp_container.setLayout(grid) self.interp_container.setHidden(True) self.vbox.addWidget(self.interp_container) def create_dataset_selector(self) -> None: dataset_label = QLabel('Dataset:') self.dataset_selector = QComboBox() self.dataset_selector.currentIndexChanged.connect( self.on_dataset_selected) hbox = QHBoxLayout() hbox.addWidget(dataset_label) hbox.addWidget(self.dataset_selector) self.vbox.addLayout(hbox) def add_dataset(self, path: str) -> None: variables = gis4wrf.core.get_supported_wrf_nc_variables(path) times = gis4wrf.core.get_wrf_nc_time_steps(path) extra_dims = gis4wrf.core.get_wrf_nc_extra_dims(path) dataset_name = os.path.basename(path) is_new_dataset = dataset_name not in self.datasets self.datasets[dataset_name] = Dataset(dataset_name, path, variables, times, extra_dims) if is_new_dataset: self.dataset_selector.addItem(dataset_name, dataset_name) self.select_dataset(dataset_name) def select_dataset(self, dataset_name: str) -> None: index = self.dataset_selector.findData(dataset_name) self.dataset_selector.setCurrentIndex(index) def init_variable_selector(self) -> None: dataset = self.dataset selected = self.selected_variable.get(dataset.name) self.variable_selector.clear() for var_name, variable in sorted(dataset.variables.items(), key=lambda v: v[1].label): item = QListWidgetItem(variable.label) item.setData(Qt.UserRole, var_name) self.variable_selector.addItem(item) if var_name == selected: item.setSelected(True) if selected is None: self.extra_dim_container.hide() def init_time_selector(self) -> None: dataset = self.dataset self.time_selector.setMaximum(len(dataset.times) - 1) selected_time = self.selected_time.get(dataset.name, 0) self.select_time(selected_time) # force label update in case the index didn't change during dataset change self.on_time_selected(selected_time) def select_time(self, index: int) -> None: self.time_selector.setValue(index) def init_extra_dim_selector(self) -> None: dataset = self.dataset variable = self.variable extra_dim_name = variable.extra_dim_name if extra_dim_name is None: self.extra_dim_container.hide() return # prevent double layer replace, already happens in on_variable_selected() self.pause_replace_layer = True extra_dim = dataset.extra_dims[extra_dim_name] selected_extra_dim = self.selected_extra_dim.get( (dataset.name, extra_dim_name), 0) self.extra_dim_label.setText(extra_dim.label + ':') self.extra_dim_selector.clear() for step in extra_dim.steps: self.extra_dim_selector.addItem(step) self.extra_dim_selector.setCurrentIndex(selected_extra_dim) self.extra_dim_container.show() self.pause_replace_layer = False def init_interp_input(self, dataset_init: bool) -> None: if dataset_init: self.interp_vert_selector.clear() has_vert = False for variable in sorted(self.dataset.variables.values(), key=lambda v: v.label): if variable.extra_dim_name != 'bottom_top': continue has_vert = True self.interp_vert_selector.addItem(variable.label, variable.name) if not has_vert: self.extra_dim_container.setEnabled(True) self.interp_container.hide() else: variable = self.variable extra_dim_name = variable.extra_dim_name if extra_dim_name != 'bottom_top': self.interp_container.hide() return self.interp_container.show() def on_dataset_selected(self, index: int) -> None: self.init_variable_selector() self.init_time_selector() self.init_interp_input(True) previous_dataset = self.selected_dataset if previous_dataset is not None: gis4wrf.plugin.geo.remove_group(previous_dataset) self.selected_dataset = self.dataset_name def on_variable_selected(self, current: Optional[QListWidgetItem], previous: Optional[QListWidgetItem]) -> None: if current is None: return dataset = self.dataset var_name = current.data(Qt.UserRole) assert var_name == self.var_name self.selected_variable[dataset.name] = var_name self.init_extra_dim_selector() self.init_interp_input(False) self.replace_variable_layer() self.select_time_band_in_variable_layers() def on_time_selected(self, index: int) -> None: dataset = self.dataset self.selected_time[dataset.name] = index self.time_label.setText('Time: ' + dataset.times[index]) self.select_time_band_in_variable_layers() def on_extra_dim_selected(self, index: int) -> None: if index == -1: # happens when clearing the dropdown entries return variable = self.variable extra_dim_name = variable.extra_dim_name self.selected_extra_dim[(self.dataset_name, extra_dim_name)] = index self.replace_variable_layer() self.select_time_band_in_variable_layers() def on_interp_toggled(self, enabled: True) -> None: self.extra_dim_container.setEnabled(not enabled) self.replace_variable_layer() def on_interp_btn_clicked(self) -> None: self.replace_variable_layer() self.select_time_band_in_variable_layers() def replace_variable_layer(self) -> None: if self.pause_replace_layer: return if self.interp_enabled and self.interp_level is None: return dataset = self.dataset variable = self.variable extra_dim_index = self.extra_dim_index interp_level = self.interp_level interp_vert_name = self.interp_vert_name if interp_level is not None: extra_dim_index = None uri, dispose = gis4wrf.core.convert_wrf_nc_var_to_gdal_dataset( dataset.path, variable.name, extra_dim_index, interp_level, interp_vert_name) layer = gis4wrf.plugin.geo.load_layers( [(uri, variable.label, variable.name)], group_name=dataset.name, visible=True)[0] dispose_after_delete(layer, dispose) def select_time_band_in_variable_layers(self) -> None: dataset = self.dataset time_idx = self.time_index layers = gis4wrf.plugin.geo.get_raster_layers_in_group(dataset.name) for layer in layers: var_name = layer.shortName() if var_name in dataset.variables: gis4wrf.plugin.geo.switch_band(layer, time_idx) @property def dataset_name(self) -> str: return self.dataset_selector.currentData() @property def var_name(self) -> str: return self.variable_selector.currentItem().data(Qt.UserRole) @property def time_index(self) -> int: return self.time_selector.value() @property def extra_dim_index(self) -> Optional[int]: if self.variable.extra_dim_name is None: return None index = self.extra_dim_selector.currentIndex() assert index != -1 return index @property def interp_enabled(self): return self.interp_container.isVisible( ) and self.interp_container.isChecked() @property def interp_vert_name(self): if not self.interp_enabled: return None return self.interp_vert_selector.currentData() @property def interp_level(self) -> Optional[float]: if not self.interp_enabled: return None if not self.interp_input.is_valid(): return None return self.interp_input.value() @property def dataset(self) -> Dataset: return self.datasets[self.dataset_name] @property def variable(self) -> WRFNetCDFVariable: return self.dataset.variables[self.var_name]
class CommonDoublePanelWidget(DoublePanelWidget): def __init__(self, parent, label=''): super().__init__(parent) self.secondary_label = label self.secondary_labels = [] self.reach_name = '' self.qlw_variables = QListWidget() self.qlw_secondary_list = QListWidget() self.qcbx_reaches = QComboBox() self.create_layout() self.on_show() def on_show(self): super().on_show() if len(self.qlw_variables.selectedItems()) == 1: self.axes.set_ylabel(self.qlw_variables.selectedItems()[0].text()) else: self.axes.set_ylabel('Valeur') def fill_reach_list(self): self.qcbx_reaches.clear() for reach_name in self.parent.data.model.keys(): self.qcbx_reaches.addItem(reach_name) def fill_variables_list(self): self.qlw_variables.clear() for name in self.parent.data.variable_names: self.qlw_variables.addItem(name) def fill_secondary_list(self): self.qlw_secondary_list.clear() for label in self.secondary_labels: self.qlw_secondary_list.addItem(str(label)) def create_layout(self): self.qcbx_reaches.currentIndexChanged.connect(self.reach_changed) self.qlw_variables.setSelectionMode( QAbstractItemView.ExtendedSelection) self.qlw_variables.itemSelectionChanged.connect(self.on_show) self.qlw_secondary_list.setSelectionMode( QAbstractItemView.ExtendedSelection) self.qlw_secondary_list.itemSelectionChanged.connect(self.on_show) self.qvb_options.addWidget(QLabel('River reach:')) self.qvb_options.addWidget(self.qcbx_reaches) self.qvb_options.addWidget(QLabel('Variables:')) self.qvb_options.addWidget(self.qlw_variables, 20) self.qvb_options.addWidget(QLabel(self.secondary_label)) self.qvb_options.addWidget(self.qlw_secondary_list, 20) super().create_layout() def set_default_selection(self): # Select by default first variable and first time if self.qlw_variables.count() > 0: self.qlw_variables.item(0).setSelected(True) if self.qlw_secondary_list.count() > 0: self.qlw_secondary_list.item(0).setSelected(True) def reach_changed(self): self.reach_name = self.qcbx_reaches.currentText()
class SubSheet(SimpleBlackbox): author = "DrLuke" name = "Subsheet" modulename = "subsheet" Category = ["Builtin"] placeable = True implementation = SubSheetImplementation def __init__(self, *args, **kwargs): self.ownsheet = None self.sheets = None self.selectedSheet = None self.listSheetItems = {} super(SubSheet, self).__init__(*args, **kwargs) self.propertiesWidget = QWidget() self.vlayout = QVBoxLayout() self.listWidget = QListWidget() self.listWidget.itemClicked.connect(self.listClicked) self.vlayout.addWidget(self.listWidget) self.vlayout.addItem(QSpacerItem(40, 20, QSizePolicy.Minimum, QSizePolicy.Expanding)) self.propertiesWidget.setLayout(self.vlayout) def getPropertiesWidget(self): return self.propertiesWidget def updateSheets(self): if self.sheets is not None and self.ownsheet is not None: self.listSheetItems = {} self.listWidget.clear() for sheetId in self.sheets: if not sheetId == self.ownsheet: newItem = QListWidgetItem(self.sheets[sheetId]) newItem.setToolTip(str(sheetId)) newItem.setData(Qt.UserRole, sheetId) self.listSheetItems[sheetId] = newItem self.listWidget.addItem(newItem) if sheetId == self.selectedSheet: boldFont = QFont() boldFont.setBold(True) newItem.setFont(boldFont) def listClicked(self, item): normalFont = QFont() boldFont = QFont() boldFont.setBold(True) for i in range(self.listWidget.count()): itemnormal = self.listWidget.item(i) itemnormal.setFont(normalFont) self.selectedSheet = item.data(Qt.UserRole) self.sendDataToImplementations({"subsheetid": self.selectedSheet}) item.setFont(boldFont) def serialize(self): return {"subsheetid": self.selectedSheet} def deserialize(self, data): if data is not None: if "subsheetid" in data: self.selectedSheet = data["subsheetid"] self.sendDataToImplementations({"subsheetid": self.selectedSheet}) def selectedChanged(self, state): if state: self.mainRect.setPen(QPen(Qt.red)) else: self.mainRect.setPen(QPen(Qt.blue)) def defineIO(self): self.addInput(execType, "execInit", "Execute Init") self.addInput(execType, "execLoop", "Execute Loop") self.addOutput(execType, "ExecInitOut", "Init Done") self.addOutput(execType, "ExecLoopOut", "Loop Done")
class GlyphSetTab(QWidget): def __init__(self, parent=None): super().__init__(parent) self.name = self.tr("Glyph sets") self.defaultGlyphSetBox = QCheckBox(self.tr("Default glyph set:"), self) self.defaultGlyphSetDrop = QComboBox(self) self.defaultGlyphSetBox.toggled.connect(self.toggleGlyphSetDrop) self.glyphSetList = QListWidget(self) self.glyphSetList.setSortingEnabled(True) self.glyphSetContents = QPlainTextEdit(self) self.glyphSetList.currentItemChanged.connect( self.updateGlyphSetContents) self.glyphSetList.itemChanged.connect(self.renameGlyphSet) self._cachedName = None splitter = QSplitter(self) splitter.addWidget(self.glyphSetList) splitter.addWidget(self.glyphSetContents) self.addGlyphSetButton = QPushButton(self) self.addGlyphSetButton.setIcon(icons.i_plus()) self.addGlyphSetButton.clicked.connect(lambda: self.addGlyphSet()) self.removeGlyphSetButton = QPushButton(self) self.removeGlyphSetButton.setIcon(icons.i_minus()) self.removeGlyphSetButton.clicked.connect(self.removeGlyphSet) self.importButton = QPushButton(self.tr("Import"), self) importMenu = QMenu(self) importMenu.addAction(self.tr("Import from Current Font"), self.importFromCurrentFont) self.importButton.setMenu(importMenu) self.glyphListBox = QCheckBox(self.tr("Glyph list path:"), self) self.glyphListEdit = QLineEdit(self) self.glyphListEdit.setReadOnly(True) self.glyphListButton = QPushButton(self.tr("Browse…"), self) self.glyphListButton.clicked.connect(self.getGlyphList) self.glyphListBox.toggled.connect(self.glyphListEdit.setEnabled) self.glyphListBox.toggled.connect(self.glyphListButton.setEnabled) buttonsLayout = QHBoxLayout() buttonsLayout.addWidget(self.addGlyphSetButton) buttonsLayout.addWidget(self.removeGlyphSetButton) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) buttonsLayout.addWidget(spacer) buttonsLayout.addWidget(self.importButton) firstLayout = QGridLayout() line = 0 firstLayout.addWidget(self.defaultGlyphSetBox, line, 0, 1, 2) firstLayout.addWidget(self.defaultGlyphSetDrop, line, 3, 1, 3) line += 1 firstLayout.addWidget(splitter, line, 0, 1, 6) line += 1 firstLayout.addLayout(buttonsLayout, line, 0, 1, 3) secondLayout = QHBoxLayout() secondLayout.addWidget(self.glyphListBox) secondLayout.addWidget(self.glyphListEdit) secondLayout.addWidget(self.glyphListButton) mainLayout = QVBoxLayout(self) mainLayout.addLayout(firstLayout) mainLayout.addLayout(secondLayout) self.setLayout(mainLayout) self.readSettings() def addGlyphSet(self, glyphNames=[], glyphSetName=None): if glyphSetName is None: glyphSetName = self.tr("New glyph set") if glyphSetName in self.glyphSets: index = 1 while "%s %d" % (glyphSetName, index) in self.glyphSets: index += 1 glyphSetName = "%s %d" % (glyphSetName, index) self.glyphSets[glyphSetName] = glyphNames item = QListWidgetItem(glyphSetName, self.glyphSetList) item.setFlags(item.flags() | Qt.ItemIsEditable) self.glyphSetList.setCurrentItem(item) self.glyphSetList.editItem(item) self.removeGlyphSetButton.setEnabled(True) def removeGlyphSet(self): i = self.glyphSetList.currentRow() text = self.glyphSetList.takeItem(i).text() del self.glyphSets[text] if self.glyphSetList.count() < 2: self.removeGlyphSetButton.setEnabled(False) def renameGlyphSet(self): newKey = self.glyphSetList.currentItem() if newKey is None: return newKey = newKey.text() self.glyphSets[newKey] = self.glyphSets[self._cachedName] del self.glyphSets[self._cachedName] def importFromCurrentFont(self): font = QApplication.instance().currentFont() name = f"{font.info.familyName} {font.info.styleName}" self.addGlyphSet(font.glyphOrder, name) def toggleGlyphSetDrop(self): sender = self.sender() self.defaultGlyphSetDrop.setEnabled(sender.isChecked()) def updateGlyphSetContents(self, current, previous): # store content of the textEdit in the glyphSet dict if previous is not None: glyphNames = self.glyphSetContents.toPlainText().split() self.glyphSets[previous.text()] = glyphNames # now update the text edit to current glyphSet glyphSetName = current.text() text = " ".join(self.glyphSets[glyphSetName]) self.glyphSetContents.setPlainText(text) # cache current name for renames self._cachedName = glyphSetName def getGlyphList(self): fileFormats = ( self.tr("Text file {}").format("(*.txt)"), self.tr("All files {}").format("(*.*)"), ) path, _ = QFileDialog.getOpenFileName(self, self.tr("Open File"), "", ";;".join(fileFormats)) if path: self.glyphListEdit.setText(path) def readSettings(self): defaultGlyphSet = settings.defaultGlyphSet() self.defaultGlyphSetBox.setChecked(len(defaultGlyphSet)) self.glyphSets = settings.readGlyphSets() self.defaultGlyphSetDrop.clear() self.defaultGlyphSetDrop.addItems(self.glyphSets.keys()) self.glyphSetList.clear() glyphSetNames = self.glyphSets.keys() # Normally we should be enforcing this rather decently in the interface # already if glyphSetNames: for glyphSetName in glyphSetNames: item = QListWidgetItem(glyphSetName, self.glyphSetList) item.setFlags(item.flags() | Qt.ItemIsEditable) self.glyphSetList.setCurrentRow(0) self.removeGlyphSetButton.setEnabled(len(self.glyphSets) > 1) glyphListPath = settings.glyphListPath() self.glyphListBox.setChecked(bool(glyphListPath)) self.glyphListEdit.setEnabled(bool(glyphListPath)) self.glyphListEdit.setText(glyphListPath) self.glyphListButton.setEnabled(bool(glyphListPath)) def writeSettings(self): # store content of the textEdit in the glyphSet dict glyphNames = self.glyphSetContents.toPlainText().split() currentGlyphSet = self.glyphSetList.currentItem().text() self.glyphSets[currentGlyphSet] = glyphNames settings.writeGlyphSets(self.glyphSets) if not self.defaultGlyphSetBox.isChecked(): settings.setDefaultGlyphSet(None) else: defaultGlyphSet = self.defaultGlyphSetDrop.currentText() settings.setDefaultGlyphSet(defaultGlyphSet) if not self.glyphListBox.isChecked(): settings.setGlyphListPath(None) else: glyphListPath = self.glyphListEdit.text() if glyphListPath: settings.setGlyphListPath(glyphListPath) QApplication.instance().loadGlyphList()
class CodeCompletionWidget(QFrame): def __init__(self, editor): super(CodeCompletionWidget, self).__init__( None, Qt.FramelessWindowHint | Qt.ToolTip) self._editor = editor self._revision = 0 self._block = 0 self.stack_layout = QStackedLayout(self) self.stack_layout.setContentsMargins(0, 0, 0, 0) self.stack_layout.setSpacing(0) self.completion_list = QListWidget() self.completion_list.setMinimumHeight(200) self.completion_list.setAlternatingRowColors(True) self._list_index = self.stack_layout.addWidget(self.completion_list) self._icons = {'a': resources.IMAGES['attribute'], 'f': resources.IMAGES['function'], 'c': resources.IMAGES['class'], 'm': resources.IMAGES['module']} self.cc = code_completion.CodeCompletion() self._completion_results = {} self._prefix = '' self.setVisible(False) self.source = '' self._key_operations = { Qt.Key_Up: self._select_previous_row, Qt.Key_Down: self._select_next_row, Qt.Key_PageUp: (lambda: self._select_previous_row(6)), Qt.Key_PageDown: (lambda: self._select_next_row(6)), Qt.Key_Right: lambda: None, Qt.Key_Left: lambda: None, Qt.Key_Enter: self.pre_key_insert_completion, Qt.Key_Return: self.pre_key_insert_completion, Qt.Key_Tab: self.pre_key_insert_completion, Qt.Key_Space: self.hide_completer, Qt.Key_Escape: self.hide_completer, Qt.Key_Backtab: self.hide_completer, Qt.NoModifier: self.hide_completer, Qt.ShiftModifier: self.hide_completer, } self.desktop = QApplication.instance().desktop() self.completion_list.itemClicked['QListWidgetItem*'].connect(self.pre_key_insert_completion) self._editor.document().cursorPositionChanged['const QTextCursor &'].connect(self.update_metadata) def _select_next_row(self, move=1): new_row = self.completion_list.currentRow() + move if new_row < self.completion_list.count(): self.completion_list.setCurrentRow(new_row) else: self.completion_list.setCurrentRow(0) return True def _select_previous_row(self, move=1): new_row = self.completion_list.currentRow() - move if new_row >= 0: self.completion_list.setCurrentRow(new_row) else: self.completion_list.setCurrentRow( self.completion_list.count() - move) return True def update_metadata(self, cursor): if settings.CODE_COMPLETION: if self._editor.document().revision() != self._revision and \ cursor.block().blockNumber() != self._block: source = self._editor.get_text() source = source.encode(self._editor.encoding) self.cc.analyze_file(self._editor.ID, source, self._editor.indent, self._editor.useTabs) self._revision = self._editor.document().revision() self._block = cursor.block().blockNumber() def insert_completion(self, insert, type_=ord('a')): if insert != self._prefix: closing = '' if type_ in (ord('f'), ord('c')): closing = '()' extra = len(self._prefix) - len(insert) insertion = '%s%s' % (insert[extra:], closing) self._editor.textCursor().insertText(insertion) self.hide_completer() def _get_geometry(self): cr = self._editor.cursorRect() desktop_geometry = self.desktop.availableGeometry(self._editor) point = self._editor.mapToGlobal(cr.topLeft()) cr.moveTopLeft(point) #Check new position according desktop geometry width = (self.completion_list.sizeHintForColumn(0) + self.completion_list.verticalScrollBar().sizeHint().width() + 10) height = 200 orientation = (point.y() + height) < desktop_geometry.height() if orientation: cr.moveTop(cr.bottom()) cr.setWidth(width) cr.setHeight(height) if not orientation: cr.moveBottom(cr.top()) xpos = desktop_geometry.width() - (point.x() + width) if xpos < 0: cr.moveLeft(cr.left() + xpos) return cr def complete(self, results): self.add_list_items(results) self.completion_list.setCurrentRow(0) cr = self._get_geometry() self.setGeometry(cr) self.completion_list.updateGeometries() self.show() def add_list_items(self, proposals): self.completion_list.clear() for p in proposals: self.completion_list.addItem( QListWidgetItem( QIcon( self._icons.get(p[0], resources.IMAGES['attribute'])), p[1], type=ord(p[0]))) def set_completion_prefix(self, prefix, valid=True): self._prefix = prefix proposals = [] proposals += [('m', item) for item in self._completion_results.get('modules', []) if item.startswith(prefix)] proposals += [('c', item) for item in self._completion_results.get('classes', []) if item.startswith(prefix)] proposals += [('a', item) for item in self._completion_results.get( 'attributes', []) if item.startswith(prefix)] proposals += [('f', item) for item in self._completion_results.get('functions', []) if item.startswith(prefix)] if proposals and valid: self.complete(proposals) else: self.hide_completer() def _invalid_completion_position(self): result = False cursor = self._editor.textCursor() cursor.movePosition(QTextCursor.StartOfLine, QTextCursor.KeepAnchor) selection = cursor.selectedText()[:-1].split(' ') if len(selection) == 0 or selection[-1] == '' or \ selection[-1].isdigit(): result = True return result def fill_completer(self, force_completion=False): if not force_completion and (self._editor.cursor_inside_string() or self._editor.cursor_inside_comment() or self._invalid_completion_position()): return source = self._editor.get_text() source = source.encode(self._editor.encoding) offset = self._editor.textCursor().position() results = self.cc.get_completion(source, offset) self._completion_results = results if force_completion: cursor = self._editor.textCursor() cursor.movePosition(QTextCursor.StartOfWord, QTextCursor.KeepAnchor) prefix = cursor.selectedText() else: prefix = self._editor._text_under_cursor() self.set_completion_prefix(prefix) def hide_completer(self): self._prefix = '' self.hide() def pre_key_insert_completion(self): type_ = ord('a') current = self.completion_list.currentItem() insert = current.text() if not insert.endswith(')'): type_ = current.type() self.insert_completion(insert, type_) self.hide_completer() return True def process_pre_key_event(self, event): if not self.isVisible() or self._editor.lang != "python": return False skip = self._key_operations.get(event.key(), lambda: False)() self._key_operations.get(event.modifiers(), lambda: False)() if skip is None: skip = False return skip def process_post_key_event(self, event): if not settings.CODE_COMPLETION or self._editor.lang != "python": return if self.isVisible(): source = self._editor.get_text() source = source.encode(self._editor.encoding) offset = self._editor.textCursor().position() prefix, valid = self.cc.get_prefix(source, offset) self.set_completion_prefix(prefix, valid) self.completion_list.setCurrentRow(0) force_completion = (event.key() == Qt.Key_Space and event.modifiers() == Qt.ControlModifier) if event.key() == Qt.Key_Period or force_completion: self.fill_completer(force_completion)
class MainWindow(QMainWindow): def __init__(self, flags, *args, **kwargs): super().__init__(flags, *args, **kwargs) self.comps = dict() self.setFixedSize(*window_size) self.setWindowTitle('Pong') self.stack = QStackedWidget(self) self.setCentralWidget(self.stack) self.highscore_list = QListWidget() self.pong_game = SoloMode() self.pong_game.finished_signal.connect(self.finish_game) self.home_view = QWidget() self.pong_view = self.pong_game.scene_view.view self.setup_home_view() self.stack.addWidget(self.home_view) self.stack.addWidget(self.pong_view) self.stack.setCurrentWidget(self.home_view) # noinspection PyArgumentList def setup_home_view(self): res = QWidget() box_layout = QBoxLayout(QBoxLayout.Direction.LeftToRight) form = QWidget() form_layout = QFormLayout() self.comps["status"] = QLabel() self.comps["status"].setText("False") self.comps["status"].setStyleSheet('background-color: red') form_layout.addRow("Receiving", self.comps["status"]) self.comps["name"] = QLineEdit() form_layout.addRow("Full Name", self.comps["name"]) self.comps["age"] = QLineEdit() form_layout.addRow("Age", self.comps["age"]) self.comps["gender"] = QComboBox() self.comps["gender"].addItems(["male", "female", "other"]) form_layout.addRow("Gender", self.comps["gender"]) self.comps["is_real"] = QCheckBox() form_layout.addRow("Real data", self.comps["is_real"]) button = QPushButton("Play Solo") button.clicked.connect(self.play_solo) form_layout.addRow("", button) form.setLayout(form_layout) box_layout.addWidget(form, stretch=2) self.highscore_list.addItems(fetch_highscore()) box_layout.addWidget(self.highscore_list, stretch=1) res.setLayout(box_layout) res.setFixedSize(*window_size) self.home_view = res def finish_game(self): self.pong_game.stop() self.stack.setCurrentWidget(self.home_view) self.update_highscore_list() def play_solo(self): name = self.comps["name"].text() age = self.comps["age"].text() gender = self.comps["gender"].currentText() if not name: name = "Olav Ljosland" if not age: age = "24" sys_manager.person = Person.create_or_fetch(name, age, gender) sys_manager.is_real_data = bool(self.comps["is_real"].checkState()) self.stack.setCurrentWidget(self.pong_view) self.pong_game.start() def update_status_indicator(self, receiving_samples): self.comps["status"].setText(str(receiving_samples)) if receiving_samples: self.comps["status"].setStyleSheet('background-color: green') else: self.comps["status"].setStyleSheet('background-color: red') def update_highscore_list(self): self.highscore_list.clear() self.highscore_list.addItems(fetch_highscore())
class GstMediaSettings(SettingsPage): Name = 'Media Settings' def __init__(self, **kwargs): super().__init__(**kwargs) self.setLayout(QGridLayout()) self._pages = [] self._current_page = None self._settings = {} self._check = False self.listWidget = QListWidget(self) self.layout().addWidget(self.listWidget, 0, 0) self.pipeButton = QPushButton('Change Pipe', self) self.layout().addWidget(self.pipeButton, 1, 0) self.layout().setColumnStretch(0, 2) self.layout().setColumnStretch(1, 5) self.listWidget.currentItemChanged.connect(self.__change_page) self.pipeButton.clicked.connect(self.__edit_pipe) def load_settings(self, settings): settings = settings.get('_media_', {}) # Create a local copy of the configuration self._settings = deepcopy(settings) # Create the widgets pages = pages_by_element_name() for element in settings.get('pipe', ()): page = pages.get(element) if page is not None: page = page(element, parent=self) page.load_settings(settings.get('elements', {})) self._pages.append(page) item = QListWidgetItem(page.NAME) self.listWidget.addItem(item) self.listWidget.setCurrentRow(0) def get_settings(self): settings = {'elements': {}} for page in self._pages: settings['elements'].update(page.get_settings()) # The pipeline is returned only if check is disabled if not self._check: settings['pipe'] = self._settings['pipe'] return {'_media_': settings} def enable_check(self, enabled): self._check = enabled for page in self._pages: if isinstance(page, SettingsPage): page.enable_check(enabled) def __change_page(self, current, previous): if current is None: current = previous if self._current_page is not None: self.layout().removeWidget(self._current_page) self._current_page.hide() self._current_page = self._pages[self.listWidget.row(current)] self._current_page.show() self.layout().addWidget(self._current_page, 0, 1, 2, 1) def __edit_pipe(self): # Backup the settings self._settings.update(self.get_settings()['_media_']) # Show the dialog dialog = GstPipeEditDialog(self._settings.get('pipe', ()), parent=self) if dialog.exec_() == dialog.Accepted: # Reset the view self.listWidget.clear() if self._current_page is not None: self.layout().removeWidget(self._current_page) self._current_page.hide() self._current_page = None self._pages.clear() # Reload with the new pipeline self._settings['pipe'] = dialog.get_pipe() self.load_settings({'_media_': self._settings}) self.enable_check(self._check)
class ErrorsWidget(QWidget): ############################################################################### # ERRORS WIDGET SIGNALS ############################################################################### """ pep8Activated(bool) lintActivated(bool) """ pep8Activated = pyqtSignal(bool) lintActivated = pyqtSignal(bool) ############################################################################### def __init__(self): super(ErrorsWidget, self).__init__() self.pep8 = None self._outRefresh = True vbox = QVBoxLayout(self) self.listErrors = QListWidget() self.listErrors.setSortingEnabled(True) self.listPep8 = QListWidget() self.listPep8.setSortingEnabled(True) hbox_lint = QHBoxLayout() if settings.FIND_ERRORS: self.btn_lint_activate = QPushButton(_translate("ErrorsWidget", "Lint: ON")) else: self.btn_lint_activate = QPushButton(_translate("ErrorsWidget", "Lint: OFF")) self.errorsLabel = QLabel(_translate("ErrorsWidget", "Static Errors: %s") % 0) hbox_lint.addWidget(self.errorsLabel) hbox_lint.addSpacerItem(QSpacerItem(1, 0, QSizePolicy.Expanding)) hbox_lint.addWidget(self.btn_lint_activate) vbox.addLayout(hbox_lint) vbox.addWidget(self.listErrors) hbox_pep8 = QHBoxLayout() if settings.CHECK_STYLE: self.btn_pep8_activate = QPushButton(_translate("ErrorsWidget", "PEP8: ON")) else: self.btn_pep8_activate = QPushButton(_translate("ErrorsWidget", "PEP8: OFF")) self.pep8Label = QLabel(_translate("ErrorsWidget", "PEP8 Errors: %s") % 0) hbox_pep8.addWidget(self.pep8Label) hbox_pep8.addSpacerItem(QSpacerItem(1, 0, QSizePolicy.Expanding)) hbox_pep8.addWidget(self.btn_pep8_activate) vbox.addLayout(hbox_pep8) vbox.addWidget(self.listPep8) self.listErrors.itemSelectionChanged.connect(self.errors_selected) self.listPep8.itemSelectionChanged.connect(self.pep8_selected) self.btn_lint_activate.clicked['bool'].connect(self.errors_selected) self.btn_pep8_activate.clicked['bool'].connect(self._turn_on_off_pep8) def _turn_on_off_lint(self): """Change the status of the lint checker state.""" settings.FIND_ERRORS = not settings.FIND_ERRORS if settings.FIND_ERRORS: self.btn_lint_activate.setText(_translate("ErrorsWidget", "Lint: ON")) else: self.btn_lint_activate.setText(_translate("ErrorsWidget", "Lint: OFF")) self.lintActivated.emit(settings.FIND_ERRORS) def _turn_on_off_pep8(self): """Change the status of the lint checker state.""" settings.CHECK_STYLE = not settings.CHECK_STYLE if settings.CHECK_STYLE: self.btn_pep8_activate.setText(_translate("ErrorsWidget", "PEP8: ON")) else: self.btn_pep8_activate.setText(_translate("ErrorsWidget", "PEP8: OFF")) self.pep8Activated.emit(settings.CHECK_STYLE) def errors_selected(self): editorWidget = main_container.MainContainer().get_actual_editor() if editorWidget and self._outRefresh: lineno = int(self.listErrors.currentItem().data(Qt.UserRole)) editorWidget.jump_to_line(lineno) editorWidget.setFocus() def pep8_selected(self): editorWidget = main_container.MainContainer().get_actual_editor() if editorWidget and self._outRefresh: lineno = int(self.listPep8.currentItem().data(Qt.UserRole)) editorWidget.jump_to_line(lineno) editorWidget.setFocus() def refresh_lists(self, errors, pep8): self._outRefresh = False self.listErrors.clear() self.listPep8.clear() for lineno in errors.errorsSummary: linenostr = 'L%s\t' % str(lineno + 1) for data in errors.errorsSummary[lineno]: item = QListWidgetItem(linenostr + data) item.setToolTip(linenostr + data) item.setData(Qt.UserRole, lineno) self.listErrors.addItem(item) self.errorsLabel.setText(_translate("ErrorsWidget", "Static Errors: %s") % len(errors.errorsSummary)) for lineno in pep8.pep8checks: linenostr = 'L%s\t' % str(lineno + 1) for data in pep8.pep8checks[lineno]: item = QListWidgetItem(linenostr + data.split('\n')[0]) item.setToolTip(linenostr + data.split('\n')[0]) item.setData(Qt.UserRole, lineno) self.listPep8.addItem(item) self.pep8Label.setText(_translate("ErrorsWidget", "PEP8 Errors: %s") % len(pep8.pep8checks)) self._outRefresh = True def clear(self): """ Clear the widget """ self.listErrors.clear() self.listPep8.clear()
class FindDialog(QDialog): alphabetical = [dict(type="alphabetical", allowPseudoUnicode=True)] def __init__(self, currentGlyph, parent=None): super().__init__(parent) self.setWindowModality(Qt.WindowModal) self.setWindowTitle(self.tr("Find…")) self._sortedGlyphNames = currentGlyph.font.unicodeData.sortGlyphNames( currentGlyph.layer.keys(), self.alphabetical ) layout = QGridLayout(self) self.glyphLabel = QLabel(self.tr("Glyph:"), self) self.glyphEdit = QLineEdit(self) self.glyphEdit.textChanged.connect(self.updateGlyphList) self.glyphEdit.event = self.lineEvent self.glyphEdit.keyPressEvent = self.lineKeyPressEvent self.beginsWithBox = QRadioButton(self.tr("Begins with"), self) self.containsBox = QRadioButton(self.tr("Contains"), self) self.beginsWithBox.setChecked(True) self.beginsWithBox.toggled.connect(self.updateGlyphList) self.glyphList = QListWidget(self) self.glyphList.itemDoubleClicked.connect(self.accept) buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject) line = 0 layout.addWidget(self.glyphLabel, line, 0, 1, 2) layout.addWidget(self.glyphEdit, line, 2, 1, 4) line += 1 layout.addWidget(self.beginsWithBox, line, 0, 1, 3) layout.addWidget(self.containsBox, line, 3, 1, 3) line += 1 layout.addWidget(self.glyphList, line, 0, 1, 6) line += 1 layout.addWidget(buttonBox, line, 0, 1, 6) self.setLayout(layout) self.updateGlyphList() def lineEvent(self, event): if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Tab: if self.beginsWithBox.isChecked(): self.containsBox.toggle() else: self.beginsWithBox.toggle() return True else: return QLineEdit.event(self.glyphEdit, event) def lineKeyPressEvent(self, event): key = event.key() if key == Qt.Key_Up or key == Qt.Key_Down: self.glyphList.keyPressEvent(event) else: QLineEdit.keyPressEvent(self.glyphEdit, event) def updateGlyphList(self): beginsWith = self.beginsWithBox.isChecked() self.glyphList.clear() if not self.glyphEdit.isModified(): self.glyphList.addItems(self._sortedGlyphNames) else: text = self.glyphEdit.text() if beginsWith: glyphs = [ glyphName for glyphName in self._sortedGlyphNames if glyphName and glyphName.startswith(text) ] else: glyphs = [ glyphName for glyphName in self._sortedGlyphNames if glyphName and text in glyphName ] self.glyphList.addItems(glyphs) self.glyphList.setCurrentRow(0) @classmethod def getNewGlyph(cls, parent, currentGlyph): dialog = cls(currentGlyph, parent) result = dialog.exec_() currentItem = dialog.glyphList.currentItem() newGlyph = None if currentItem is not None: newGlyphName = currentItem.text() if newGlyphName in currentGlyph.layer: newGlyph = currentGlyph.layer[newGlyphName] return (newGlyph, result)
class NodeListWidget (QWidget): def __init__ (self, parent): super().__init__(parent) self.search = SearchWidget(self) self.search.searched.connect(self.populatelist) self.nodelist = QListWidget(self) self.nodelist.setSortingEnabled(True) self.nodelist.setIconSize(QSize(*(FlGlob.mainwindow.style.boldheight,)*2)) self.nodelist.currentItemChanged.connect(self.selectnode) self.nodelist.itemSelectionChanged.connect(self.onselectionchange) self.nodelist.itemActivated.connect(self.activatenode) self.nodelist.setSelectionMode(QAbstractItemView.ExtendedSelection) remwidget = QToolBar(self) remselected = QAction("Remove Selected", self) remselected.setIcon(QIcon.fromTheme("edit-delete")) remselected.setToolTip("Remove selected") remselected.triggered.connect(self.remselected) self.remselaction = remselected remtrash = QAction("Remove Trash", self) remtrash.setIcon(QIcon.fromTheme("edit-clear")) remtrash.setToolTip("Clear all trash") remtrash.triggered.connect(self.remtrash) self.remtrashaction = remtrash remwidget.addAction(remselected) remwidget.addAction(remtrash) layout = QVBoxLayout(self) layout.addWidget(self.search) layout.addWidget(self.nodelist) layout.addWidget(remwidget) self.view = None self.active = False self.setEnabled(False) @pyqtSlot() def setview (self): self.view = FlGlob.mainwindow.activeview if self.view is None: self.setEnabled(False) self.active = False else: self.setEnabled(True) self.active = True self.populatelist() @pyqtSlot() def populatelist (self): self.index = dict() self.nodelist.clear() if not self.active: return nodecont = self.view.nodecontainer.nodes for nodeID, nodeobj in nodecont.items(): if self.view.hits is not None and nodeID not in self.view.hits: continue listitem = self.listitem(self.view, nodeobj, nodeID) self.nodelist.addItem(listitem) self.index[nodeID] = listitem self.remtrashaction.setEnabled(bool(self.view.trash)) @pyqtSlot(str) def selectbyID (self, nodeID): if not self.active: return if nodeID in self.index: self.nodelist.setCurrentItem(self.index[nodeID]) def listitem (self, view, nodeobj, nodeID): typename = nodeobj.typename if typename == "root": descr = "" elif typename == "bank": descr = "(%s) %s" % (nodeobj.bankmode, ", ".join(nodeobj.subnodes)) elif typename == "talk": descr = "[%s]" % elidestring(nodeobj.text, 30) elif typename == "response": descr = "[%s]" % elidestring(nodeobj.text, 30) else: descr = "" label = "%s: %s %s" % (nodeID, typename, descr) if nodeID in view.trash: trash = True icon = QIcon.fromTheme("user-trash") else: trash = False icon = QIcon.fromTheme("text-x-generic") item = NodeListItem(icon, label) item.setData(item.IDRole, int(nodeID)) item.setData(item.TrashRole, trash) return item @pyqtSlot(QListWidgetItem, QListWidgetItem) def selectnode (self, listitem, olditem): if listitem is None: return window = FlGlob.mainwindow view = window.activeview nodeID = str(listitem.data(listitem.IDRole)) window.setselectednode(view, nodeID) @pyqtSlot() def onselectionchange (self): selected = self.nodelist.selectedItems() seltrash = [item for item in selected if item.data(item.TrashRole)] self.remselaction.setEnabled(bool(seltrash)) @pyqtSlot(QListWidgetItem) def activatenode (self, listitem): window = FlGlob.mainwindow view = window.activeview nodeID = str(listitem.data(listitem.IDRole)) window.setactivenode(view, nodeID) @pyqtSlot() def remselected (self): selected = self.nodelist.selectedItems() seltrash = [item for item in selected if item.data(item.TrashRole)] answer = QMessageBox.question(self, "Node removal", "Permanently remove selected trash nodes (%s)?\n\nThis will also clear the undo action list." % len(seltrash)) if answer == QMessageBox.No: return self.view.removenodes([str(item.data(item.IDRole)) for item in selected]) self.remselaction.setEnabled(False) @pyqtSlot() def remtrash (self): count = len(self.view.trash) answer = QMessageBox.question(self, "Node removal", "Permanently remove all (%s) trash nodes?\n\nThis will also clear the undo action list." % count) if answer == QMessageBox.No: return self.remtrashaction.setEnabled(False) self.view.removetrash()
class Window(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.mainWidget = QWidget() self.mainWidget.setMinimumSize(QtCore.QSize(640, 480)) self.mainWidget.setWindowTitle("menoTulo") self.grid = QVBoxLayout() self.ui() def inputGrid(self): self.inputGrid = QHBoxLayout() self.otsikko = QLineEdit(self) self.summa = QLineEdit(self) self.otsikko.setPlaceholderText("Tulon/menon kuvaus...") self.summa.setPlaceholderText("Summa...") self.inputGrid.addWidget(self.otsikko) self.inputGrid.addWidget(self.summa) self.grid.addLayout(self.inputGrid) def nappiGrid(self): self.nappiGrid = QHBoxLayout() self.tuloButton = QPushButton("Lisää tulo", self) self.menoButton = QPushButton("Lisää meno", self) self.tuloButton.clicked.connect(self.addTulo) self.menoButton.clicked.connect(self.addMeno) self.nappiGrid.addWidget(self.tuloButton) self.nappiGrid.addWidget(self.menoButton) self.grid.addLayout(self.nappiGrid) def listaGrid(self): self.listaGrid = QHBoxLayout() self.tuloLista = QListWidget() self.menoLista = QListWidget() self.tuloLista.itemClicked.connect(self.deleteItem) self.menoLista.itemClicked.connect(self.deleteItem) self.listaGrid.addWidget(self.tuloLista) self.listaGrid.addWidget(self.menoLista) self.grid.addLayout(self.listaGrid) def totalGrid(self): self.totalGrid = QHBoxLayout() self.totalSum = 0 self.totalMenot = 0 self.totalTulot = 0 self.tuloLabel = QLabel() self.sumLabel = QLabel() self.menoLabel = QLabel() self.clearButton = QPushButton("TYHJENNÄ KAIKKI", self) self.clearButton.clicked.connect(self.clearAll) self.totalGrid.addWidget(self.tuloLabel) self.totalGrid.addWidget(self.sumLabel) self.totalGrid.addWidget(self.menoLabel) self.totalGrid.addWidget(self.clearButton) self.tuloLabel.setText("TULOT:") self.sumLabel.setText("TOTAL:") self.menoLabel.setText("MENOT:") self.grid.addLayout(self.totalGrid) def ui(self): self.inputGrid() self.nappiGrid() self.listaGrid() self.totalGrid() self.mainWidget.setLayout(self.grid) self.mainWidget.show() def virhe(self): QMessageBox.about(self, "Virhe", "Syötä summaan vain numeroita!") def poistoVarmistus(self): vastaus = QMessageBox.question(self, "Poista valittu", "Poistetaanko varmasti?", QMessageBox.No | QMessageBox.Yes) if vastaus == QMessageBox.Yes: return True return False def tyhjennysVarmistus(self): vastaus = QMessageBox.question(self, "Tyhjennä kaikki", "Oletko varma?", QMessageBox.No | QMessageBox.Yes) if vastaus == QMessageBox.Yes: return True return False def clearAll(self): if self.tyhjennysVarmistus(): self.totalSum = 0 self.totalMenot = 0 self.totalTulot = 0 self.tuloLista.clear() self.menoLista.clear() self.tuloLabel.setText("TULOT:") self.sumLabel.setText("TOTAL:") self.menoLabel.setText("MENOT:") def deleteItem(self): if self.sender() == self.tuloLista: lista = self.tuloLista else: lista = self.menoLista if not lista.selectedItems(): return if self.poistoVarmistus(): for item in lista.selectedItems(): poistoSumma = int( lista.takeItem(lista.row(item)).text().split()[0]) lista.takeItem(lista.row(item)) if lista == self.tuloLista: self.totalTulot -= poistoSumma else: self.totalMenot -= poistoSumma self.updateTotal() self.tuloLista.clearSelection() self.menoLista.clearSelection() def updateTotal(self): self.tuloLabel.setText("TULOT: " + str(self.totalTulot)) self.menoLabel.setText("MENOT: " + str(self.totalMenot)) self.totalSum = self.totalTulot - self.totalMenot self.sumLabel.setText("TOTAL: " + str(self.totalSum)) def addMeno(self): if not self.summa.text().isdigit(): self.virhe() self.summa.clear() else: infoText = self.summa.text() + " " + self.otsikko.text() if infoText != " ": self.menoLista.addItem(infoText) self.totalSum -= int(self.summa.text()) self.sumLabel.setText("TOTAL: " + str(self.totalSum)) self.totalMenot += int(self.summa.text()) self.menoLabel.setText("MENOT: " + str(self.totalMenot)) self.summa.clear() self.otsikko.clear() else: pass def addTulo(self): if not self.summa.text().isdigit(): self.virhe() self.summa.clear() else: infoText = self.summa.text() + " " + self.otsikko.text() if infoText != " ": self.tuloLista.addItem(infoText) self.totalSum += int(self.summa.text()) self.sumLabel.setText("TOTAL: " + str(self.totalSum)) self.totalTulot += int(self.summa.text()) self.tuloLabel.setText("TULOT: " + str(self.totalTulot)) self.summa.clear() self.otsikko.clear() else: pass
class DebuggerMainWindow(object): def __init__(self, comm): self.comm = comm self.follow_state = True self.init_instances() self.init_widgets() self.init_actions() self.window.closeEvent = self.close_handler self.window.showMaximized() def run(self): self.poll_timer = QTimer() self.poll_timer.timeout.connect(self.poll_handler) self.comm.start_worker() self.poll_timer.start(1000) def poll_handler(self): self.comm.put_job(self.comm.get_agent_track) data = self.comm.take_data() for location_info, state in data: file_name, node_id = location_info i = self.get_instance(file_name) if i is None: text = "%s:%s" % (str(location_info), state) else: node = i.model.get_node(node_id) if node is not None: text = "%s: %s: %s" % (file_name, node.get_display_text(), state) else: text = "%s:%s" % (str(location_info), state) self.add_to_history_list(location_info, text) if self.follow_state: self.focus_last() def init_widgets(self): self.window = loadUi(MAIN_UI_PATH) self.mdi = self.window.mdiArea self.mdi.setViewMode(QMdiArea.TabbedView) self.mdi.setTabsMovable(True) self.mdi.setTabsClosable(True) self.mdi.setTabShape(QTabWidget.Rounded) self.dock_anchor = self.window.dockAnchor self.dock_anchor.layout().setAlignment(Qt.AlignTop) self.history_list = QListWidget() self.history_list.itemSelectionChanged.connect(self.list_item_selected) self.add_dock_content(self.history_list) def list_item_selected(self): citem = self.history_list.currentItem() self.focus_on_location(citem.location_info) def init_instances(self): self.instances = {} def remove_instance(self, ins): file_name = ins.file_name self.instances.pop(file_name) def add_instance(self, ins): file_name = ins.file_name self.instances[file_name] = ins def get_instance(self, file_name): if file_name in self.instances: return self.instances[file_name] else: full_path = GraphInstanceVM.get_full_path(file_name) model = GraphInstanceVM.get_model(full_path) if model is None: return None ins = GraphInstanceVM(model, self, file_name) return ins def init_actions(self): self.window.actionResume.triggered.connect(self.action_resume_handler) self.window.actionStop.triggered.connect(self.action_stop_handler) self.window.actionFollow.triggered.connect(self.action_follow_handler) self.window.actionHold.triggered.connect(self.action_hold_handler) def action_resume_handler(self): self.clear_list() self.comm.put_job(functools.partial(self.comm.track_agent, True)) def action_stop_handler(self): self.comm.put_job(functools.partial(self.comm.track_agent, False)) def action_follow_handler(self): self.follow_state = True def action_hold_handler(self): self.follow_state = False def close_handler(self, ev): # disable tracking for some agents self.poll_timer.stop() self.comm.put_job(self.comm.finish) self.comm.shutdown() def add_dock_content(self, widget): self.clear_dock_contents() self.dock_anchor.layout().addWidget(widget) def get_dock_contents(self): l = self.dock_anchor.layout() ret = [] for i in range(l.count()): ret.append(l.itemAt(i).widget()) return ret def clear_dock_contents(self): ws = self.get_dock_contents() for w in ws: w.deleteLater() def focus_on_location(self, location): file_name, node_id = location instance = self.get_instance(file_name) if instance is None: logger.fatal("can not find src file for %s" % file_name) return False ret = instance.focus_on(node_id) if ret is False: logger.fatal("can not find node %s for %s" % (node_id, file_name)) return False return True def add_to_history_list(self, location, text): item = HistoryListItem(location, text) self.history_list.addItem(item) def clear_list(self): self.history_list.clear() def focus_last(self): c = self.history_list.count() if c > 0: item = self.history_list.item(c-1) self.history_list.setCurrentItem(item) self.focus_on_location(item.location_info)
class DropWidget(QWidget): """ Pyqt5 widget to show items in a QListWidget with Checks. It is used in PlotSplitter. """ # Signals list2drop = pyqtSignal(list, list, bool) def __init__(self): super().__init__() self.init_ui() def init_ui(self): """Layout and main functionality.""" # Labels drop_label = QLabel("Delete parameter") # Lists self.drop_list = QListWidget(self) # Buttons apply_drop_button = QPushButton("Apply") apply_drop_button.clicked.connect(self.send_labels) hide_drop_button = QPushButton("Hide") hide_drop_button.clicked.connect(self.hide) # Radio buttons self.all_radio = QRadioButton("All", self) self.all_radio.setChecked(True) self.good_radio = QRadioButton("Use QC Flags = 0 and 1", self) self.one_radio = QRadioButton("Remove QC flag: ", self) # Check box self.drop_nan_check = QCheckBox("Drop NaN", self) self.drop_nan_check.setChecked(True) # Spin inputs self.qc_spin_box = QSpinBox(self) self.qc_spin_box.setMinimum(0) self.qc_spin_box.setMaximum(9) self.qc_spin_box.setValue(0) # Layout # - Horizontal Layout for one_radio - h_one = QHBoxLayout() h_one.addWidget(self.one_radio) h_one.addWidget(self.qc_spin_box) # - General layout - v_drop = QVBoxLayout() v_drop.addWidget(drop_label) v_drop.addWidget(self.drop_list) v_drop.addWidget(self.all_radio) v_drop.addWidget(self.good_radio) v_drop.addLayout(h_one) v_drop.addWidget(self.drop_nan_check) v_drop.addWidget(apply_drop_button) v_drop.addWidget(hide_drop_button) self.setLayout(v_drop) def add_labels(self, labels): """Add items to self.drop_list""" # Clear the list self.drop_list.clear() # Add new items self.drop_list.addItems(labels) # Configure the items checkable for index in range(self.drop_list.count()): item = self.drop_list.item(index) item.setFlags(item.flags() | Qt.ItemIsUserCheckable) item.setCheckState(Qt.Unchecked) def send_labels(self): """ It returns the list of checked items from self.drop_list. It also send the signal list2drop with the list. Returns ------- (labels, flag_list): (list of str, list of int) (List with checked labels from self.drop_list, List of flags) """ # Look for checked items and create the list labels = [] for index in range(self.drop_list.count()): item = self.drop_list.item(index) if item.checkState(): labels.append(item.text()) # Flag lists flag_list = [] if self.all_radio.isChecked(): flag_list = [None] elif self.good_radio.isChecked(): flag_list = [2, 3, 4, 5, 6, 7, 8, 9] elif self.one_radio.isChecked(): flag_list = [self.qc_spin_box.value()] # Send the signal if labels: self.list2drop.emit(labels, flag_list, self.drop_nan_check.isChecked()) return labels, flag_list
class PaletteChooser(QDialog): def __init__(self, parent, modelwrapper): """ This window will open a palette chooser to let users select a palette from the (global) list of possible palettes. :param parent: The parent window, should be the current instance of MainWindow. :param modelwrapper: The wrapper of the model. """ super().__init__(parent=parent) self.setWindowTitle("Choose Palette") self.modelwrapper = modelwrapper # vertical layout as central panel. vlayout = QVBoxLayout() self.setLayout(vlayout) self.setFixedSize(300, 400) # add a list widget to view all the pretty palettes. self.list = QListWidget() self.list.setSelectionMode(1) vlayout.addWidget(self.list) options = QWidget() opts_layout = QVBoxLayout() options.setLayout(opts_layout) vlayout.addWidget(options) ubox = QWidget() ulayout = QHBoxLayout() ubox.setLayout(ulayout) vlayout.addWidget(ubox) ulayout.addWidget(QLabel("upper bound:")) self.upperBoundField = QSpinBox() self.upperBoundField.setRange(-2147483648, 2147483647) self.upperBoundField.setValue(modelwrapper.model.upper_bound) self.upperBoundField.setSingleStep( (modelwrapper.model.highest - modelwrapper.model.lowest) / 1000) ulayout.addWidget(self.upperBoundField) lbox = QWidget() llayout = QHBoxLayout() lbox.setLayout(llayout) vlayout.addWidget(lbox) llayout.addWidget(QLabel("lower bound:")) self.lowerBoundField = QSpinBox() self.lowerBoundField.setRange(-2147483648, 2147483647) self.lowerBoundField.setValue(modelwrapper.model.lower_bound) self.lowerBoundField.setSingleStep( (modelwrapper.model.highest - modelwrapper.model.lowest) / 1000) llayout.addWidget(self.lowerBoundField) # add a button bar at the bottom. button_bar = QWidget() button_bar_layout = QHBoxLayout() button_bar.setLayout(button_bar_layout) vlayout.addWidget(button_bar) # add a cancel button. cancel_button = QPushButton('Cancel') cancel_button.clicked.connect(self.close) button_bar_layout.addWidget(cancel_button) # add import palette button import_button = QPushButton('Import') import_button.clicked.connect(self.import_palette) button_bar_layout.addWidget(import_button) # add apply button. apply_button = QPushButton('Apply') apply_button.clicked.connect(self.apply) button_bar_layout.addWidget(apply_button) # add a ok button. ok_button = QPushButton('OK') ok_button.clicked.connect(self.ok) button_bar_layout.addWidget(ok_button) self.gen_palette_list() def gen_palette_list(self): self.list.clear() for i, palt in enumerate(palettes): item = QListWidgetItem(self.list) # item.setBackground(QtCore.Qt.red) widg = QWidget() # widg.setStyleSheet("background-color:blue") layo = QHBoxLayout() self.list.setItemWidget(item, widg) text = QLabel(palt.name) text.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.MinimumExpanding) grad = QLabel() grad.setScaledContents(True) grad.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) grad.setPixmap(QPixmap(palt.generate_preview(width=100, height=1))) # grad.setStyleSheet("background-color:green") layo.addWidget(text) layo.addWidget(grad) widg.setLayout(layo) widg.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.MinimumExpanding) item.setSizeHint(widg.sizeHint()) if self.modelwrapper.get_preference( PreferenceEnum.PALETTE) is palt: self.list.setCurrentRow(i) def import_palette(self): files, _ = QFileDialog.getOpenFileNames( None, "Import palette file", "", "Palette Files (*.palette);;All Files(*)") loaded = [] for file in files: loaded.extend(load_custom_palettes(file)) self.gen_palette_list() for file in loaded: if not path.exists(path.join(main.CUSTOM_PALETTE_PATH, path.basename(file))) \ or not path.samefile(file, path.join(main.CUSTOM_PALETTE_PATH, path.basename(file))): copy(file, main.CUSTOM_PALETTE_PATH) self.close() self.parent().add_dialog( PaletteChooser(self.parent(), self.modelwrapper)) def ok(self): self.apply() self.close() def apply(self): index = self.list.currentRow() self.modelwrapper.set_palette(palettes[index]) self.modelwrapper.set_lower_bound(self.lowerBoundField.value()) self.modelwrapper.set_upper_bound(self.upperBoundField.value()) # TODO is this function still necessary? def closeEvent(self, event): """ Overrides the closing event to execute the on_close callback after closing. This is better than overriding close() because this will also execute when the user presses the x button on the top of the window.""" event.accept() self.parent().dialogs.remove(self)
class Ahsoka(QWidget): def __init__(self): super().__init__() self.init() self.place() self.show() def init(self): self.setWindowTitle('Ahsoka') self.setWindowIcon(QIcon(imgPath('icon.png'))) self.urlLabel = QLabel('Ссылка:') self.nameLabel = QLabel('Название:') self.urlEdit = QLineEdit() self.nameEdit = QLineEdit() self.downloadBtn = QPushButton('Скачать') self.updateBtn = QPushButton('Обновить') self.gamesList = QListWidget() self.enginesBox = QGroupBox('Движки') self.playBtn = QPushButton('Играть') self.delBtn = QPushButton('Удалить') self.statusBar = QStatusBar() self.connectAll() def successMessage(self, message): self.statusBar.setStyleSheet('color: green') self.statusBar.showMessage(message) def errorMessage(self, message): self.statusBar.setStyleSheet('color: red') self.statusBar.showMessage(message) def connectAll(self): self.downloadBtn.clicked.connect(self.downloadGame) self.updateBtn.clicked.connect(self.setGames) self.gamesList.setVerticalScrollBar(QScrollBar()) self.setEngines() self.setGames() self.playBtn.clicked.connect(self.play) self.delBtn.clicked.connect(self.delGame) self.successMessage('Добро пожаловать в лучший лаунчер флешек Ahsoka') def place(self): self.grid = QGridLayout() self.grid.setSpacing(5) self.grid.addWidget(self.urlLabel, 0, 0, 1, 1) self.grid.addWidget(self.urlEdit, 0, 1, 1, 1) self.grid.addWidget(self.nameLabel, 1, 0, 1, 1) self.grid.addWidget(self.nameEdit, 1, 1, 1, 1) self.grid.addWidget(self.downloadBtn, 0, 2, 1, 1) self.grid.addWidget(self.updateBtn, 1, 2, 1, 1) self.grid.addWidget(self.gamesList, 2, 0, 1, 2) self.grid.addWidget(self.enginesBox, 2, 2, 1, 1) self.grid.addWidget(self.playBtn, 3, 0, 1, 2) self.grid.addWidget(self.delBtn, 3, 2, 1, 1) self.grid.addWidget(self.statusBar, 4, 0, 1, 3) self.setLayout(self.grid) def setGames(self): self.gamesList.clear() for game in sorted(listdir('games')): self.gamesList.addItem(game[:-4].title()) def setEngines(self): enginesLayout = QVBoxLayout() for engine in ['flashplayer']: btn = QRadioButton(engine.capitalize()) if 'flashplayer' in engine: btn.setChecked(True) enginesLayout.addWidget(btn) self.enginesBox.setLayout(enginesLayout) def wget(self, *args, **kwargs): download(*args, **kwargs) self.setGames() self.urlEdit.clear() self.nameEdit.clear() self.successMessage('Загрузка завершена') def downloadGame(self): try: url = swf = self.urlEdit.text().strip() name = self.nameEdit.text().strip() if not url.endswith('.swf'): req = get(url) self.statusBar.showMessage(str(req)) try: html = req.content.decode('utf-8') except: html = req.content.decode('cp1251') swf = findall(r'\".[^"]+\.swf\"', html)[0][1:-1] swf = urljoin(url, swf) print(swf) self.successMessage('Скачивание...') args = swf, kwargs = { 'out': 'games/' } if not name else { 'out': getGamePath(name) } Thread(target=self.wget, args=args, kwargs=kwargs).start() except Exception as Exc: print(Exc) self.urlEdit.clear() self.errorMessage('Попробуйте другую ссылку') def delGame(self): game = self.gamesList.currentItem() if game is None: return remove(getGamePath(game.text())) self.setGames() self.successMessage('Игра удалена') def play(self): game = self.gamesList.currentItem() if game is None: return engine = libPath( ('flashplayer' if sys.platform == 'linux' else 'flashplayer.exe')) args = f'{engine} \"{getGamePath(game.text())}\"', self.statusBar.showMessage('Игра запущена') Thread(target=popen, args=args).start()
class NewProjectManager(QDialog): def __init__(self, parent=None): super(NewProjectManager, self).__init__(parent, Qt.Dialog) self.setWindowTitle(translations.TR_NEW_PROJECT) self.setMinimumHeight(500) vbox = QVBoxLayout(self) vbox.addWidget(QLabel(translations.TR_CHOOSE_TEMPLATE)) vbox.addWidget(QLabel(translations.TR_TAB_PROJECTS)) hbox = QHBoxLayout() self.list_projects = QListWidget() self.list_projects.setProperty("wizard", True) hbox.addWidget(self.list_projects) self.list_templates = QListWidget() self.list_templates.setProperty("wizard", True) hbox.addWidget(self.list_templates) self.text_info = QTextBrowser() self.text_info.setProperty("wizard", True) hbox.addWidget(self.text_info) vbox.addLayout(hbox) hbox2 = QHBoxLayout() cancel = QPushButton(translations.TR_CANCEL) choose = QPushButton(translations.TR_CHOOSE) hbox2.addSpacerItem(QSpacerItem(1, 0, QSizePolicy.Expanding, QSizePolicy.Fixed)) hbox2.addWidget(cancel) hbox2.addWidget(choose) vbox.addLayout(hbox2) self.template_registry = IDE.get_service("template_registry") categories = self.template_registry.list_project_categories() for category in categories: self.list_projects.addItem(category) cancel.clicked['bool'].connect(self.close) choose.clicked['bool'].connect(self._start_wizard) self.list_projects.itemSelectionChanged.connect(self._project_selected) self.list_templates.itemSelectionChanged.connect(self._template_selected) def _project_selected(self): self.list_templates.clear() item = self.list_projects.currentItem() category = item.text() for template in self.template_registry.list_templates_for_cateogory( category): item = QListWidgetItem(template.type_name) item.setData(Qt.UserRole, template) item = self.list_templates.addItem(item) def _template_selected(self): item = self.list_templates.currentItem() ptype = item.data(Qt.UserRole) self.text_info.setText(ptype.description) def _start_wizard(self): return QMessageBox.critical(self, "Beta Info", "Can not construct this segment!") item = self.list_templates.currentItem() if item is not None: ptype = item.data(Qt.UserRole)
class MusicPlayer(QMainWindow): """MusicPlayer houses all of elements that directly interact with the main window.""" def __init__(self, parent=None): """Initialize the QMainWindow widget. The window title, window icon, and window size are initialized here as well as the following widgets: QMediaPlayer, QMediaPlaylist, QMediaContent, QMenuBar, QToolBar, QLabel, QPixmap, QSlider, QDockWidget, QListWidget, QWidget, and QVBoxLayout. The connect signals for relavant widgets are also initialized. """ super(MusicPlayer, self).__init__(parent) self.setWindowTitle('Mosaic') window_icon = utilities.resource_filename('mosaic.images', 'icon.png') self.setWindowIcon(QIcon(window_icon)) self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63) # Initiates Qt objects to be used by MusicPlayer self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.playlist_location = defaults.Settings().playlist_path self.content = QMediaContent() self.menu = self.menuBar() self.toolbar = QToolBar() self.art = QLabel() self.pixmap = QPixmap() self.slider = QSlider(Qt.Horizontal) self.duration_label = QLabel() self.playlist_dock = QDockWidget('Playlist', self) self.library_dock = QDockWidget('Media Library', self) self.playlist_view = QListWidget() self.library_view = library.MediaLibraryView() self.library_model = library.MediaLibraryModel() self.preferences = configuration.PreferencesDialog() self.widget = QWidget() self.layout = QVBoxLayout(self.widget) self.duration = 0 self.playlist_dock_state = None self.library_dock_state = None # Sets QWidget() as the central widget of the main window self.setCentralWidget(self.widget) self.layout.setContentsMargins(0, 0, 0, 0) self.art.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) # Initiates the playlist dock widget and the library dock widget self.addDockWidget(defaults.Settings().dock_position, self.playlist_dock) self.playlist_dock.setWidget(self.playlist_view) self.playlist_dock.setVisible(defaults.Settings().playlist_on_start) self.playlist_dock.setFeatures(QDockWidget.DockWidgetClosable) self.addDockWidget(defaults.Settings().dock_position, self.library_dock) self.library_dock.setWidget(self.library_view) self.library_dock.setVisible(defaults.Settings().media_library_on_start) self.library_dock.setFeatures(QDockWidget.DockWidgetClosable) self.tabifyDockWidget(self.playlist_dock, self.library_dock) # Sets the range of the playback slider and sets the playback mode as looping self.slider.setRange(0, self.player.duration() / 1000) self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) # OSX system menu bar causes conflicts with PyQt5 menu bar if sys.platform == 'darwin': self.menu.setNativeMenuBar(False) # Initiates Settings in the defaults module to give access to settings.toml defaults.Settings() # Signals that connect to other methods when they're called self.player.metaDataChanged.connect(self.display_meta_data) self.slider.sliderMoved.connect(self.seek) self.player.durationChanged.connect(self.song_duration) self.player.positionChanged.connect(self.song_position) self.player.stateChanged.connect(self.set_state) self.playlist_view.itemActivated.connect(self.activate_playlist_item) self.library_view.activated.connect(self.open_media_library) self.playlist.currentIndexChanged.connect(self.change_index) self.playlist.mediaInserted.connect(self.initialize_playlist) self.playlist_dock.visibilityChanged.connect(self.dock_visiblity_change) self.library_dock.visibilityChanged.connect(self.dock_visiblity_change) self.preferences.dialog_media_library.media_library_line.textChanged.connect(self.change_media_library_path) self.preferences.dialog_view_options.dropdown_box.currentIndexChanged.connect(self.change_window_size) self.art.mousePressEvent = self.press_playback # Creating the menu controls, media controls, and window size of the music player self.menu_controls() self.media_controls() self.load_saved_playlist() def menu_controls(self): """Initiate the menu bar and add it to the QMainWindow widget.""" self.file = self.menu.addMenu('File') self.edit = self.menu.addMenu('Edit') self.playback = self.menu.addMenu('Playback') self.view = self.menu.addMenu('View') self.help_ = self.menu.addMenu('Help') self.file_menu() self.edit_menu() self.playback_menu() self.view_menu() self.help_menu() def media_controls(self): """Create the bottom toolbar and controls used for media playback.""" self.addToolBar(Qt.BottomToolBarArea, self.toolbar) self.toolbar.setMovable(False) play_icon = utilities.resource_filename('mosaic.images', 'md_play.png') self.play_action = QAction(QIcon(play_icon), 'Play', self) self.play_action.triggered.connect(self.player.play) stop_icon = utilities.resource_filename('mosaic.images', 'md_stop.png') self.stop_action = QAction(QIcon(stop_icon), 'Stop', self) self.stop_action.triggered.connect(self.player.stop) previous_icon = utilities.resource_filename('mosaic.images', 'md_previous.png') self.previous_action = QAction(QIcon(previous_icon), 'Previous', self) self.previous_action.triggered.connect(self.previous) next_icon = utilities.resource_filename('mosaic.images', 'md_next.png') self.next_action = QAction(QIcon(next_icon), 'Next', self) self.next_action.triggered.connect(self.playlist.next) repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png') self.repeat_action = QAction(QIcon(repeat_icon), 'Repeat', self) self.repeat_action.setShortcut('R') self.repeat_action.triggered.connect(self.repeat_song) self.toolbar.addAction(self.play_action) self.toolbar.addAction(self.stop_action) self.toolbar.addAction(self.previous_action) self.toolbar.addAction(self.next_action) self.toolbar.addAction(self.repeat_action) self.toolbar.addWidget(self.slider) self.toolbar.addWidget(self.duration_label) def file_menu(self): """Add a file menu to the menu bar. The file menu houses the Open File, Open Multiple Files, Open Playlist, Open Directory, and Exit Application menu items. """ self.open_action = QAction('Open File', self) self.open_action.setShortcut('O') self.open_action.triggered.connect(self.open_file) self.open_multiple_files_action = QAction('Open Multiple Files', self) self.open_multiple_files_action.setShortcut('M') self.open_multiple_files_action.triggered.connect(self.open_multiple_files) self.open_playlist_action = QAction('Open Playlist', self) self.open_playlist_action.setShortcut('CTRL+P') self.open_playlist_action.triggered.connect(self.open_playlist) self.open_directory_action = QAction('Open Directory', self) self.open_directory_action.setShortcut('D') self.open_directory_action.triggered.connect(self.open_directory) self.save_playlist_action = QAction('Save Playlist', self) self.save_playlist_action.setShortcut('CTRL+S') self.save_playlist_action.triggered.connect(self.save_playlist) self.exit_action = QAction('Quit', self) self.exit_action.setShortcut('CTRL+Q') self.exit_action.triggered.connect(self.closeEvent) self.file.addAction(self.open_action) self.file.addAction(self.open_multiple_files_action) self.file.addAction(self.open_playlist_action) self.file.addAction(self.open_directory_action) self.file.addSeparator() self.file.addAction(self.save_playlist_action) self.file.addSeparator() self.file.addAction(self.exit_action) def edit_menu(self): """Add an edit menu to the menu bar. The edit menu houses the preferences item that opens a preferences dialog that allows the user to customize features of the music player. """ self.preferences_action = QAction('Preferences', self) self.preferences_action.setShortcut('CTRL+SHIFT+P') self.preferences_action.triggered.connect(lambda: self.preferences.exec_()) self.edit.addAction(self.preferences_action) def playback_menu(self): """Add a playback menu to the menu bar. The playback menu houses """ self.play_playback_action = QAction('Play', self) self.play_playback_action.setShortcut('P') self.play_playback_action.triggered.connect(self.player.play) self.stop_playback_action = QAction('Stop', self) self.stop_playback_action.setShortcut('S') self.stop_playback_action.triggered.connect(self.player.stop) self.previous_playback_action = QAction('Previous', self) self.previous_playback_action.setShortcut('B') self.previous_playback_action.triggered.connect(self.previous) self.next_playback_action = QAction('Next', self) self.next_playback_action.setShortcut('N') self.next_playback_action.triggered.connect(self.playlist.next) self.playback.addAction(self.play_playback_action) self.playback.addAction(self.stop_playback_action) self.playback.addAction(self.previous_playback_action) self.playback.addAction(self.next_playback_action) def view_menu(self): """Add a view menu to the menu bar. The view menu houses the Playlist, Media Library, Minimalist View, and Media Information menu items. The Playlist item toggles the playlist dock into and out of view. The Media Library items toggles the media library dock into and out of view. The Minimalist View item resizes the window and shows only the menu bar and player controls. The Media Information item opens a dialog that shows information relevant to the currently playing song. """ self.dock_action = self.playlist_dock.toggleViewAction() self.dock_action.setShortcut('CTRL+ALT+P') self.library_dock_action = self.library_dock.toggleViewAction() self.library_dock_action.setShortcut('CTRL+ALT+L') self.minimalist_view_action = QAction('Minimalist View', self) self.minimalist_view_action.setShortcut('CTRL+ALT+M') self.minimalist_view_action.setCheckable(True) self.minimalist_view_action.triggered.connect(self.minimalist_view) self.view_media_info_action = QAction('Media Information', self) self.view_media_info_action.setShortcut('CTRL+SHIFT+M') self.view_media_info_action.triggered.connect(self.media_information_dialog) self.view.addAction(self.dock_action) self.view.addAction(self.library_dock_action) self.view.addSeparator() self.view.addAction(self.minimalist_view_action) self.view.addSeparator() self.view.addAction(self.view_media_info_action) def help_menu(self): """Add a help menu to the menu bar. The help menu houses the about dialog that shows the user information related to the application. """ self.about_action = QAction('About', self) self.about_action.setShortcut('H') self.about_action.triggered.connect(lambda: about.AboutDialog().exec_()) self.help_.addAction(self.about_action) def open_file(self): """Open the selected file and add it to a new playlist.""" filename, success = QFileDialog.getOpenFileName(self, 'Open File', '', 'Audio (*.mp3 *.flac)', '', QFileDialog.ReadOnly) if success: file_info = QFileInfo(filename).fileName() playlist_item = QListWidgetItem(file_info) self.playlist.clear() self.playlist_view.clear() self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(filename))) self.player.setPlaylist(self.playlist) playlist_item.setToolTip(file_info) self.playlist_view.addItem(playlist_item) self.playlist_view.setCurrentRow(0) self.player.play() def open_multiple_files(self): """Open the selected files and add them to a new playlist.""" filenames, success = QFileDialog.getOpenFileNames(self, 'Open Multiple Files', '', 'Audio (*.mp3 *.flac)', '', QFileDialog.ReadOnly) if success: self.playlist.clear() self.playlist_view.clear() for file in natsort.natsorted(filenames, alg=natsort.ns.PATH): file_info = QFileInfo(file).fileName() playlist_item = QListWidgetItem(file_info) self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file))) self.player.setPlaylist(self.playlist) playlist_item.setToolTip(file_info) self.playlist_view.addItem(playlist_item) self.playlist_view.setCurrentRow(0) self.player.play() def open_playlist(self): """Load an M3U or PLS file into a new playlist.""" playlist, success = QFileDialog.getOpenFileName(self, 'Open Playlist', '', 'Playlist (*.m3u *.pls)', '', QFileDialog.ReadOnly) if success: playlist = QUrl.fromLocalFile(playlist) self.playlist.clear() self.playlist_view.clear() self.playlist.load(playlist) self.player.setPlaylist(self.playlist) for song_index in range(self.playlist.mediaCount()): file_info = self.playlist.media(song_index).canonicalUrl().fileName() playlist_item = QListWidgetItem(file_info) playlist_item.setToolTip(file_info) self.playlist_view.addItem(playlist_item) self.playlist_view.setCurrentRow(0) self.player.play() def save_playlist(self): """Save the media in the playlist dock as a new M3U playlist.""" playlist, success = QFileDialog.getSaveFileName(self, 'Save Playlist', '', 'Playlist (*.m3u)', '') if success: saved_playlist = "{}.m3u" .format(playlist) self.playlist.save(QUrl().fromLocalFile(saved_playlist), "m3u") def load_saved_playlist(self): """Load the saved playlist if user setting permits.""" saved_playlist = "{}/.m3u" .format(self.playlist_location) if os.path.exists(saved_playlist): playlist = QUrl().fromLocalFile(saved_playlist) self.playlist.load(playlist) self.player.setPlaylist(self.playlist) for song_index in range(self.playlist.mediaCount()): file_info = self.playlist.media(song_index).canonicalUrl().fileName() playlist_item = QListWidgetItem(file_info) playlist_item.setToolTip(file_info) self.playlist_view.addItem(playlist_item) self.playlist_view.setCurrentRow(0) def open_directory(self): """Open the selected directory and add the files within to an empty playlist.""" directory = QFileDialog.getExistingDirectory(self, 'Open Directory', '', QFileDialog.ReadOnly) if directory: self.playlist.clear() self.playlist_view.clear() for dirpath, __, files in os.walk(directory): for filename in natsort.natsorted(files, alg=natsort.ns.PATH): file = os.path.join(dirpath, filename) if filename.endswith(('mp3', 'flac')): self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file))) playlist_item = QListWidgetItem(filename) playlist_item.setToolTip(filename) self.playlist_view.addItem(playlist_item) self.player.setPlaylist(self.playlist) self.playlist_view.setCurrentRow(0) self.player.play() def open_media_library(self, index): """Open a directory or file from the media library into an empty playlist.""" self.playlist.clear() self.playlist_view.clear() if self.library_model.fileName(index).endswith(('mp3', 'flac')): self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(self.library_model.filePath(index)))) self.playlist_view.addItem(self.library_model.fileName(index)) elif self.library_model.isDir(index): directory = self.library_model.filePath(index) for dirpath, __, files in os.walk(directory): for filename in natsort.natsorted(files, alg=natsort.ns.PATH): file = os.path.join(dirpath, filename) if filename.endswith(('mp3', 'flac')): self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file))) playlist_item = QListWidgetItem(filename) playlist_item.setToolTip(filename) self.playlist_view.addItem(playlist_item) self.player.setPlaylist(self.playlist) self.player.play() def display_meta_data(self): """Display the current song's metadata in the main window. If the current song contains metadata, its cover art is extracted and shown in the main window while the track number, artist, album, and track title are shown in the window title. """ if self.player.isMetaDataAvailable(): file_path = self.player.currentMedia().canonicalUrl().toLocalFile() (album, artist, title, track_number, *__, artwork) = metadata.metadata(file_path) try: self.pixmap.loadFromData(artwork) except TypeError: self.pixmap = QPixmap(artwork) meta_data = '{} - {} - {} - {}' .format(track_number, artist, album, title) self.setWindowTitle(meta_data) self.art.setScaledContents(True) self.art.setPixmap(self.pixmap) self.layout.addWidget(self.art) def initialize_playlist(self, start): """Display playlist and reset playback mode when media inserted into playlist.""" if start == 0: if self.library_dock.isVisible(): self.playlist_dock.setVisible(True) self.playlist_dock.show() self.playlist_dock.raise_() if self.playlist.playbackMode() != QMediaPlaylist.Sequential: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png') self.repeat_action.setIcon(QIcon(repeat_icon)) def press_playback(self, event): """Change the playback of the player on cover art mouse event. When the cover art is clicked, the player will play the media if the player is either paused or stopped. If the media is playing, the media is set to pause. """ if event.button() == 1 and configuration.Playback().cover_art_playback.isChecked(): if (self.player.state() == QMediaPlayer.StoppedState or self.player.state() == QMediaPlayer.PausedState): self.player.play() elif self.player.state() == QMediaPlayer.PlayingState: self.player.pause() def seek(self, seconds): """Set the position of the song to the position dragged to by the user.""" self.player.setPosition(seconds * 1000) def song_duration(self, duration): """Set the slider to the duration of the currently played media.""" duration /= 1000 self.duration = duration self.slider.setMaximum(duration) def song_position(self, progress): """Move the horizontal slider in sync with the duration of the song. The progress is relayed to update_duration() in order to display the time label next to the slider. """ progress /= 1000 if not self.slider.isSliderDown(): self.slider.setValue(progress) self.update_duration(progress) def update_duration(self, current_duration): """Calculate the time played and the length of the song. Both of these times are sent to duration_label() in order to display the times on the toolbar. """ duration = self.duration if current_duration or duration: time_played = QTime((current_duration / 3600) % 60, (current_duration / 60) % 60, (current_duration % 60), (current_duration * 1000) % 1000) song_length = QTime((duration / 3600) % 60, (duration / 60) % 60, (duration % 60), (duration * 1000) % 1000) if duration > 3600: time_format = "hh:mm:ss" else: time_format = "mm:ss" time_display = "{} / {}" .format(time_played.toString(time_format), song_length.toString(time_format)) else: time_display = "" self.duration_label.setText(time_display) def set_state(self, state): """Change the icon in the toolbar in relation to the state of the player. The play icon changes to the pause icon when a song is playing and the pause icon changes back to the play icon when either paused or stopped. """ if self.player.state() == QMediaPlayer.PlayingState: pause_icon = utilities.resource_filename('mosaic.images', 'md_pause.png') self.play_action.setIcon(QIcon(pause_icon)) self.play_action.triggered.connect(self.player.pause) elif (self.player.state() == QMediaPlayer.PausedState or self.player.state() == QMediaPlayer.StoppedState): self.play_action.triggered.connect(self.player.play) play_icon = utilities.resource_filename('mosaic.images', 'md_play.png') self.play_action.setIcon(QIcon(play_icon)) def previous(self): """Move to the previous song in the playlist. Moves to the previous song in the playlist if the current song is less than five seconds in. Otherwise, restarts the current song. """ if self.player.position() <= 5000: self.playlist.previous() else: self.player.setPosition(0) def repeat_song(self): """Set the current media to repeat and change the repeat icon accordingly. There are four playback modes: repeat none, repeat all, repeat once, and shuffle. Clicking the repeat button cycles through each playback mode. """ if self.playlist.playbackMode() == QMediaPlaylist.Sequential: self.playlist.setPlaybackMode(QMediaPlaylist.Loop) repeat_on_icon = utilities.resource_filename('mosaic.images', 'md_repeat_all.png') self.repeat_action.setIcon(QIcon(repeat_on_icon)) elif self.playlist.playbackMode() == QMediaPlaylist.Loop: self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop) repeat_on_icon = utilities.resource_filename('mosaic.images', 'md_repeat_once.png') self.repeat_action.setIcon(QIcon(repeat_on_icon)) elif self.playlist.playbackMode() == QMediaPlaylist.CurrentItemInLoop: self.playlist.setPlaybackMode(QMediaPlaylist.Random) repeat_icon = utilities.resource_filename('mosaic.images', 'md_shuffle.png') self.repeat_action.setIcon(QIcon(repeat_icon)) elif self.playlist.playbackMode() == QMediaPlaylist.Random: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png') self.repeat_action.setIcon(QIcon(repeat_icon)) def activate_playlist_item(self, item): """Set the active media to the playlist item dobule-clicked on by the user.""" current_index = self.playlist_view.row(item) if self.playlist.currentIndex() != current_index: self.playlist.setCurrentIndex(current_index) if self.player.state() != QMediaPlayer.PlayingState: self.player.play() def change_index(self, row): """Highlight the row in the playlist of the active media.""" self.playlist_view.setCurrentRow(row) def minimalist_view(self): """Resize the window to only show the menu bar and audio controls.""" if self.minimalist_view_action.isChecked(): if self.playlist_dock.isVisible(): self.playlist_dock_state = True if self.library_dock.isVisible(): self.library_dock_state = True self.library_dock.close() self.playlist_dock.close() QTimer.singleShot(10, lambda: self.resize(500, 0)) else: self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63) if self.library_dock_state: self.library_dock.setVisible(True) if self.playlist_dock_state: self.playlist_dock.setVisible(True) def dock_visiblity_change(self, visible): """Change the size of the main window when the docks are toggled.""" if visible and self.playlist_dock.isVisible() and not self.library_dock.isVisible(): self.resize(defaults.Settings().window_size + self.playlist_dock.width() + 6, self.height()) elif visible and not self.playlist_dock.isVisible() and self.library_dock.isVisible(): self.resize(defaults.Settings().window_size + self.library_dock.width() + 6, self.height()) elif visible and self.playlist_dock.isVisible() and self.library_dock.isVisible(): self.resize(defaults.Settings().window_size + self.library_dock.width() + 6, self.height()) elif (not visible and not self.playlist_dock.isVisible() and not self.library_dock.isVisible()): self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63) def media_information_dialog(self): """Show a dialog of the current song's metadata.""" if self.player.isMetaDataAvailable(): file_path = self.player.currentMedia().canonicalUrl().toLocalFile() else: file_path = None dialog = information.InformationDialog(file_path) dialog.exec_() def change_window_size(self): """Change the window size of the music player.""" self.playlist_dock.close() self.library_dock.close() self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63) def change_media_library_path(self, path): """Change the media library path to the new path selected in the preferences dialog.""" self.library_model.setRootPath(path) self.library_view.setModel(self.library_model) self.library_view.setRootIndex(self.library_model.index(path)) def closeEvent(self, event): """Override the PyQt close event in order to handle save playlist on close.""" playlist = "{}/.m3u" .format(self.playlist_location) if defaults.Settings().save_playlist_on_close: self.playlist.save(QUrl().fromLocalFile(playlist), "m3u") else: if os.path.exists(playlist): os.remove(playlist) QApplication.quit()
class mainWindow(QTabWidget): sendMessage = pyqtSignal(list, name='sendMessage') selectFriend = pyqtSignal(list, name='selectFriend') selectAutoGroup = pyqtSignal(list, name='selectAutoGroup') imgHeadRequest = pyqtSignal(str, name='imgHeadRequest') friendAutoReply = pyqtSignal(int, name='friendAutoReply') # 朋友自动回复 chatroom_num = 0 # 群个数 selectGroupAutoReply = [] # 自动回复的群 ''' 通讯录信息 | NickName ,Sex,Province,City,signature,FromUserName| ''' AllFriendsInfo = {} def __init__(self): super().__init__() self.focusID = 0 # self.setStyle('qrc/black.qss') self.createActions() self.createTrayIcon() self.init() def setStyle(self, _qssPath): with open(_qssPath, encoding='UTF-8') as file: str = file.read() qss = ''.join(str) self.setStyleSheet(qss) def init(self): self.tabChat = QWidget() self.tabContact = QWidget() self.tabSet = QWidget() self.addTab(self.tabChat, '微信') self.addTab(self.tabContact, '通讯录') self.addTab(self.tabSet, '设置') self.tabChatInit() self.setInit() self.contactInit() # self.leftLayout = QVBoxLayout() # self.rightLayout = QVBoxLayout() # mainLayout = QGridLayout() # # self.contact = QListWidget() # self.leftLayout.addWidget(self.contact) # # self.chatroom = QLineEdit() # self.chatroom.setText('This is ChatRoom') # self.chatlog = QLabel() # self.chatlog.setText('This is ChatLog') # # self.rightLayout.addWidget(self.chatlog) # self.rightLayout.addWidget(self.chatroom) # # mainLayout.addLayout(self.leftLayout, 0, 0, 1, 1) # mainLayout.addLayout(self.rightLayout, 0, 1, 1, 3) # # self.setLayout(mainLayout) self.setWindowTitle(self.tr('Wechat_alpha')) def addChatFriend(self, _NickName, _RemarkName): item = QListWidgetItem() str = _NickName if _RemarkName is not '': str += '[' + _RemarkName + ']' item.setText(str) self.listChatting.addItem(item) # 通讯录写入名单 def fillContact(self, _fullContact): # self.AllFriendsInfo = _fullContact for each in _fullContact: item = QListWidgetItem() str = each['RemarkName'] if str is '': str = each['NickName'] item.setText(str) self.contactList.addItem(item) # | NickName, Sex, Province, City, signature, FromUserName | self.AllFriendsInfo[str] = [ each['NickName'], each['Sex'], each['Province'], each['City'], each['Signature'], each['UserName'] ] # 群自动回复----获得群名 def setChatroomFill(self, _chatroom): self.chatroom_num = 0 for each in _chatroom: self.chatroom_num += 1 # self.chatroomInfo[each['NickName']] = each['UserName'] item = QListWidgetItem() str = each['NickName'] item.setText(str) self.allGroupList.addItem(item) # print(self.chatroomInfo) def contactInit(self): size = self.size() self.contactList = QListWidget() self.contactList.setFixedSize(size.width() / 3, size.height()) self.contactList.setVerticalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOn) self.contactList.itemClicked.connect(self.contactListClick) infoWidget = QWidget() infoWidget.setFixedSize(size.width() * 2 / 3, size.height()) topLayout = QGridLayout() midLayout = QVBoxLayout() bottomLayout = QHBoxLayout() # top self.headLabel = QLabel() # 头像 self.headLabel.setFixedSize(150, 150) self.headLabel.setScaledContents(True) self.signatureLabel = QLabel() # 签名 self.signatureLabel.setAlignment(QtCore.Qt.AlignVCenter) self.nickNameLabel = QLabel() # 微信名 self.nickNameLabel.setAlignment(QtCore.Qt.AlignVCenter) topLayout.addWidget(self.nickNameLabel, 1, 0, 1, 3) topLayout.addWidget(self.signatureLabel, 2, 0, 1, 3) topLayout.addWidget(self.headLabel, 0, 1, 1, 1) # mid self.remarkNameLabel = QLabel() # 备注 self.cityLabel = QLabel() # 城市 midLayout.addWidget(self.remarkNameLabel) midLayout.addWidget(self.cityLabel) # bottom self.sendMsgBtn = QPushButton('发消息') bottomLayout.addWidget(self.sendMsgBtn) layout = QGridLayout() infoLayout = QVBoxLayout() infoLayout.addLayout(topLayout) infoLayout.addLayout(midLayout) infoLayout.addLayout(bottomLayout) infoLayout.addSpacing(10) infoWidget.setLayout(infoLayout) layout.addWidget(self.contactList, 0, 0, 1, 1) layout.addWidget(infoWidget, 0, 1, 1, 2) self.tabContact.setLayout(layout) def setInit(self): setTab = QTabWidget(self.tabSet) setTab.setTabPosition(QTabWidget.West) # 方向 size = self.size() #############################自动回复################################ btnAutoSet = QPushButton('应用') btnAutoCancel = QPushButton('取消') btnAutoCancel.clicked.connect(self.clearSelectList) btnAutoSet.clicked.connect(self.setSelectList) btnLayout = QHBoxLayout() btnLayout.addWidget(btnAutoSet) btnLayout.addSpacing(5) btnLayout.addWidget(btnAutoCancel) self.allGroupList = QListWidget() self.selectGroupList = QListWidget() # 选定自动回复的 self.allGroupList.setFixedSize(size.width() * 3 / 7, size.height() * 2 / 3) self.selectGroupList.setFixedSize(size.width() * 3 / 7, size.height() * 2 / 3) self.allGroupList.setVerticalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOn) self.selectGroupList.setVerticalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOn) self.allGroupList.itemDoubleClicked.connect(self.aGroupDoubleClick) self.selectGroupList.itemDoubleClicked.connect(self.sGroupDoubleClick) self.setAutoLayout = QGridLayout() self.autoReplyFriend = QCheckBox('自动回复') self.autoReplyFriend.stateChanged.connect(self.setFriendAutoReply) self.setAutoLayout.setSpacing(10) self.setAutoLayout.addWidget(self.autoReplyFriend, 0, 0, 1, 1) self.setAutoLayout.addWidget(self.allGroupList, 1, 0, 10, 1) self.setAutoLayout.addWidget(self.selectGroupList, 1, 1, 10, 1) self.setAutoLayout.addLayout(btnLayout, 12, 1, 1, 1) # for each in self.ChatroomCheckBoxList: # self.setAutoLayout.addWidget(each) tabAuto = QWidget() tabAuto.setLayout(self.setAutoLayout) ##################################################################### # 其他 self.showLabel = QLabel() self.showLabel.setScaledContents(True) self.showLabel.setFixedSize(size.width() * 2 / 3, size.width() * 2 / 3) sexDisttibutionBtn = QPushButton('性别分布') wordCouldBtn = QPushButton('签名词图') sexDisttibutionBtn.clicked.connect(self.calSex) wordCouldBtn.clicked.connect(self.generateWordCloud) layout = QGridLayout() layout.addWidget(self.showLabel, 0, 0, 2, 2) layout.addWidget(sexDisttibutionBtn, 2, 0, 1, 1) layout.addWidget(wordCouldBtn, 2, 1, 1, 1) tabFun = QWidget() tabFun.setLayout(layout) ##################################################################### setTab.addTab(tabAuto, '自动回复') setTab.addTab(tabFun, '特色功能') # setTab.addTab('其他') def tabChatInit(self): size = self.size() layout = QGridLayout() self.listChatting = QListWidget() self.listChatting.setFixedSize(size.width() / 3, size.height()) self.chatLog = QTextBrowser() self.chatLog.document().setMaximumBlockCount(1000) # 限制1000行 self.chatLog.setFixedSize(size.width() * 2 / 3, size.height() * 2 / 3) self.textInput = QTextEdit() self.textInput.setFixedSize(size.width() * 2 / 3, size.height() / 4) self.btnSend = QPushButton() self.btnSend.setText('发送') # 显示正在聊天的朋友 self.chattingFri = QLabel('当前聊天朋友:_____') self.btnSend.clicked.connect(self.sendMsg) self.listChatting.itemClicked.connect(self.listClick) self.chatLog.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.chatLog.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) layout.addWidget(self.listChatting, 0, 0, 6, 1) layout.addWidget(self.chatLog, 0, 1, 3, 3) layout.addWidget(self.textInput, 3, 1, 2, 3) layout.addWidget(self.chattingFri, 5, 1, 1, 1) layout.addWidget(self.btnSend, 5, 3, 1, 1) self.tabChat.setLayout(layout) def showChatLog(self, _Msg): # count = -1 # # for count, line in enumerate(open(thefilepath, 'rU')): # # pass # # count += 1 msg_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(_Msg['time'])) content = _Msg['content'] if _Msg['fromusr'] == _Msg['selfusr']: self.chatLog.append(msg_time + '\n' + '我' + ':' + content + '\n') else: fromFriend = _Msg['remarkname'] self.chatLog.append(msg_time + '\n' + fromFriend + ':' + content + '\n') def showSendChatLog(self, _Msg): msg_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(time.time()))) content = _Msg[0] self.chatLog.append(msg_time + '\n' + '我' + ':' + content + '\n') @pyqtSlot() def sendMsg(self): sMsg = self.textInput.toPlainText() print("::", sMsg) if sMsg != '': self.textInput.clear() self.sendMessage.emit([sMsg]) @pyqtSlot(QListWidgetItem) def listClick(self, item): self.selectFriend.emit([item.text()]) print('好友:', item.text()) @pyqtSlot(QListWidgetItem) def contactListClick(self, item): global curTmpImg # | NickName, Sex, Province, City, signature, FromUserName | cur = self.AllFriendsInfo[item.text()] self.imgHeadRequest.emit(cur[5]) if curTmpImg: png = QtGui.QPixmap() png.loadFromData(curTmpImg) # png.scaled((50,50)) self.headLabel.setPixmap(png) curTmpImg = None self.signatureLabel.setText('签名 ' + ''.join(cur[4])) # 签名 str = ''.join(cur[0]) if cur[1] == 1: str += ' ♂' else: str += ' ♀' self.nickNameLabel.setText('微信 ' + str) # 微信名 self.remarkNameLabel.setText('备注 ' + item.text()) # 备注 self.cityLabel.setText('地区 ' + ''.join(cur[2] + ' ' + cur[3])) # 城市 # add to select list @pyqtSlot(QListWidgetItem) def aGroupDoubleClick(self, item): select = item.text() item = QListWidgetItem() item.setText(select) self.selectGroupList.addItem(item) self.selectGroupAutoReply.append(select) # remove select item from list @pyqtSlot(QListWidgetItem) def sGroupDoubleClick(self, item): select = item.text() self.selectGroupList.removeItemWidget( self.selectGroupList.takeItem(self.selectGroupList.row(item))) self.selectGroupAutoReply.remove(select) @pyqtSlot(int) def setFriendAutoReply(self, _state): self.friendAutoReply.emit(_state) # 清空选定 def clearSelectList(self): self.selectGroupList.clear() self.selectGroupAutoReply.clear() # 应用群自动回复 def setSelectList(self): self.selectAutoGroup.emit(self.selectGroupAutoReply) # 获取头像 def postUserHead(self, _img): global curTmpImg curTmpImg = _img # print(_img) # 更改当前聊天朋友名字显示 def changeChattingFri(self, _str): self.chattingFri.setText('当前发送:' + _str[0]) # 计算性别 def calSex(self): # 设置全局字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决‘-’表现为方块的问题 plt.rcParams['axes.unicode_minus'] = False female = 0 total = len(self.AllFriendsInfo) for each in self.AllFriendsInfo.values(): if each[1] is 2: female += 1 male = total - female data = {'男性(人)': (male, '#7199cf'), '女性(人)': (female, '#ffff10')} # 设置绘图对象的大小 fig = plt.figure(figsize=(8, 8)) sex = data.keys() values = [x[0] for x in data.values()] colors = [x[1] for x in data.values()] ax1 = fig.add_subplot(111) ax1.set_title('性别比例') labels = [ '{}:{}'.format(city, value) for city, value in zip(sex, values) ] # 设置饼图的凸出显示 explode = [0, 0.1] # 画饼状图, 并且指定标签和对应的颜色 # 指定阴影效果 ax1.pie(values, labels=labels, colors=colors, explode=explode, shadow=True) pngPath = 'cache/_sd/sd.jpg' plt.savefig(pngPath) # plt.show() if os.path.exists(pngPath): png = QtGui.QPixmap(pngPath) self.showLabel.setPixmap(png) # 生成词云 def generateWordCloud(self): signature = [each[4] for each in self.AllFriendsInfo.values()] text = ','.join(signature) pattern = re.compile('<span.*?</span>') # 匹配表情 text = re.sub(repl='', string=text, pattern=pattern) # 删除表情 coloring = np.array(Image.open("qrc/back.jpg")) my_wordcloud = wordcloud.WordCloud( background_color="white", max_words=2000, mask=coloring, max_font_size=60, random_state=42, scale=2, font_path="qrc/FZSTK.ttf" ).generate( text ) # 生成词云。font_path="C:\Windows\Fonts\msyhl.ttc"指定字体,有些字不能解析中文,这种情况下会出现乱码。 file_name_p = 'cache/word/wc.jpg' my_wordcloud.to_file(file_name_p) # 保存图片 if os.path.exists(file_name_p): png = QtGui.QPixmap(file_name_p) self.showLabel.setPixmap(png) def createTrayIcon(self): ''' 创建托盘图标,可以让程序最小化到windows托盘中运行 :return: ''' self.trayIconMenu = QMenu(self) self.trayIconMenu.addAction(self.restoreAction) self.trayIconMenu.addSeparator() self.trayIconMenu.addAction(self.quitAction) self.trayIcon = QSystemTrayIcon(self) self.trayIcon.setContextMenu(self.trayIconMenu) self.trayIcon.setIcon(QIcon('qrc/icon.png')) self.setWindowIcon(QIcon('qrc/icon.png')) self.trayIcon.show() def createActions(self): ''' 为托盘图标添加功能 :return: ''' self.restoreAction = QAction("来喽", self, triggered=self.showNormal) self.quitAction = QAction("告辞", self, triggered=QApplication.instance().quit) def iconActivated(self, reason): ''' 激活托盘功能 :param reason: :return: ''' if reason in (QSystemTrayIcon.Trigger, QSystemTrayIcon.DoubleClick): self.showNormal() # 弹窗提醒 def msgWarning(self, _message, _type): if _type == 0: QMessageBox.information(self, "红包提醒", _message, QMessageBox.Yes) else: QMessageBox.information(self, "撤回提醒", _message, QMessageBox.Yes)
class PeersDialog(QDialog): def __init__(self, peers): super().__init__() self.peers = peers self.setWindowModality(Qt.ApplicationModal) self.setMaximumSize(500, 200) self.setMinimumSize(500, 200) self.resize(500, 200) self.setLayout(QHBoxLayout()) self.listWidget = QListWidget(self) self.listWidget.setAlternatingRowColors(True) self.layout().addWidget(self.listWidget) for peer in self.peers: self.listWidget.addItem(peer['uri']) self.buttonsLayout = QVBoxLayout() self.layout().addLayout(self.buttonsLayout) self.discoverPeersButton = QPushButton(self) self.addPeerButton = QPushButton(self) self.removePeerButton = QPushButton(self) self.removeAllButton = QPushButton(self) self.discoverPeersButton.clicked.connect(self.discover_peers) self.addPeerButton.clicked.connect(self.add_peer) self.removePeerButton.clicked.connect(self.remove_peer) self.removeAllButton.clicked.connect(self.remove_all) self.buttonsLayout.addWidget(self.discoverPeersButton) self.buttonsLayout.addWidget(self.addPeerButton) self.buttonsLayout.addWidget(self.removePeerButton) self.buttonsLayout.addWidget(self.removeAllButton) self.buttonsLayout.addSpacing(70) self.dialogButton = QDialogButtonBox(self) self.dialogButton.setStandardButtons(self.dialogButton.Ok) self.dialogButton.accepted.connect(self.accept) self.buttonsLayout.addWidget(self.dialogButton) self.layout().setStretch(0, 2) self.layout().setStretch(1, 1) self.retranslateUi() def retranslateUi(self): self.setWindowTitle("Manage connected peers") self.discoverPeersButton.setText('Discover peers') self.addPeerButton.setText("Manually add a peer") self.removePeerButton.setText("Remove selected peer") self.removeAllButton.setText("Remove all peers") def add_peer(self): ip, ok = QInputDialog.getText(None, 'Address', 'Peer IP') if ok: self._add_peer(ip) def _add_peer(self, ip): port = config['Remote']['BindPort'] uri = compose_uri(ip, port) for peer in self.peers: if peer['uri'] == uri: QMessageBox.critical(None, 'Error', 'Already connected') return try: peer = {'proxy': RemoteController.connect_to(uri), 'uri': uri} self.peers.append(peer) self.listWidget.addItem(peer['uri']) except Exception as e: QMessageBox.critical(None, 'Error', str(e)) def discover_peers(self): dialog = PeersDiscoveryDialog() if dialog.exec_() == dialog.Accepted: for peer in dialog.get_peers(): self._add_peer(peer) def remove_peer(self): if len(self.listWidget.selectedIndexes()) != 0: self.peers.pop(self.current_index()) self.listWidget.takeItem(self.current_index()) def remove_all(self): self.peers.clear() self.listWidget.clear() def current_index(self): return self.listWidget.selectedIndexes()[0].row()
class FoldersManager(QWidget): def __init__(self, main_parent=None): super(FoldersManager, self).__init__() self.mainwindow = main_parent self.setAttribute(Qt.WA_DeleteOnClose) self.setGeometry(50, 50, 350, 250) self.setMinimumSize(450, 350) self.setMaximumSize(450, 350) self.setFont(QFont("Consolas", 10)) self.setWindowTitle("Folders Manager") self.setWindowIcon(QIcon(files.Images.HQPLAYER_LOGO)) self.explanation_label = QLabel(self) self.explanation_label.setGeometry(14, 20, 250, 16) self.explanation_label.setToolTip("Music folders used for the playlist.") self.explanation_label.setText("Music folders used for the playlist.") self.add_button = QPushButton(self) self.add_button.setGeometry(405, 60, 25, 25) self.add_button.setToolTip("Add folder") self.add_button.setIcon(QIcon(files.Images.ADD)) self.add_button.setIconSize(QSize(25, 25)) self.add_button.setFocusPolicy(Qt.ClickFocus) self.remove_button = QPushButton(self) self.remove_button.setGeometry(405, 90, 25, 25) self.remove_button.setToolTip("Remove folder") self.remove_button.setIcon(QIcon(files.Images.REMOVE)) self.remove_button.setIconSize(QSize(25, 25)) self.remove_button.setFocusPolicy(Qt.ClickFocus) self.folder_list = QListWidget(self) self.folder_list.setGeometry(10, 40, 373, 300) self.folder_list.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.folder_list.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.folder_list.setEditTriggers(QListWidget.SelectedClicked) self.folder_list.setDefaultDropAction(Qt.IgnoreAction) self.add_button.released.connect(self.ab_released) self.add_button.clicked.connect(self.ab_clicked) self.remove_button.released.connect(self.rm_released) self.remove_button.clicked.connect(self.rm_clicked) def remove_sel(self): list_items = self.folder_list.selectedItems() if not list_items: return for item in list_items: self.folder_list.takeItem(self.folder_list.row(item)) def refresh_list(self): self.folder_list.clear() if self.mainwindow.options.user_music_folders is not None: for folder in self.mainwindow.options.user_music_folders: self.folder_list.addItem(folder) self.folder_list.sortItems() def get_selected_item(self): return (self.folder_list.selectedItems()[0]).text() def ab_released(self): self.add_button.clearFocus() def rm_released(self): self.remove_button.clearFocus() def ab_clicked(self): file_dialog = QFileDialog() file_dialog.setFileMode(QFileDialog.DirectoryOnly) file_dialog.setDirectory(self.mainwindow.options.get_default_last_folder_opened()) file_dialog.setOption(QFileDialog.DontUseNativeDialog, True) file_view = file_dialog.findChild(QListView, 'listView') # to make it possible to select multiple directories: if file_view: file_view.setSelectionMode(QAbstractItemView.MultiSelection) f_tree_view = file_dialog.findChild(QTreeView) if f_tree_view: f_tree_view.setSelectionMode(QAbstractItemView.MultiSelection) if file_dialog.exec(): folders = file_dialog.selectedFiles() if len(folders) != 0: for folder in folders: parent_folder = os.path.dirname(r"{}".format(folder)) self.mainwindow.options.save_user_defaults(music_folder=folder, last_folder_opened=parent_folder) self.folder_list.addItem(folder) self.folder_list.sortItems() # folder = QFileDialog.getExistingDirectory(self, "Add Folder(s)", # self.mainwindow.options.get_default_last_folder_opened(), # QFileDialog.ShowDirsOnly) def rm_clicked(self): if len(self.folder_list.selectedItems()) != 0: self.mainwindow.options.delete_music_folder(self.get_selected_item()) self.remove_sel()
class Dimili(QMainWindow): def baslat(self, anaPencere): anaPencere.resize(600, 400) anaPencere.setWindowTitle("Dimili-Türkçe Sözlük") anaPencere.setFixedSize(600,400) icon =QIcon() icon.addPixmap(QPixmap("Dictionary.png"),QIcon.Normal,QIcon.Off) anaPencere.setWindowIcon(icon) zemin=QWidget(anaPencere) zemin.setGeometry(QRect(0,30,600,390)) zemin.setStyleSheet("background-color:rgb(167, 196, 233);") self.araKutu = QLineEdit(anaPencere) self.araKutu.setGeometry(QRect(10, 80, 200, 20)) self.araKutu.textChanged.connect(self.benzerKelimeler) self.kelimeGir = QLabel("Kelimeler:",anaPencere) self.kelimeGir.setGeometry(QRect(10, 110, 141, 21)) self.kelimeGor = QLabel("Kelime Ara",anaPencere) self.kelimeGor.setGeometry(QRect(10, 30, 91, 16)) self.harfGrup=QButtonGroup(anaPencere) aharf=QPushButton("â",anaPencere) aharf.setGeometry(QRect(10,50,25,25)) eharf=QPushButton("é",anaPencere) eharf.setGeometry(QRect(30,50,25,25)) self.DilGrup=QButtonGroup(anaPencere) self.Dil1 = QPushButton("Zazaca-Türkçe",anaPencere) self.Dil1.setGeometry(QRect(230, 80, 91, 23)) self.Dil1.setCheckable(True) self.Dil1.setAutoExclusive(True) self.Dil1.setChecked(True) self.Dil1.setStyleSheet("background-color: rgb(102, 255, 0);") self.Dil2 = QPushButton("Türkçe-Zazaca",anaPencere) self.Dil2.setGeometry(QRect(330, 80, 91, 23)) self.Dil2.setCheckable(True) self.Dil2.setAutoExclusive(True) self.Dil2.setStyleSheet("background-color: rgb(255, 94, 105);") self.DilGrup.addButton(self.Dil1,1) self.DilGrup.addButton(self.Dil2,2) self.DilGrup.buttonClicked[int].connect(self.dilSecme) self.kelimeListesi=QListWidget(anaPencere) self.kelimeListesi.setGeometry(QRect(10, 130, 191, 231)) self.kelimeListesi.itemClicked.connect(self.kelimeAcikla) self.kelimeAnlam = QLabel("Kelimenin Anlamı:",anaPencere) self.kelimeAnlam.setGeometry(QRect(230, 110, 131, 21)) self.cumleList1 = QListWidget(anaPencere) self.cumleList1.setGeometry(QRect(230, 130, 351, 51)) self.ornekCumle1 = QLabel("Örnek Zazaca Cümle:",anaPencere) self.ornekCumle1.setGeometry(QRect(230, 200, 101, 21)) self.cumleList2 = QListWidget(anaPencere) self.cumleList2.setGeometry(QRect(230, 220, 351, 51)) self.ornekCumle2 = QLabel("Örnek Türkçe Cümle:",anaPencere) self.ornekCumle2.setGeometry(QRect(230, 290, 111, 16)) self.cumleList3 = QListWidget(anaPencere) self.cumleList3.setGeometry(QRect(230, 310, 351, 51)) self.anaMenu = QMenuBar(anaPencere) self.anaMenu.setGeometry(QRect(0, 0, 600, 21)) self.menuDosya = QMenu("Dosya",self.anaMenu) self.menuDuzenle = QMenu("Düzenle",self.anaMenu) self.menuYardim = QMenu("Yardım",self.anaMenu) anaPencere.setMenuBar(self.anaMenu) self.durum = QStatusBar(zemin) anaPencere.setStatusBar(self.durum) self.durum.setStyleSheet("background-color:white") self.durum.showMessage("Hazır") self.cikis= QAction(QIcon("Exit.ico"),"&Çıkış",anaPencere) self.cikis.setShortcut("Ctrl+X") self.cikis.triggered.connect(anaPencere.close) self.actionHakkinda = QAction("Hakkında",anaPencere) self.actionHakkinda.triggered.connect(self.hakkinda) self.actionSecenekler = QAction("Seçenekler",anaPencere) self.menuDosya.addAction(self.cikis) self.menuDuzenle.addAction(self.actionSecenekler) self.menuYardim.addAction(self.actionHakkinda) self.anaMenu.addAction(self.menuDosya.menuAction()) self.anaMenu.addAction(self.menuDuzenle.menuAction()) self.anaMenu.addAction(self.menuYardim.menuAction()) def kelimeAcikla(self): if self.DilGrup.checkedId()==1: self.cumleList1.clear() self.cumleList2.clear() self.cumleList3.clear() itemtext= [str(x.text()) for x in self.kelimeListesi.selectedItems()] for it in itemtext: itemtext=it self.im.execute("select Tur from DimTur where Zazaca=?",[itemtext]) turliste=[tur[0] for tur in self.im.fetchall()] for tura in turliste: turliste=tura self.im.execute("select Turkce from DimTur where Zazaca=?",[itemtext]) turkAnlam=[tur[0] for tur in self.im.fetchall()] for tr in turkAnlam: self.cumleList1.addItem(itemtext+"("+turliste+")"+" : "+tr) self.im.execute("select OrnekZazacaCumle from DimTur where Zazaca=?",[itemtext]) ornekZaza=[zaza[0] for zaza in self.im.fetchall()] for za in ornekZaza: ornekZaza=za self.cumleList2.addItem(ornekZaza) self.im.execute("select OrnekTurkceCumle from DimTur where Zazaca=?",[itemtext]) ornekTurk=[turk[0] for turk in self.im.fetchall()] for orn in ornekTurk: ornekTurk=orn self.cumleList3.addItem(ornekTurk) if self.DilGrup.checkedId()==2: self.cumleList1.clear() self.cumleList2.clear() self.cumleList3.clear() itemtext= [str(x.text()) for x in self.kelimeListesi.selectedItems()] for it in itemtext: itemtext=it self.im.execute("select Tur from DimTur where Turkce=?",[itemtext]) turliste=[tur[0] for tur in self.im.fetchall()] for tura in turliste: turliste=tura self.im.execute("select Zazaca from DimTur where Turkce=?",[itemtext]) zazaAnlam=[tur[0] for tur in self.im.fetchall()] for tr in zazaAnlam: self.cumleList1.addItem(itemtext+"("+turliste+")"+" : "+tr) self.im.execute("select OrnekZazacaCumle from DimTur where Turkce=?",[itemtext]) ornekTurk=[turk[0] for turk in self.im.fetchall()] for orn in ornekTurk: ornekTurk=orn self.cumleList2.addItem(ornekTurk) self.im.execute("select OrnekTurkceCumle from DimTur where Turkce=?",[itemtext]) ornekZaza=[zaza[0] for zaza in self.im.fetchall()] for za in ornekZaza: ornekZaza=za self.cumleList3.addItem(ornekZaza) def benzerKelimeler(self): if self.DilGrup.checkedId()==1: self.VT=sqlite3.connect("DimiliVT.sqlite") self.im=self.VT.cursor() self.kelimeListesi.clear() kelime=self.araKutu.text() if kelime=="" or kelime==None: self.kelimeListesi.clear() else: self.im.execute("select Zazaca from DimTur where Zazaca like ? order by Zazaca ",[kelime+'%']) zazaListe=[za[0] for za in self.im.fetchall()] for i in zazaListe: self.kelimeListesi.addItem(i) if self.DilGrup.checkedId()==2: self.VT=sqlite3.connect("DimiliVT.sqlite") self.im=self.VT.cursor() kelime=self.araKutu.text() self.kelimeListesi.clear() if kelime=="" or kelime==None: self.kelimeListesi.clear() else: self.im.execute("select Turkce from DimTur where Turkce like ? ",[kelime+'%']) turkListe=[tu[0] for tu in self.im.fetchall()] for i in turkListe: self.kelimeListesi.addItem(i) def dilSecme(self,ind): if ind==1: self.araKutu.setText("") self.kelimeListesi.clear() self.cumleList1.clear() self.cumleList2.clear() self.cumleList3.clear() self.Dil1.setStyleSheet("background:#66FF00") self.Dil2.setStyleSheet("background-color:#E41841") if ind==2: self.araKutu.setText("") self.kelimeListesi.clear() self.cumleList1.clear() self.cumleList2.clear() self.cumleList3.clear() self.Dil2.setStyleSheet("background:#66FF00") self.Dil1.setStyleSheet("background-color:#E41841") def hakkinda(self): QMessageBox.about(self, "Program Hakkında", "Bu program <b>bla bla</b> tarafından programlanmıştır. 2015")
class MetToolsDownloadManager(QWidget): def __init__(self, iface) -> None: super().__init__() self.iface = iface self.options = get_options() self.msg_bar = MessageBar(iface) vbox = QVBoxLayout() self.setLayout(vbox) hbox = QHBoxLayout() vbox.addLayout(hbox) hbox.addWidget(QLabel('Dataset: ')) self.cbox_dataset = QComboBox() self.cbox_dataset.addItem('-') for index, (dataset_name, dataset_label) in enumerate(met_datasets.items()): self.cbox_dataset.addItem(dataset_name, dataset_name) self.cbox_dataset.setItemData(index + 1, dataset_label, Qt.ToolTipRole) self.cbox_dataset.currentIndexChanged.connect(self.on_dataset_changed) hbox.addWidget(self.cbox_dataset) hbox_product_name = QHBoxLayout() vbox.addLayout(hbox_product_name) hbox_product_name.addWidget(QLabel('Product: ')) self.cbox_product = QComboBox() self.cbox_product.currentIndexChanged.connect(self.on_product_changed) hbox_product_name.addWidget(self.cbox_product) hbox_start_datetime = QHBoxLayout() vbox.addLayout(hbox_start_datetime) self.dedit_start_date = QDateTimeEdit() self.dedit_start_date.setCalendarPopup(True) hbox_start_datetime.addWidget(QLabel('Start: ')) hbox_start_datetime.addWidget(self.dedit_start_date) hbox_end_datetime = QHBoxLayout() vbox.addLayout(hbox_end_datetime) self.dedit_end_date = QDateTimeEdit() self.dedit_end_date.setCalendarPopup(True) hbox_end_datetime.addWidget(QLabel('End: ')) hbox_end_datetime.addWidget(self.dedit_end_date) gbox_extent = QGroupBox('Extent') vbox.addWidget(gbox_extent) vbox_extent = QVBoxLayout() gbox_extent.setLayout(vbox_extent) hbox_extent = QHBoxLayout() vbox_extent.addLayout(hbox_extent) self.radio_global = QRadioButton('Global') self.radio_global.toggled.connect(self.on_extent_radio_button_clicked) hbox_extent.addWidget(self.radio_global) self.radio_subset = QRadioButton('Subset') self.radio_subset.toggled.connect(self.on_extent_radio_button_clicked) hbox_extent.addWidget(self.radio_subset) self.widget_extent = QWidget() vbox_extent.addWidget(self.widget_extent) grid_extent = QGridLayout() self.widget_extent.setLayout(grid_extent) self.widget_extent.hide() self.top = add_grid_lineedit(grid_extent, 0, 'North Latitude', LAT_VALIDATOR, '°', required=True) self.right = add_grid_lineedit(grid_extent, 1, 'East Longitude', LON_VALIDATOR, '°', required=True) self.left = add_grid_lineedit(grid_extent, 2, 'West Longitude', LON_VALIDATOR, '°', required=True) self.bottom = add_grid_lineedit(grid_extent, 3, 'South Latitude', LAT_VALIDATOR, '°', required=True) self.extent_from_active_layer = QPushButton('Set from Active Layer') grid_extent.addWidget(self.extent_from_active_layer, 4, 1) self.extent_from_active_layer.clicked.connect( self.on_extent_from_active_layer_button_clicked) self.radio_global.setChecked(True) self.tree = QListWidget() vbox_tree = QVBoxLayout() vbox.addLayout(vbox_tree) vbox_tree.addWidget(self.tree) self.btn_download = QPushButton('Download') self.btn_download.clicked.connect(self.on_download_button_clicked) vbox.addWidget(self.btn_download) self.progress_bar = QProgressBar() self.progress_bar.setTextVisible(False) self.progress_bar.hide() vbox.addWidget(self.progress_bar) def on_dataset_changed(self, index: int): self.cbox_product.clear() dataset_name = self.cbox_dataset.currentData() if dataset_name is None: return auth = (self.options.rda_username, self.options.rda_password) self.products = get_met_products(dataset_name, auth) for product in self.products.keys(): self.cbox_product.addItem(product, product) def on_product_changed(self, index: int): if index == -1: return self.tree.clear() product_name = self.cbox_product.currentData() current_avail_vars = self.products[product_name] dates = [] for name in current_avail_vars.keys(): item = QListWidgetItem(current_avail_vars[name]['label']) item.setData(Qt.UserRole, name) item.setCheckState(Qt.Checked) self.tree.addItem(item) dates.append(current_avail_vars[name]['start_date']) dates.append(current_avail_vars[name]['end_date']) date_min = min(dates) date_max = max(dates) for dt_input in [self.dedit_start_date, self.dedit_end_date]: dt_input.setDateTimeRange( QDateTime(QDate(date_min.year, date_min.month, date_min.day), QTime(date_min.hour, date_min.minute)), QDateTime(QDate(date_max.year, date_max.month, date_max.day), QTime(date_max.hour, date_max.minute))) min_dt = self.dedit_start_date.minimumDateTime() max_dt = self.dedit_start_date.maximumDateTime() self.dedit_start_date.setDateTime(min_dt) self.dedit_end_date.setDateTime(max_dt) def on_download_button_clicked(self): param_names = [] for index in range(self.tree.count()): item = self.tree.item(index) if item.checkState() == Qt.Checked: param_name = item.data(Qt.UserRole) param_names.append(param_name) dataset_name = self.cbox_dataset.currentData() product_name = self.cbox_product.currentData() start_date = self.dedit_start_date.dateTime().toPyDateTime() end_date = self.dedit_end_date.dateTime().toPyDateTime() args = [ self.options.met_dir, dataset_name, product_name, start_date, end_date ] if is_met_dataset_downloaded(*args): reply = QMessageBox.question(self.iface.mainWindow( ), 'Existing dataset', ( 'You already downloaded data with the selected dataset/product/date/time combination. ' 'If you continue, this data will be removed.\n' 'Location: {}'.format(get_met_dataset_path(*args))), QMessageBox.Ok, QMessageBox.Cancel) if reply == QMessageBox.Cancel: return lat_north = self.top.value() lat_south = self.bottom.value() lon_west = self.left.value() lon_east = self.right.value() auth = (self.options.rda_username, self.options.rda_password) thread = TaskThread(lambda: download_met_dataset( self.options.met_dir, auth, dataset_name, product_name, param_names, start_date, end_date, lat_south, lat_north, lon_west, lon_east), yields_progress=True) thread.started.connect(self.on_started_download) thread.progress.connect(self.on_progress_download) thread.finished.connect(self.on_finished_download) thread.succeeded.connect(self.on_successful_download) thread.failed.connect(reraise) thread.start() def on_started_download(self) -> None: self.btn_download.hide() self.progress_bar.show() def on_progress_download(self, percent: int, status: str) -> None: self.progress_bar.setValue(percent) if status == 'submitted': self.msg_bar.info( 'Met dataset download request submitted successfully, waiting until available for download...' ) elif status == 'ready': self.msg_bar.info( 'Met dataset download request is now ready, downloading...') else: print(status) def on_finished_download(self) -> None: self.btn_download.show() self.progress_bar.hide() def on_successful_download(self) -> None: self.msg_bar.success('Meteorological dataset downloaded successfully.') Broadcast.met_datasets_updated.emit() def on_extent_radio_button_clicked(self): if self.radio_global.isChecked(): self.top.set_value(90) self.bottom.set_value(-90) self.left.set_value(-180) self.right.set_value(180) self.top.setDisabled(True) self.bottom.setDisabled(True) self.left.setDisabled(True) self.right.setDisabled(True) self.widget_extent.hide() elif self.radio_subset.isChecked(): self.widget_extent.show() self.top.setDisabled(False) self.bottom.setDisabled(False) self.left.setDisabled(False) self.right.setDisabled(False) def on_extent_from_active_layer_button_clicked(self): layer = self.iface.activeLayer() # type: Optional[QgsMapLayer] if layer is None: return layer_crs = CRS(layer.crs().toProj4()) target_crs = CRS('+proj=latlong +datum=WGS84') extent = layer.extent() # type: QgsRectangle bbox = rect_to_bbox(extent) bbox_geo = layer_crs.transform_bbox(bbox, target_crs.srs) padding = 5 # degrees lat_south = max(bbox_geo.miny - 5, -90) lat_north = min(bbox_geo.maxy + 5, 90) lon_west = max(bbox_geo.minx - 5, -180) lon_east = min(bbox_geo.maxx + 5, 180) self.bottom.set_value(lat_south) self.top.set_value(lat_north) self.left.set_value(lon_west) self.right.set_value(lon_east)
class Theme(QWidget): """Theme widget class.""" def __init__(self, parent): super(Theme, self).__init__() self._preferences, vbox = parent, QVBoxLayout(self) vbox.addWidget(QLabel(self.tr("<b>Select Theme:</b>"))) self.list_skins = QListWidget() self.list_skins.setSelectionMode(QListWidget.SingleSelection) vbox.addWidget(self.list_skins) self.btn_delete = QPushButton(self.tr("Delete Theme")) self.btn_preview = QPushButton(self.tr("Preview Theme")) self.btn_create = QPushButton(self.tr("Create Theme")) hbox = QHBoxLayout() hbox.addWidget(self.btn_delete) hbox.addSpacerItem(QSpacerItem(10, 0, QSizePolicy.Expanding, QSizePolicy.Fixed)) hbox.addWidget(self.btn_preview) hbox.addWidget(self.btn_create) vbox.addLayout(hbox) self._refresh_list() self.btn_preview.clicked['bool'].connect(self.preview_theme) self.btn_delete.clicked['bool'].connect(self.delete_theme) self.btn_create.clicked['bool'].connect(self.create_theme) self._preferences.savePreferences.connect(self.save) def delete_theme(self): if self.list_skins.currentRow() != 0: file_name = ("%s.qss" % self.list_skins.currentItem().text()) qss_file = file_manager.create_path(resources.NINJA_THEME_DOWNLOAD, file_name) file_manager.delete_file(qss_file) self._refresh_list() def create_theme(self): designer = preferences_theme_editor.ThemeEditor(self) designer.exec_() self._refresh_list() def showEvent(self, event): self._refresh_list() super(Theme, self).showEvent(event) def _refresh_list(self): self.list_skins.clear() self.list_skins.addItem("Default") files = [file_manager.get_file_name(filename) for filename in file_manager.get_files_from_folder( resources.NINJA_THEME_DOWNLOAD, "qss")] files.sort() self.list_skins.addItems(files) if settings.NINJA_SKIN in files: index = files.index(settings.NINJA_SKIN) self.list_skins.setCurrentRow(index + 1) else: self.list_skins.setCurrentRow(0) def save(self): qsettings = IDE.ninja_settings() settings.NINJA_SKIN = self.list_skins.currentItem().text() qsettings.setValue("preferences/theme/skin", settings.NINJA_SKIN) self.preview_theme() def preview_theme(self): if self.list_skins.currentRow() == 0: qss_file = resources.NINJA_THEME else: file_name = ("%s.qss" % self.list_skins.currentItem().text()) qss_file = file_manager.create_path(resources.NINJA_THEME_DOWNLOAD, file_name) with open(qss_file) as f: qss = f.read() QApplication.instance().setStyleSheet(qss)
class EasyQListSuite(QWidget): """ Provide a window that has a QListWidget with 'Add' and 'Remove' button. """ def __init__(self, *__args): super(EasyQListSuite, self).__init__(*__args) self.__item_list = [] self.__list_main = QListWidget(self) self.__button_add = QPushButton('Add') self.__button_remove = QPushButton('Remove') self.__init_ui() self.__config_ui() def update_item(self, items: [(str, any)]): """ Specify a (key, value) tuple list. Key will be displayed as list item. Value can be retrieved by get_select_items() :param items: Specify a (key, value) tuple list. :return: None """ self.__item_list.clear() for item in items: if isinstance(item, (list, tuple)): if len(item) == 0: continue elif len(item) == 1: self.__item_list.append((str(item[0]), item[0])) else: self.__item_list.append((str(item[0]), item[1])) else: self.__item_list.append((str(item), item)) self.__update_list() def get_select_items(self) -> [any]: """ Get the value of the items that user selected. :return: The value of the items that user selected. """ return [item.data(Qt.UserRole) for item in self.__list_main.selectedItems()] def set_add_handler(self, handler): """ Add a handler for 'Add' button clicking :param handler: The handler that connects to the button clicked signal :return: """ self.__button_add.clicked.connect(handler) def set_remove_handler(self, handler): """ Add a handler for 'Remove' button clicking :param handler: The handler that connects to the button clicked signal :return: """ self.__button_remove.clicked.connect(handler) # ---------------------------------------- Private ---------------------------------------- def __init_ui(self): main_layout = QVBoxLayout() self.setLayout(main_layout) line_layout = QHBoxLayout() line_layout.addWidget(self.__button_add) line_layout.addWidget(self.__button_remove) main_layout.addWidget(self.__list_main) main_layout.addLayout(line_layout) def __config_ui(self): pass def __update_list(self): self.__list_main.clear() for text, obj in self.__item_list: item = QListWidgetItem() item.setText(text) item.setData(Qt.UserRole, obj) self.__list_main.addItem(item)
class SessionsManager(QDialog): """Session Manager, to load different configurations of ninja.""" def __init__(self, parent=None): super(SessionsManager, self).__init__(parent, Qt.Dialog) self._ide = parent self.setWindowTitle(translations.TR_SESSIONS_TITLE) self.setMinimumWidth(400) vbox = QVBoxLayout(self) vbox.addWidget(QLabel(translations.TR_SESSIONS_DIALOG_BODY)) self.sessionList = QListWidget() self.sessionList.addItems([key for key in settings.SESSIONS]) self.sessionList.setCurrentRow(0) self.contentList = QListWidget() self.btnDelete = QPushButton(translations.TR_SESSIONS_BTN_DELETE) self.btnDelete.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.btnUpdate = QPushButton(translations.TR_SESSIONS_BTN_UPDATE) self.btnUpdate.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.btnCreate = QPushButton(translations.TR_SESSIONS_BTN_CREATE) self.btnCreate.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.btnOpen = QPushButton(translations.TR_SESSIONS_BTN_ACTIVATE) self.btnOpen.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.btnOpen.setDefault(True) hbox = QHBoxLayout() hbox.addWidget(self.btnDelete) hbox.addWidget(self.btnUpdate) hbox.addWidget(self.btnCreate) hbox.addWidget(self.btnOpen) vbox.addWidget(self.sessionList) vbox.addWidget(self.contentList) vbox.addLayout(hbox) self.sessionList.itemSelectionChanged.connect(self.load_session_content) self.btnOpen.clicked['bool'].connect(self.open_session) self.btnUpdate.clicked['bool'].connect(self.save_session) self.btnCreate.clicked['bool'].connect(self.create_session) self.btnDelete.clicked['bool'].connect(self.delete_session) self.load_session_content() def load_session_content(self): """Load the selected session, replacing the current session.""" item = self.sessionList.currentItem() self.contentList.clear() if item is not None: key = item.text() files = [translations.TR_FILES] + \ [file[0] for file in settings.SESSIONS[key][0]] projects = [translations.TR_PROJECT] + settings.SESSIONS[key][1] content = files + projects self.contentList.addItems(content) def create_session(self): """Create a new Session.""" sessionInfo = QInputDialog.getText(None, translations.TR_SESSIONS_CREATE_TITLE, translations.TR_SESSIONS_CREATE_BODY) if sessionInfo[1]: sessionName = sessionInfo[0] if not sessionName or sessionName in settings.SESSIONS: QMessageBox.information(self, translations.TR_SESSIONS_MESSAGE_TITLE, translations.TR_SESSIONS_MESSAGE_BODY) return SessionsManager.save_session_data(sessionName, self._ide) self._ide.Session = sessionName self.close() @classmethod def save_session_data(cls, sessionName, ide): """Save the updates from a session.""" openedFiles = ide.filesystem.get_files() files_info = [] for path in openedFiles: editable = ide.get_or_create_editable(path) if editable.is_dirty: stat_value = 0 else: stat_value = os.stat(path).st_mtime files_info.append([path, editable.editor.getCursorPosition(), stat_value]) projects_obj = ide.filesystem.get_projects() projects = [projects_obj[proj].path for proj in projects_obj] settings.SESSIONS[sessionName] = [files_info, projects] qsettings = ide.data_settings() qsettings.setValue('ide/sessions', settings.SESSIONS) def save_session(self): """Save current session""" if self.sessionList.currentItem(): sessionName = self.sessionList.currentItem().text() SessionsManager.save_session_data(sessionName, self._ide) self._ide.show_message(translations.TR_SESSIONS_UPDATED_NOTIF % {'session': sessionName}, 2000) self.load_session_content() def open_session(self): """Open a saved session""" if self.sessionList.currentItem(): key = self.sessionList.currentItem().text() self._load_session_data(key) self._ide.Session = key self.close() def delete_session(self): """Delete a session""" if self.sessionList.currentItem(): key = self.sessionList.currentItem().text() settings.SESSIONS.pop(key) self.sessionList.takeItem(self.sessionList.currentRow()) self.contentList.clear() qsettings = self._ide.data_settings() qsettings.setValue('ide/sessions', settings.SESSIONS) def _load_session_data(self, key): """Activate the selected session, closing the current files/projects""" main_container = self._ide.get_service('main_container') projects_explorer = self._ide.get_service('projects_explorer') if projects_explorer and main_container: projects_explorer.close_opened_projects() for fileData in settings.SESSIONS[key][0]: path, line, stat_value = fileData if file_manager.file_exists(path): mtime = os.stat(path).st_mtime ignore_checkers = (mtime == stat_value) main_container.open_file(path, line, ignore_checkers=ignore_checkers) if projects_explorer: projects_explorer.load_session_projects( settings.SESSIONS[key][1])
class CustomMetDatasetDialog(QDialog): def __init__(self, vtable_dir: str, spec: Optional[dict] = None) -> None: super().__init__() self.vtable_dir = vtable_dir self.paths = set() # type: Set[Path] geom = QGuiApplication.primaryScreen().geometry() w, h = geom.width(), geom.height() self.setWindowTitle("Custom Meteorological Dataset") self.setMinimumSize(w * 0.25, h * 0.35) layout = QVBoxLayout() # button to open folder/files dialog hbox = QHBoxLayout() layout.addLayout(hbox) add_folder_btn = QPushButton('Add folder') add_files_btn = QPushButton('Add files') remove_selected_btn = QPushButton('Remove selected') hbox.addWidget(add_folder_btn) hbox.addWidget(add_files_btn) hbox.addWidget(remove_selected_btn) add_folder_btn.clicked.connect(self.on_add_folder_btn_clicked) add_files_btn.clicked.connect(self.on_add_files_btn_clicked) remove_selected_btn.clicked.connect( self.on_remove_selected_btn_clicked) # show added files in a list self.paths_list = QListWidget() self.paths_list.setSelectionMode(QAbstractItemView.ContiguousSelection) layout.addWidget(self.paths_list) grid = QGridLayout() layout.addLayout(grid) # date/time start/end self.start_date_input = QDateTimeEdit() self.start_date_input.setCalendarPopup(True) self.end_date_input = QDateTimeEdit() self.end_date_input.setCalendarPopup(True) add_grid_labeled_widget(grid, 0, 'Start Date/Time', self.start_date_input) add_grid_labeled_widget(grid, 1, 'End Date/Time', self.end_date_input) # interval in seconds interval_validator = QIntValidator() interval_validator.setBottom(1) self.interval_input = add_grid_lineedit(grid, 2, 'Interval in seconds', interval_validator, required=True) # vtable file input self.vtable_input, vtable_hbox = create_file_input( dialog_caption='Select VTable file', is_folder=False, start_folder=vtable_dir) add_grid_labeled_widget(grid, 3, 'VTable', vtable_hbox) btn_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) btn_box.accepted.connect(self.on_ok_clicked) btn_box.rejected.connect(self.reject) layout.addWidget(btn_box) self.setLayout(layout) if spec: self.paths = set(map(Path, spec['paths'])) self.base_folder = spec['base_folder'] self.update_file_list() start_date, end_date = spec['time_range'] for date_input, date in [(self.start_date_input, start_date), (self.end_date_input, end_date)]: date_input.setDateTime( QDateTime(QDate(date.year, date.month, date.day), QTime(date.hour, date.minute))) self.interval_input.set_value(spec['interval_seconds']) self.vtable_input.setText(spec['vtable']) @property def start_date(self) -> datetime: return self.start_date_input.dateTime().toPyDateTime() @property def end_date(self) -> datetime: return self.end_date_input.dateTime().toPyDateTime() @property def interval_seconds(self) -> int: return self.interval_input.value() @property def vtable_path(self) -> str: return self.vtable_input.text() def on_ok_clicked(self) -> None: if not self.paths: raise UserError('No GRIB files were added') if not self.interval_input.is_valid(): raise UserError('Interval must be an integer above 0') if self.start_date == self.end_date: raise UserError('Start date cannot be the same as end date') if self.start_date > self.end_date: raise UserError('Start date cannot be after the end date') if not self.vtable_path: raise UserError('No VTable file selected') if not os.path.exists(os.path.join(self.vtable_dir, self.vtable_path)): raise UserError('VTable file does not exist') self.accept() def on_add_folder_btn_clicked(self) -> None: folder = QFileDialog.getExistingDirectory(caption='Select folder') if not folder: return paths = [] # type: List[Path] for root, _, filenames in os.walk(folder): paths.extend(Path(root) / filename for filename in filenames) self.update_paths(self.paths.union(paths)) self.update_file_list() def on_add_files_btn_clicked(self) -> None: paths, _ = QFileDialog.getOpenFileNames(caption='Select files') if not paths: return self.update_paths(self.paths.union(map(Path, paths))) self.update_file_list() def on_remove_selected_btn_clicked(self) -> None: paths = [ item.data(Qt.UserRole) for item in self.paths_list.selectedItems() ] self.update_paths(self.paths.difference(paths)) self.update_file_list() def update_paths(self, paths: Set[Path]) -> None: if len(paths) == 1: # special case as os.path.commonpath() would return '.' base_folder = os.path.dirname(list(paths)[0]) elif paths: try: base_folder = os.path.commonpath(paths) except ValueError: raise UnsupportedError( 'Only datasets with files located on the same drive are supported' ) else: base_folder = None self.base_folder = base_folder self.paths = paths def update_file_list(self) -> None: self.paths_list.clear() for path in sorted(self.paths): item = QListWidgetItem(str(path)) item.setData(Qt.UserRole, path) self.paths_list.addItem(item)
class ResumeBox(QGroupBox): restartRequested = pyqtSignal(QWidget) def __init__(self, parent): super(ResumeBox, self).__init__(parent) self.engine = None self.game = None self.parent = parent self.matches = [] self.initUI() def initUI(self): self.widgetLayout = QVBoxLayout(self) self.savedlist = QListWidget(self) self.savedlist.setSelectionMode( QAbstractItemView.SingleSelection) self.savedlist.hide() self.widgetLayout.addWidget(self.savedlist) self.buttonLayout = QHBoxLayout() self.widgetLayout.addLayout(self.buttonLayout) self.resumebutton = QPushButton(self) self.resumebutton.clicked.connect(self.resumeGame) self.resumebutton.hide() self.buttonLayout.addWidget(self.resumebutton) self.cancelbutton = QPushButton(self) self.cancelbutton.clicked.connect(self.deleteGame) self.cancelbutton.hide() self.buttonLayout.addWidget(self.cancelbutton) self.emptyLabel = QLabel(self) self.widgetLayout.addWidget(self.emptyLabel) self.retranslateUI() def retranslateUI(self): self.setTitle(i18n( "ResumeBox", 'Saved Games')) self.resumebutton.setText( i18n("ResumeBox", 'Resume')) self.cancelbutton.setText( i18n("ResumeBox", 'Cancel')) self.emptyLabel.setText(i18n( "ResumeBox", 'No matches to be resumed')) def changeGame(self, game): self.game = game self.engine = ResumeEngine(game) self.savedlist.clear() self.matches = [] candidates = self.engine.getCandidates() if not candidates: self.savedlist.hide() self.resumebutton.hide() self.cancelbutton.hide() self.emptyLabel.show() else: self.emptyLabel.hide() for idMatch, candidate in candidates.items(): self.matches.append(idMatch) savedtime = datetime.datetime.strptime( candidate['started'], "%Y-%m-%d %H:%M:%S.%f") strtime = savedtime.strftime("%Y-%m-%d %H:%M:%S") hours, remainder = divmod(int(candidate['elapsed']), 3600) minutes, seconds = divmod(remainder, 60) strelapsed = "{0:02}:{1:02}:{2:02}".format( hours, minutes, seconds) msg = i18n("ResumeBox", 'Saved on {}. Time played: {}').format(strtime, strelapsed) item = QListWidgetItem(msg, self.savedlist) playerlist = "" for player in candidate['players']: playerlist += "\n " + player item.setToolTip(i18n( "ResumeBox", "Players: {}").format(playerlist)) self.savedlist.addItem(item) self.savedlist.show() self.resumebutton.show() self.cancelbutton.show() def resumeGame(self): selected = self.savedlist.selectedIndexes() if len(selected) > 0: idMatch = self.matches[selected[0].row()] gameengine = self.engine.resume(idMatch) matchTab = GameWidgetFactory.resumeGameWidget( self.game, gameengine, self.parent) if matchTab: matchTab.closeRequested.connect(self.parent.removeTab) matchTab.restartRequested.connect(self.restartGame) self.parent.newTab(matchTab, self.game) def restartGame(self, gamewidget): self.restartRequested.emit(gamewidget) def deleteGame(self): selected = self.savedlist.selectedIndexes() if len(selected) > 0: idMatch = self.matches[selected[0].row()] tit = i18n("ResumeBox", 'Cancel Saved Game') msg = i18n("ResumeBox", "Are you sure you want to cancel saved game?") reply = QMessageBox.question(self, tit, msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return False gameengine = self.engine.resume(idMatch) gameengine.cancelMatch() self.changeGame(self.game)
class Links(BottomTab): """This part will show the files which have a link with the current file""" def __init__(self, parent, path=None, window=None): BottomTab.__init__(self, parent) self.path = path self.window = window self.layout = QVBoxLayout(self) """Building of interface""" #Top self.top = QWidget(self) self.topLayout = QHBoxLayout(self.top) self.labelProjectName = QLabel("Projet : ", self.top) self.labelProjectName.setObjectName("label1_links") self.projectName = QLabel("Aucun", self.top) self.projectName.setObjectName("content1_links") self.labelName = QLabel("Nom : ", self.top) self.labelName.setObjectName("label2_links") self.name = QLabel("Inconnu", self.top) self.name.setObjectName("content2_links") self.labelType = QLabel("Type : ", self.top) self.labelType.setObjectName("label3_links") self.type = QLabel("Inconnu", self.top) self.type.setObjectName("content3_links") self.topLayout.addWidget(self.labelProjectName) self.topLayout.addWidget(self.projectName) self.topLayout.addWidget(self.labelName) self.topLayout.addWidget(self.name) self.topLayout.addWidget(self.labelType) self.topLayout.addWidget(self.type) spacer = QSpacerItem(250, 20) self.topLayout.addItem(spacer) self.layout.addWidget(self.top, 1) #Bottom self.bottom = QWidget(self) self.bottomLayout = QHBoxLayout(self.bottom) self.mainFiles = QGroupBox(self.tr("Fichiers principaux liés"), self.bottom) self.mainFiles.setObjectName("list1_links") self.mainFilesList = QListWidget(self.mainFiles) mfLayout = QVBoxLayout(self.mainFiles) mfLayout.addWidget(self.mainFilesList) self.styleFiles = QGroupBox(self.tr("Styles liés"), self.bottom) self.styleFiles.setObjectName("list2_links") self.styleFilesList = QListWidget(self.styleFiles) stfLayout = QVBoxLayout(self.styleFiles) stfLayout.addWidget(self.styleFilesList) self.scriptFiles = QGroupBox(self.tr("Scripts liés"), self.bottom) self.scriptFiles.setObjectName("list3_links") self.scriptFilesList = QListWidget(self.scriptFiles) scfLayout = QVBoxLayout(self.scriptFiles) scfLayout.addWidget(self.scriptFilesList) self.details = QGroupBox(self.tr("Détails"), self.bottom) self.chemin_det = QLabel(self.details) dLayout = QVBoxLayout(self.details) dLayout.addWidget(self.chemin_det) self.bottomLayout.addWidget(self.mainFiles) self.bottomLayout.addWidget(self.styleFiles) self.bottomLayout.addWidget(self.scriptFiles) self.bottomLayout.addWidget(self.details) self.layout.addWidget(self.bottom, 3) self.setStyleSheet(""" *{font-family:calibri;} QLabel{max-height:35px;font-size:15px;} QLabel#label1_links, QLabel#label2_links, QLabel#label3_links{max-width:70px;} QLabel#content1_links, QLabel#content2_links, QLabel#content3_links{font-weight:bold;} #list1_links,#list2_links,#list3_links{max-width:250px;} """) self.refresh(path) def refresh(self, path=None): if path is not None: self.path = path #Nettoyage de listes et des champs self.projectName.setText("Aucun") self.name.setText("Inconnu") self.type.setText("Inconnu") self.mainFilesList.clear() self.styleFilesList.clear() self.scriptFilesList.clear() self.chemin_det.setText("") if self.path is not None: if os.path.isfile(self.path): file = UserFile(self.path) self.name.setText(file.name()) isProjectFile, projectFile = False, None projects = self.window.opennedProjects project = None for p in projects: isProjectFile, projectFile = p.isProjectFile(self.path) if isProjectFile: project = p if isProjectFile: self.projectName.setText(project.name) self.type.setText(projectFile.type) for pf in projectFile.links[ProjectFile.MAIN_FILE]: item = QListWidgetItem(pf.name) item.projectFile = pf self.mainFilesList.addItem(item) for pf in projectFile.links[ProjectFile.STYLE_FILE]: item = QListWidgetItem(pf.name) item.projectFile = pf self.styleFilesList.addItem(item) for pf in projectFile.links[ProjectFile.SCRIPT_FILE]: item = QListWidgetItem(pf.name) item.projectFile = pf self.scriptFilesList.addItem(item) self.mainFilesList.itemClicked.connect( self.on_widgetList_itemClicked) self.styleFilesList.itemClicked.connect( self.on_widgetList_itemClicked) self.scriptFilesList.itemClicked.connect( self.on_widgetList_itemClicked) def on_widgetList_itemClicked(self, item): projectFile = item.projectFile self.chemin_det.setText(self.tr("Chemin : ") + projectFile.path)
class FindDialog(QDialog): alphabetical = [dict(type="alphabetical", allowPseudoUnicode=True)] def __init__(self, currentGlyph, parent=None): super().__init__(parent) self.setWindowModality(Qt.WindowModal) self.setWindowTitle(self.tr("Find…")) self.font = currentGlyph.font self._sortedGlyphNames = self.font.unicodeData.sortGlyphNames(self.font.keys(), self.alphabetical) layout = QGridLayout(self) self.glyphLabel = QLabel(self.tr("Glyph:"), self) self.glyphEdit = QLineEdit(self) self.glyphEdit.textChanged.connect(self.updateGlyphList) self.glyphEdit.event = self.lineEvent self.glyphEdit.keyPressEvent = self.lineKeyPressEvent self.beginsWithBox = QRadioButton(self.tr("Begins with"), self) self.containsBox = QRadioButton(self.tr("Contains"), self) self.beginsWithBox.setChecked(True) self.beginsWithBox.toggled.connect(self.updateGlyphList) self.glyphList = QListWidget(self) self.glyphList.itemDoubleClicked.connect(self.accept) buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject) l = 0 layout.addWidget(self.glyphLabel, l, 0, 1, 2) layout.addWidget(self.glyphEdit, l, 2, 1, 4) l += 1 layout.addWidget(self.beginsWithBox, l, 0, 1, 3) layout.addWidget(self.containsBox, l, 3, 1, 3) l += 1 layout.addWidget(self.glyphList, l, 0, 1, 6) l += 1 layout.addWidget(buttonBox, l, 0, 1, 6) self.setLayout(layout) self.updateGlyphList() def lineEvent(self, event): if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Tab: if self.beginsWithBox.isChecked(): self.containsBox.toggle() else: self.beginsWithBox.toggle() return True else: return QLineEdit.event(self.glyphEdit, event) def lineKeyPressEvent(self, event): key = event.key() if key == Qt.Key_Up or key == Qt.Key_Down: self.glyphList.keyPressEvent(event) else: QLineEdit.keyPressEvent(self.glyphEdit, event) def updateGlyphList(self): beginsWith = self.beginsWithBox.isChecked() self.glyphList.clear() if not self.glyphEdit.isModified(): self.glyphList.addItems(self._sortedGlyphNames) else: text = self.glyphEdit.text() if beginsWith: glyphs = [glyphName for glyphName in self._sortedGlyphNames if glyphName and glyphName.startswith(text)] else: glyphs = [glyphName for glyphName in self._sortedGlyphNames if glyphName and text in glyphName] self.glyphList.addItems(glyphs) self.glyphList.setCurrentRow(0) @classmethod def getNewGlyph(cls, parent, currentGlyph): dialog = cls(currentGlyph, parent) result = dialog.exec_() currentItem = dialog.glyphList.currentItem() newGlyph = None if currentItem is not None: newGlyphName = currentItem.text() if newGlyphName in dialog.font: newGlyph = dialog.font[newGlyphName] return (newGlyph, result)
class RecipeData(QWidget): def __init__(self): super().__init__() self.current_item = 0 self.shopping_list_item = 0 grid = QGridLayout() grid.setSpacing(15) # - - - Widgets - - - type_label = QLabel('Type:') type_label.setFixedWidth(250) type_combo_box = QComboBox(self) type_combo_box.setFixedWidth(250) combobox_items = ['All', 'Starter', 'Snacks', 'Breakfast', 'Lunch/Dinner'] type_combo_box.addItems(combobox_items) search_label = QLabel('Search:') search_label.setFixedWidth(250) search_input = QLineEdit() search_input.setFixedWidth(250) self.list_box = QListWidget() self.list_box.setFixedWidth(250) # New recipe button self.new_recipe_button = QPushButton() self.new_recipe_button.setIcon(QIcon('add.png')) self.new_recipe_button.setIconSize(QSize(28, 28)) self.new_recipe_button.setMaximumSize(32, 32) self.new_recipe_button.setStyleSheet("background-color: white") self.new_recipe_button.setStatusTip('Add New Recipe.') self.new_recipe_button.clicked.connect(lambda: add_new_recipe()) # Add to shopping list button self.add_to_shopping_button = QPushButton() self.add_to_shopping_button.setIcon(QIcon('shopping.png')) self.add_to_shopping_button.setIconSize(QSize(32, 32)) self.add_to_shopping_button.setMaximumSize(32, 32) self.add_to_shopping_button.setStyleSheet("background-color: white") self.add_to_shopping_button.setStatusTip('Add Recipe To Shopping List.') self.add_to_shopping_button.clicked.connect(lambda: self.add_to_shopping_list()) # Refresh data button self.refresh_button = QPushButton() self.refresh_button.setIcon(QIcon('refresh.png')) self.refresh_button.setIconSize(QSize(26, 26)) self.refresh_button.setMaximumSize(32, 32) self.refresh_button.setStyleSheet("background-color: white") self.refresh_button.setStatusTip('Refresh List.') # Delete recipe button self.delete_button = QPushButton() self.delete_button.setIcon(QIcon('delete.png')) self.delete_button.setIconSize(QSize(28, 28)) self.delete_button.setMaximumSize(32, 32) self.delete_button.setStyleSheet("background-color: white") self.delete_button.setStatusTip('Delete Recipe.') self.delete_button.clicked.connect(lambda: self.delete_recipe()) self.text_area = QTabWidget() self.text_area.tab1 = QTextEdit() self.text_area.tab2 = EditRecipe() self.text_area.addTab(self.text_area.tab1, 'Display') self.text_area.addTab(self.text_area.tab2, 'Edit') # Layout of widgets on grid grid.addWidget(type_label, 0, 0,) grid.addWidget(type_combo_box, 1, 0) grid.addWidget(search_label, 2, 0) grid.addWidget(search_input, 3, 0) grid.addWidget(self.list_box, 4, 0) grid.addWidget(self.new_recipe_button, 0, 1) grid.addWidget(self.add_to_shopping_button, 1, 1) grid.addWidget(self.refresh_button, 2, 1) grid.addWidget(self.delete_button, 3, 1) grid.addWidget(self.text_area, 0, 2, 5, 1) self.setLayout(grid) self.populate_recipe_list() def populate_recipe_list(self): self.list_box.clear() recipe_names = SQL_reader.recipe_names() for name in recipe_names: QListWidgetItem(str(name), self.list_box) self.list_box.itemClicked.connect(self.show_recipe) def show_recipe(self, item): title, ingredients, instructions = SQL_reader.recipe_data(item.text()) recipe_text = html_print.display_output(title, ingredients, instructions) self.text_area.tab1.setHtml(recipe_text) self.shopping_list_item = item self.current_item = item.text() return def add_to_shopping_list(self): ShoppingList.add_recipe(main_window.window_content.tab2, self.current_item) def delete_recipe(self): SQL_reader.delete_function(self.current_item) self.populate_recipe_list()
class ImePanel(QWidget): def __init__(self, inputMethodManager): super().__init__() self.imm = inputMethodManager self.qLineImmDict = {} self.initUI() def getIMM(self): return self.imm def initUI(self): self.resize(800, 600) vbox = QVBoxLayout() hbox = QHBoxLayout() subvbox = QVBoxLayout() subhbox = QHBoxLayout() label = QLabel('当前状态:', self) subhbox.addWidget(label) self.stateNameEditBox = QLineEdit(self) self.stateNameEditBox.setReadOnly(True) subhbox.addWidget(self.stateNameEditBox) subhbox.setStretchFactor(self.stateNameEditBox, 2) self.qLineImmDict[self.stateNameEditBox] = 'currStateName' subvbox.addLayout(subhbox) subhbox = QHBoxLayout() label = QLabel('光标位置:', self) subhbox.addWidget(label) self.cursorPosEditBox = QLineEdit(self) self.cursorPosEditBox.setReadOnly(True) self.cursorPosEditBox.resize(100, 30) subhbox.addWidget(self.cursorPosEditBox) subvbox.addLayout(subhbox) self.qLineImmDict[self.cursorPosEditBox] = 'cursorPos' subhbox = QHBoxLayout() label = QLabel('上屏串:', self) subhbox.addWidget(label) self.completedEditBox = QLineEdit(self) self.completedEditBox.setReadOnly(True) subhbox.addWidget(self.completedEditBox) subvbox.addLayout(subhbox) # 行--------------------- self.qLineImmDict[self.completedEditBox] = 'Completed' subhbox = QHBoxLayout() label = QLabel('输入串:', self) subhbox.addWidget(label) self.compositionEditBox = QLineEdit(self) self.compositionEditBox.setReadOnly(True) subhbox.addWidget(self.compositionEditBox) self.qLineImmDict[self.compositionEditBox] = 'Composition' subvbox.addLayout(subhbox) subhbox = QHBoxLayout() label = QLabel('输入串显示为:', self) subhbox.addWidget(label) self.compDisplayEditBox = QLineEdit(self) self.compDisplayEditBox.setReadOnly(True) subhbox.addWidget(self.compDisplayEditBox) subvbox.addLayout(subhbox) # 行--------------------- self.qLineImmDict[self.compDisplayEditBox] = 'CompDisplay' hbox.addLayout(subvbox) subvbox = QVBoxLayout() label = QLabel('候选串', self) subvbox.addWidget(label) self.candList = QListWidget(self) subvbox.addWidget(self.candList) hbox.addLayout(subvbox) vbox.addLayout(hbox) hbox = QHBoxLayout() label = QLabel('在此输入:', self) hbox.addWidget(label) self.editorBox = QLineEdit4Ime(self.getIMM(), self) hbox.addWidget(self.editorBox) vbox.addLayout(hbox) # 行--------------------- vbox.addStretch(1) self.setLayout(vbox) self.show() def ImeKeyPressEvent(self): for k, v in self.qLineImmDict.items(): if type(self.getIMM().GetCoreData(v)) == 'str': k.setText(self.getIMM().GetCoreData(v)) else: k.setText(str(self.getIMM().GetCoreData(v))) self.candList.clear() for i in self.getIMM().GetCoreData('Candidates'): self.candList.addItem(i)
class TimelineWindow(QWidget): def __init__(self): super().__init__() timeline_bk_path = './source/pic/timeline_bk.png' hgzy_font_path = './source/font/HGZYT_CNKI.TTF' rem_ico_path = './source/pic/rem.png' fontId = QFontDatabase.addApplicationFont(hgzy_font_path) fontName = QFontDatabase.applicationFontFamilies(fontId)[0] self.index = -1 self.pix = QPixmap(timeline_bk_path) self.resize(self.pix.width(),self.pix.height()) self.pix = self.pix.scaled(int(self.pix.width()),int(self.pix.height())) self.setMask(self.pix.mask()) screen = QDesktopWidget().screenGeometry() self.move((screen.width() - self.pix.width()) / 2, (screen.height() - self.pix.height()) / 2) self.setAttribute(Qt.WA_TranslucentBackground) self.setWindowFlags(Qt.FramelessWindowHint) rem_icon = QIcon(QPixmap(rem_ico_path)) self.setWindowIcon(rem_icon) self.m_DragPosition = None self.m_drag = False self.animelist = QListWidget(self) self.animelist.setObjectName('AnimeList') self.animelist.setStyleSheet('#AnimeList{background:transparent}') self.animelist.setGeometry(200,165,310,350) self.animelist.setFont(QFont(fontName,11,QFont.Light)) self.detail = Detail(self.x()+50,self.y()-15) self.detail_show = False self.animelist.itemDoubleClicked.connect(self.DetailBt) self.TimeLabels_path = [] self.TimeLabels_clicked_path = [] self.weekanime = TimeLine().get_week_anime() for time in range(1,8): self.TimeLabels_path.append('./source/pic/week_day_%d.png' % time) self.TimeLabels_clicked_path.append('./source/pic/week_day_%d_clicked.png' % time) self.TimeLabels = [] for time in range(7): self.TimeLabels.append(QDlabel(self)) self.setTimeLabel() self.daylabel = QLabel(self) self.daylabel.setObjectName('DayLabel') self.daylabel.setGeometry(290,110,200,40) self.daylabel.setFont(QFont(fontName,13,QFont.Bold)) self.setDaytext() self.timelineshow = False def paintEvent(self, event): paint = QPainter(self) paint.drawPixmap(0,0,self.pix.width(),self.pix.height(),self.pix) def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.m_drag = True self.m_DragPosition = event.globalPos() - self.pos() if self.detail_show == True: self.detail.raise_() event.accept() elif event.button() == Qt.RightButton: if self.detail_show == True: self.detail.close() self.detail_show = False self.hide() self.timelineshow = False event.accept() def mouseMoveEvent(self, event): if Qt.LeftButton and self.m_drag: self.move(event.globalPos() - self.m_DragPosition) self.detail.move(self.x()+50 - self.detail.pix.width(),self.y()-15) event.accept() def mouseReleaseEvent(self, event): self.m_drag = False def closeEvent(self, event): self.detail.close() self.detail_show = False self.timelineshow = False def setTimeLabel(self): label_between = 60 week_animes = self.weekanime start = week_animes[0]['day_of_week']-1 for time in range(start,start+7): time_mod = time % 7 self.TimeLabels[time_mod].setObjectName('DayLabel%d' % (time_mod+1)) self.TimeLabels[time_mod].setStyleSheet('#DayLabel%d{border-image:url(%s)}' % (time_mod+1,self.TimeLabels_path[time_mod])) self.TimeLabels[time_mod].setGeometry(100,120 + label_between * (time-start),57,24) self.labelclick = week_animes[0]['day_of_week'] self.TimeLabels[self.labelclick-1].setStyleSheet('#DayLabel%d{border-image:url(%s)}' % (self.labelclick,self.TimeLabels_clicked_path[self.labelclick-1])) def setLabelClick(self, time_n): self.TimeLabels[self.labelclick-1].setStyleSheet( '#DayLabel%d{border-image:url(%s)}' % (self.labelclick, self.TimeLabels_path[self.labelclick-1])) self.TimeLabels[time_n].setStyleSheet('#DayLabel%d{border-image:url(%s)}' % (time_n+1,self.TimeLabels_clicked_path[time_n])) def setDaytext(self): for animes in self.weekanime: if animes['day_of_week'] == self.labelclick: date = animes['date'] day_of_week = self.labelclick self.animelist.clear() for anime in animes['seasons']: item_text = '' if anime['delay'] == 1: item_text += anime['pub_time'] + ' ' + anime['delay_index'] + ' ' + anime['delay_reason'] + '\n' + anime['title'] else: item_text += anime['pub_time'] + ' ' + anime['pub_index'] + '\n' + anime['title'] self.animelist.addItem(item_text) break week_day = ['周一','周二','周三','周四','周五','周六','周日'] daytext = date + ' ' + week_day[day_of_week - 1] self.daylabel.setText(daytext) def GetDetail(self,title): dbsql = AnimeData() infos = dbsql.SqliteInfoSearch({'title':title}) resinfo = [] if infos: for info in infos: resinfo.append(info[0]) resinfo.append(info[1]) resinfo.append(info[2]) resinfo.append(info[3]) resinfo.append(info[4]) resinfo.append(info[5]) resinfo.append(info[6]) resinfo.append(info[7]) return resinfo def DelDetail(self): self.detail.animetitle.setParent(None) self.detail.animeintro.setParent(None) self.detail.animetags.setParent(None) self.detail.animeorder.setParent(None) self.detail.animeindexshow.setParent(None) self.detail.animeindexshowtext.setParent(None) self.detail.animetagstext.setParent(None) self.detail.animeordertext.setParent(None) self.detail.animetitletext.setParent(None) self.detail.animetagstext.setParent(None) self.detail.pic_label.setParent(None) def DetailBt(self): if self.detail_show == False: title = self.animelist.currentItem().text().split('\n')[1] info = self.GetDetail(title) self.detail.setInfo(info) self.index = self.animelist.currentIndex() self.detail.show() self.detail_show = True elif self.detail_show == True and self.index != self.animelist.currentIndex(): self.detail.close() self.DelDetail() title = self.animelist.currentItem().text().split('\n')[1] info = self.GetDetail(title) self.index = self.animelist.currentIndex() self.detail.setInfo(info) self.detail.show() else: self.detail.close() self.DelDetail() self.index = -1 self.detail_show = False
class Lookup(QWidget): MODEL_CLASS = None def __init__(self, parent, model): QWidget.__init__(self, parent, Qt.Window) self.model = model self.model.view = self self._setupUi() self.searchEdit.searchChanged.connect(self.searchChanged) self.searchEdit.returnPressed.connect(self.returnPressed) self.namesList.currentRowChanged.connect(self.currentRowChanged) self.namesList.itemDoubleClicked.connect(self.itemDoubleClicked) self._shortcutUp.activated.connect(self.upPressed) self._shortcutDown.activated.connect(self.downPressed) def _setupUi(self): self.setWindowTitle(tr("Lookup")) self.resize(314, 331) self.verticalLayout = QVBoxLayout(self) self.searchEdit = SearchEdit(self) self.verticalLayout.addWidget(self.searchEdit) self.namesList = QListWidget(self) self.namesList.setEditTriggers(QAbstractItemView.NoEditTriggers) self.namesList.setSelectionBehavior(QAbstractItemView.SelectRows) self.namesList.setUniformItemSizes(True) self.namesList.setSelectionRectVisible(True) self.verticalLayout.addWidget(self.namesList) self.searchEdit.immediate = True self._shortcutUp = QShortcut(self.searchEdit) self._shortcutUp.setKey(QKeySequence(Qt.Key_Up)) self._shortcutUp.setContext(Qt.WidgetShortcut) self._shortcutDown = QShortcut(self.searchEdit) self._shortcutDown.setKey(QKeySequence(Qt.Key_Down)) self._shortcutDown.setContext(Qt.WidgetShortcut) def _restoreSelection(self): self.namesList.setCurrentRow(self.model.selected_index) #--- Event Handlers def returnPressed(self): self.model.go() def searchChanged(self): self.model.search_query = str(self.searchEdit.text()) def currentRowChanged(self, row): if row >= 0: self.model.selected_index = row def itemDoubleClicked(self, item): self.model.go() def upPressed(self): if self.namesList.currentRow() > 0: self.namesList.setCurrentRow(self.namesList.currentRow()-1) def downPressed(self): if self.namesList.currentRow() < self.namesList.count()-1: self.namesList.setCurrentRow(self.namesList.currentRow()+1) #--- model --> view def refresh(self): self.namesList.clear() self.namesList.addItems(self.model.names) self._restoreSelection() self.searchEdit.setText(self.model.search_query) def show(self): QWidget.show(self) self.searchEdit.setFocus() # see csv_options self.raise_() def hide(self): QWidget.hide(self)
class MainWindow(QMainWindow): # -------------------------------------------------------------------------- __init__() def __init__(self, parent=None): """ Main Window Constructor This is a special case constructor as we need an object of type QMainWindow to supprt a menu bar at the top of the window and a status bar at the bottom of the window. However this QMAinWindow widget has issues with adding additoonal widgets to it. We need to create a main_widget within this QMainWindow object that can easily have its own layout and have its own widgets assigend to it. This main_widget will inherit from the generic QWidget. """ super(MainWindow, self).__init__(parent) # Create and assign a main_widget and main_layout for the main window self.main_widget = QWidget(self) self.main_layout = QGridLayout(self.main_widget) self.setCentralWidget(self.main_widget) # Define the test targets available. Test targets are folders in the # test cases folder that hold individula test cases. self.update_list_of_test_targets() self.loaded_test_suite = "" # self.loaded_test_target = "" self.loaded_target = "" self.test_case_full_pathname_list = [] self.test_case_results = [] self.pass_color = QColor(100, 255, 100) # light green self.fail_color = QColor(255, 100, 100) # light red self.running_color = QColor(255, 255, 100) # light yellow self.ready_icon = ClickableQIcon( os.path.join(RESOURCE_PATH, "ready.png" ) ) self.running_icon = ClickableQIcon( os.path.join(RESOURCE_PATH, "running.jpg" ) ) self.passed_icon = ClickableQIcon( os.path.join(RESOURCE_PATH, "passed.png" ) ) self.failed_icon = ClickableQIcon( os.path.join(RESOURCE_PATH, "failed.jpg" ) ) self.not_ready_icon = ClickableQIcon( os.path.join(RESOURCE_PATH, "no.png" ) ) self.running_icon = ClickableQIcon( os.path.join(RESOURCE_PATH, "running.jpg" ) ) self.open_icon = ClickableQIcon( os.path.join(RESOURCE_PATH, "open.png" ) ) self.exit_icon = ClickableQIcon( os.path.join(RESOURCE_PATH, "exit.png" ) ) self.about_icon = ClickableQIcon( os.path.join(RESOURCE_PATH, "about.png" ) ) self.help_icon = ClickableQIcon( os.path.join(RESOURCE_PATH, "help.png" ) ) self.target_icon = ClickableQIcon( os.path.join(RESOURCE_PATH, "target.png" ) ) # Each test suite result will be stored in a data time stamped folder # so we are going to need a string to hold that value. Each time the # run_test_suite() method is called we will get an updated value for # this date_time_string self.date_time_string = time.strftime("%Y%m%d%H%M%S", time.localtime()) # --- Define the frames for the main window / central widget in the main window. # The frames are the large division of the windows in which widgets are placed. # Here is the intended frame layout for the MainWindow: # +-----------------------------------------+ # | Status and Summary Frame | # |-----------------------------------------| # | Test | | # | Suite Frame | Test | # |---------------------+ Case | # | Console | Frame | # | Frame | | # | | | # +-----------------------------------------+ self.status_frame = QFrame() # status and summary frame self.suite_frame = QFrame() # test suite frame self.case_frame = QFrame() # test case frame self.console_frame = QFrame() # console frame self.status_frame.setFrameStyle( QFrame.Panel | QFrame.Raised ) # \ self.suite_frame.setFrameStyle( QFrame.Panel | QFrame.Raised ) # \__ set initial frame styles self.case_frame.setFrameStyle( QFrame.Panel | QFrame.Raised ) # / self.console_frame.setFrameStyle( QFrame.Panel | QFrame.Raised ) # / # --- Add the frames to the grid layout of the main window # to the main window # ( Frame, Row, Col, RSpan, CSpan, Allignment ) self.main_layout.addWidget(self.status_frame, 0, 0, 5, 12) #, Qt.AlignLeft | Qt.AlignTop) self.main_layout.addWidget(self.suite_frame, 13, 0, 8, 6) #, Qt.AlignHCenter | Qt.AlignTop) self.main_layout.addWidget(self.case_frame, 6, 6, 15, 6) self.main_layout.addWidget(self.console_frame, 6, 0, 7, 6) # Set the main_layout as the main_wigit self.main_widget.setLayout(self.main_layout) # --- Define and set the status bar that appears at the bottom of the wondow # TODO: make this font a little smaller self.status_bar = self.statusBar() # Status Bar appears on the bottom self.status_bar.showMessage('No Test Suite Loaded') # of the main window # --- Menu Bar for the top of the main window print("call create_menu_bar()") self.create_menu_bar() # --- Main Window Geometry self.setGeometry(100, 100, 1200, 800) # --- Create the About Dialog self.about_dialog = QDialog() self.about_dialog.setWindowTitle("About Test Master II") about_layout = QGridLayout() title = QLabel("Test Mster II") author = QLabel("Madvax") email = QLabel("*****@*****.**") about_layout.addWidget(QLabel("---------------") , 1, 1 , Qt.AlignCenter) about_layout.addWidget(title , 2, 1 , Qt.AlignCenter) about_layout.addWidget(author , 3, 1 , Qt.AlignCenter) about_layout.addWidget(email , 4, 1 , Qt.AlignCenter) about_layout.addWidget(QLabel("---------------") , 5, 1 , Qt.AlignCenter) self.about_dialog.setLayout(about_layout) # --- Create the Help Dialog # The help text in this dialog is taken from the HELP file # in the root folder for this repository self.help_dialog = QDialog() self.help_dialog.setWindowTitle("Help With Test Master II") help_layout = QGridLayout() help_text = QTextEdit() try: f = open(os.path.join(MY_PATH, "../HELP") , 'r') text = f.read() f.close() help_text.setText(text) except: help_text.setText("Sorry, Unlable to locate help file") help_text.setReadOnly(True) font = help_text.font() font.setFamily("Currier") font.setPointSize(10) help_layout.addWidget(help_text, 0,0) self.help_dialog.setLayout(help_layout) self.help_dialog.setGeometry(150,150, 500,500) # ----------------------------------------------------------------------- Status Frame Widgets # --- Create and populate the product pull down with products # taken from the test cases folder # --- Logo Image that loads the About Window self.logo = QPixmap( os.path.join(RESOURCE_PATH, "splash.jpg") ) self.logo.scaled(10, 10, Qt.KeepAspectRatio) self.logo_image = ClickableQLabel() self.logo_image.setScaledContents(True) self.logo_image.setPixmap(self.logo) self.logo_image.setMaximumWidth(80) self.logo_image.setMaximumHeight(100) # --- Suite and Target labels self.test_suite_label = QLabel("Test Suite: None") self.test_target_label = QLabel("Test Target: None") # --- Generic spacer to help with alignemtns self.spacer = QLabel(" ") # --- Status Frame Layout and widget placement status_frame_layout = QGridLayout() status_frame_layout.addWidget(self.logo_image , 0, 0, 3, 1, Qt.AlignLeft | Qt.AlignTop ) status_frame_layout.addWidget(self.test_suite_label , 1, 1, 1, 1, Qt.AlignLeft | Qt.AlignVCenter ) status_frame_layout.addWidget(self.test_target_label , 0, 1, 1, 1, Qt.AlignLeft | Qt.AlignVCenter ) status_frame_layout.addWidget(self.spacer , 0, 4, 1, 1, Qt.AlignLeft | Qt.AlignTop ) status_frame_layout.addWidget(self.spacer , 0, 5, 1, 3, Qt.AlignLeft | Qt.AlignTop ) self.status_frame.setLayout(status_frame_layout) # ----------------------------------------------------------------------- SUITE FRAME WIDGETS palette = QPalette() palette.setColor( QPalette.Text, QColor( 0, 75, 0) ) # Very Dark green text on a palette.setColor( QPalette.Base, QColor(200, 255, 200) ) # very light green background text_area_font = QFont("Courier", 15, QFont.Bold) self.suite_text_area = QTextEdit() self.suite_text_area.setPalette(palette) self.suite_text_area.setFont(text_area_font) suite_layout = QVBoxLayout() suite_layout.addWidget(self.suite_text_area) self.suite_frame.setLayout(suite_layout) self.suite_text_area.setText("No Test Suite Loaded") # ----------------------------------------------------------------------- CONSOLE FRAME WIDGETS palette = QPalette() palette.setColor(QPalette.Text, Qt.white) # White text on a palette.setColor(QPalette.Base, Qt.black) # black background text_area_font = QFont("Courier", 15, QFont.Bold) self.console_text_area = QTextEdit() self.console_text_area.setPalette(palette) self.console_text_area.setFont(text_area_font) console_layout = QVBoxLayout() console_layout.addWidget(self.console_text_area) self.console_frame.setLayout(console_layout) self.console_text_area.setText("Console Area") # ----------------------------------------------------------------------- TEST CASE FRAME WIDGETS self.testcase_list_widget = QListWidget() self.testcase_list_widget.setLineWidth(3) testcase_layout = QVBoxLayout() testcase_layout.addWidget(self.testcase_list_widget) self.case_frame.setLayout(testcase_layout) # -------------------------------------------------------------------------- create_menu_bar() def create_menu_bar(self): """ """ # --- Create the menu bar object print("Crate Menu Bar") menu_bar = self.menuBar() # --- Define some actions for the menu bar open_action = QAction(QIcon(os.path.join(MY_PATH, '../res/open.png')), '&Open Test Suite', self) open_action.setShortcut('Ctrl+O') open_action.setStatusTip('Open a Test Suite') open_action.triggered.connect( self.open_test_suite) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - exit_action = QAction(QIcon(os.path.join(MY_PATH, '../res/exit.png')), '&Exit', self) exit_action.setShortcut('Ctrl+Q') exit_action.setStatusTip('Exit application') exit_action.triggered.connect( qApp.quit) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - select_target_action = QAction(QIcon(os.path.join(MY_PATH, '../res/target.png')), '&Target', self) select_target_action.setShortcut('Ctrl+T') select_target_action.setStatusTip('Select test taget') select_target_action.triggered.connect( self.select_target) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - run_tests_action = QAction(QIcon(os.path.join(MY_PATH, '../res/run.png')), '&Run Test', self) run_tests_action.setShortcut('Ctrl+R') run_tests_action.setStatusTip('Run tests agains the target') run_tests_action.triggered.connect( self.run_test_suite) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - stop_tests_action = QAction(QIcon(os.path.join(MY_PATH, '../res/stop.png')), '&Stop Test', self) stop_tests_action.setShortcut('Ctrl+S') stop_tests_action.setStatusTip('Stops running tests') stop_tests_action.triggered.connect( self.open_test_suite) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - help_action = QAction(QIcon(os.path.join(MY_PATH, '../res/help.png')), '&Help', self) help_action.setShortcut('Ctrl+H') help_action.setStatusTip('Help') help_action.triggered.connect( self.open_help) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - about_action = QAction(QIcon(os.path.join(MY_PATH, '../res/about.png')), '&About', self) about_action.setShortcut('Ctrl+A') about_action.setStatusTip('About Test MAster II') about_action.triggered.connect( self.open_about) # Add actions to the menu bar fileMenu = menu_bar.addMenu('&File') testMenu = menu_bar.addMenu('&Test') helpMenu = menu_bar.addMenu('&Help') # - - - - - - - - - - - - - - - - - - - fileMenu.addAction(open_action) fileMenu.addAction(exit_action) # - - - - - - - - - - - - - - - - - - - testMenu.addAction(select_target_action) testMenu.addAction(run_tests_action) testMenu.addAction(stop_tests_action) # - - - - - - - - - - - - - - - - - - - helpMenu.addAction(help_action) helpMenu.addAction(about_action) # -------------------------------------------------------------------------- open_test_suite() def open_test_suite(self): """ Open a test suite file and loads the test cases from the suite into the tool. There is a chained process flow when you open a test suite: open_test_suite() calls select_target() select_target then calls load_test_cases() Once a test suite is opened, the user may later choose a new target for the same test suite as teh select_target() method call load_test_cases(). """ self.test_case_data_list = [] url = QUrl() # This File Dialog should start in url.setScheme("file") # the test suites folder by default. url.setPath( "%s/../testsuites" %MY_PATH ) # TODO: os.path.join() options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog file_dialog = QFileDialog() file_dialog.setDirectoryUrl(url) self.testsuite_file, _ = file_dialog.getOpenFileName(self,"QFileDialog.getOpenFileName()", "","All Files (*)", options=options) if self.testsuite_file: self.test_suite_label.setText("Test Suite: %s" %self.testsuite_file.split('/')[LAST]) message = "Loaded Test Suite: %s" %self.testsuite_file logger.info(message) # Crate a list of test cases from the test suite file. However, these # test cases are only file names with not path. We'll have to add the path # based on the target selected. try: f = open(self.testsuite_file, 'r') lines = f.readlines() f.close() self.suite_text_area.clear() for line in lines: line = line.strip() self.suite_text_area.append(line) except: message = "Unalbe to read test cases from test suite %s" %self.testsuite_file logger.error(message) self.suite_text_area.setText(message) lines = [] self.test_case_file_list = [] # a list of test case file names with no paths for line in lines: line = line.strip() if len(line) < 1: pass elif line.startswith('#'): pass else: self.test_case_file_list.append(line) self.test_case_count = len(self.test_case_file_list) message = "Found %d test cases in %s" %(self.test_case_count, self.testsuite_file.split('/')[LAST]) logger.info(message) self.status_bar.showMessage(message) # open the select a test target for this suite self.select_target() # load the test cases # logger.info("Back from select_target() ... calling load_test_cases()") # self.load_test_cases() # -------------------------------------------------------------------------- load_test_cases() def load_test_cases(self): """ When we load the test cases from the test suite file we populate the test case frame a.k.a. cases frame with the test cases. However, before we put up the green run icon we have to ensure that a target as been selected and using that target, verify that the test cases requested in the test suite are available in the target folder. """ self.test_cases = [] # Start with an empty list of test cases self.testcase_list_widget.clear() # Clear any test cases from the test case frame self.testcase_list_widget_items_list = [] if len(self.test_case_file_list) > 0: counter = 0 for t in self.test_case_file_list: counter += 1 logger.info("Loading test case %d of %d %s" %(counter, len(self.test_case_file_list), t) ) # In this loop the variable t is the file name of a candidate test case # without the path of the file. We will need to use the target to # generate a ful path file name for the test case in this loop. # # Create a list of test case data where each item in the list is a # dictionary with two key-valie pairs: name an state. The name is # the file name of the script as read from the test suite file and # the state is one of: # "not ready" - File not found or target not specified # "ready" - File exists and target is specified # "running" - Test case is being execuited # "passed" - Test case has finished without error or failed step # "failed" - Test case failed one or more steps # "error" - Test case finished with and error, not the same as a failure # Definethe full path of the candidate test case test_case_path_filename = "" test_case_path_filename = os.path.join( os.path.join(TESTCASE_PATH, self.loaded_target), t ) message = "Test case full path %s" %(test_case_path_filename) logger.info(message) test_case_record = {} # used to hold the data for a test case # if the full path test case file exists then we mark it a ready # otherwise we mark it a not ready if os.path.isfile( test_case_path_filename ): test_case_record = {"name": t, "state":ready, "file": test_case_path_filename} # # \ *** This is the list of *** self.test_case_full_pathname_list.append(test_case_path_filename) # > *** executable test cases *** # # / *** used for "run test suite" *** else: test_case_record = {"name": t, "state":not_ready, "file": None} # define the icon for the test case based on the state of the test case if test_case_record["state"] == ready: test_case_icon = ClickableQIcon( os.path.join(RESOURCE_PATH, "run.png") ) else: test_case_icon = ClickableQIcon( os.path.join(RESOURCE_PATH, "no.png") ) test_case_record["icon"] = test_case_icon # At this point the test case reacod is a dictionary with the key-value # paris listed below: # {"same": string, "state", string, "file": full_path_filename, "icon": ClickableIcon} # uisng this date we can create a QListItem and add it to the testcase_list_widget. message = "Adding test case %s to the test case list widget" %test_case_record["name"] logger.info(message) list_item = QListWidgetItem() list_item.setText("Name: %s\nFile:%s\nState:%s" %(test_case_record["name"], test_case_record["file"], test_case_record["state"])) list_item.setIcon(test_case_record["icon"]) self.testcase_list_widget.addItem(list_item) self.testcase_list_widget_items_list.append(list_item) else: message = "Failed to load any test cases from %s" %self.testsuite_file.split('/')[LAST] logger.warning(message) self.status_bar.showMessage(message) # -------------------------------------------------------------------------- update_list_of_test_targets() def update_list_of_test_targets(self): """ update the list of test targets from the contents of the testcases folder """ target_candidates = os.listdir(TESTCASE_PATH) self.target_list = [{"name":"Not selected", "folder":"Not selected" }] for item in target_candidates: if os.path.isdir( os.path.join(TESTCASE_PATH, item) ): target = {} target["name"] = item target["folder"] = os.path.join(TESTCASE_PATH, item) self.target_list.append(target) logger.info("Added target %s to the list of targets" %item) # -------------------------------------------------------------------------- select_target() def select_target(self): """ Select a target from teh list of available test targets """ self.update_list_of_test_targets() targets = [] for target in self.target_list[1:]: targets.append(target["name"]) item, okPressed = QInputDialog.getItem(self, "Select Test Target","Target:", targets, 0, False) if okPressed and item: self.test_target_label.setText("Test Target: %s" %item) self.loaded_target = item logger.info("Loaded Test Target: %s" %item) # load the test cases logger.info("Back from select_target() ... calling load_test_cases()") self.load_test_cases() # -------------------------------------------------------------------------- run_test_suite() def run_test_suite(self): """ Execute all of the tests in a test suite. The list of executables is stored in self.test_case_full_pathname_list. """ if len(self.test_case_full_pathname_list) > 0: self.suite_results_folder = os.path.join(RESULTS_HOME, time.strftime("%Y%m%d%H%M%S", time.localtime()) ) os.mkdir(self.suite_results_folder) message = "Created suite results folder %s" %self.suite_results_folder logger.info(message) # intiialize a list of dictionaries to store the results of this test suite run self.test_suite_results = [] # This is the main loop for executing test cases. # In this loop we create folders for the results # of each test case and call/run each test cases # and provide the test cases results folder name # as the last argument to the test case invocation # command. We also keep track of the test case # results and store them in the test case list: # self.test_case_results counter = 0 for test_case in self.test_case_full_pathname_list: test_case_results = {} self.active_test_case = test_case self.active_test_case_results_folder = "" counter += 1 # Make the test case results folder test_case_short_name = test_case.split('/')[LAST] if '.' in test_case_short_name: test_case_short_name = test_case_short_name.split('.')[FIRST] test_case_results_folder = os.path.join(self.suite_results_folder, test_case_short_name) os.mkdir(test_case_results_folder) self.active_test_case_results_folder = test_case_results_folder message = "Created test case resulst folder %s" %test_case_results_folder logger.info(message) # Identify and use the test case list widget item for this test case list_item = self.testcase_list_widget_items_list[counter - 1] bg_color = self.running_color icon = self.running_icon text = "Test: %s\nFile: %s\nState: Running" %(test_case.split('/')[LAST], test_case, ) self.set_test_case_list_wdiget_item(list_item, icon, bg_color, text ) message = "Running Test case %d of %d: %s " %(counter, len(self.test_case_full_pathname_list), test_case) logger.info(message) self.status_bar.showMessage(message) self.repaint() # heavy sigh ... # ************************* # *** RUN THE TEST CASE *** # ************************* results = self.execute_test_case() if results["return_code"] == 0: list_item = self.testcase_list_widget_items_list[counter - 1] bg_color = self.pass_color icon = self.passed_icon text = "Test: %s\nFile: %s\nState: PASSED" %(test_case.split('/')[LAST], test_case, ) self.set_test_case_list_wdiget_item(list_item, icon, bg_color, text ) test_case_results = {"testcase" : test_case_short_name, "file" : test_case, "result" : "passed", "results_folder" : test_case_results_folder } else: list_item = self.testcase_list_widget_items_list[counter - 1] bg_color = self.fail_color icon = self.failed_icon text = "Test: %s\nFile: %s\nState: FAIILED" %(test_case.split('/')[LAST], test_case, ) self.set_test_case_list_wdiget_item(list_item, icon, bg_color, text ) test_case_results = {"testcase" : test_case_short_name, "file" : test_case, "result" : "failed", "results_folder" : test_case_results_folder } self.repaint() # Write the output and errors files to the test case results folder # output - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - tc_output = results["output"] tc_output = tc_output.strip() if len(tc_output) < 1: pass else: output_file = os.path.join(test_case_results_folder, TC_OUTPUT_FILE) try: f = open(output_file, 'w') f.write(tc_output) f.close() except Exception as e: message = "Ubnable to write to test case output file %s" %output_file logger.error(message) # errors - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - tc_errors = results["error"] tc_errors = tc_errors.strip() if len(tc_errors) < 1: pass else: errors_file = os.path.join(test_case_results_folder, TC_ERRORS_FILE) try: f = open(errors_file, 'w') f.write(tc_errors) f.close() except Exception as e: message = "Ubnable to write to test case errors file %s" %errors_file logger.error(message) # Test Suite results can be used later in summary reports or general reporting self.test_suite_results.append(test_case_results) message = "test case %d of %d complete" %(counter, len(self.test_case_full_pathname_list)) self.status_bar.showMessage(message) logger.info(message) # Need a method for updateing all of the attributes of a list item # Log the results logger.info("Test suite results:") logger.info(str(self.test_suite_results)) else: message = "No test cases loaded. Nothing to do" logger.warning(message) mBox = QMessageBox() mBox.setText(message) mBox.setWindowTitle("Warning -- No test cases") mBox.setIcon(QMessageBox.Warning) mBox.setStandardButtons(QMessageBox.Ok) mBox.exec_() # -------------------------------------------------------------------------- set_test_case_list_wdiget_item() def set_test_case_list_wdiget_item(self, list_widget_item, icon , background_color, text ): """ sets the properties of a test cacse list widget item list_widget_item : test case list widget item icon : QIcon or ClickableIcon background_color : Qt.QColor text : test for the list idget item """ list_widget_item.setText(text) list_widget_item.setBackground(background_color) list_widget_item.setIcon(icon) # -------------------------------------------------------------------------- open_about() def open_about(self): """ """ self.about_dialog.exec() # -------------------------------------------------------------------------- open_help() def open_help(self): """ """ self.help_dialog.exec() # -------------------------------------------------------------------------- execute_test_case() def execute_test_case(self): """ """ # If the active test case is a python script then be sure to run it # UNBUFFERED mode otehrwise just execute the active test case if self.active_test_case.endswith('.py') or self.active_test_case.endswith('.Py') or self.active_test_case.endswith('.PY') : command_list = [PYTHON_INTERPRETER, "-u", self.active_test_case] else: command_list = [self.active_test_case] message = "RUNING:\n%s\n\nRESULTS IN:\n%s\n\n" %(self.active_test_case, self.active_test_case_results_folder) logger.info(message) p = subprocess.Popen(command_list , stdout=subprocess.PIPE , stderr=subprocess.PIPE ) output_buffer = "" error_buffer = "" return_code = 127 sel = selectors.DefaultSelector() sel.register(p.stdout, selectors.EVENT_READ) sel.register(p.stderr, selectors.EVENT_READ) while p.poll() == None: for key, _ in sel.select(): data = key.fileobj.read1().decode() if not data: break if key.fileobj is p.stdout: output_buffer += data else: error_buffer += data data = "%s" %str(data).strip() # text_buffer += data self.console_text_area.append(data) self.console_text_area.moveCursor(QTextCursor.End) self.repaint() return {"return_code": p.poll() , "output" : output_buffer , "error" : error_buffer } # -------------------------------------------------------------------------- event() def event(self, e): """ Manages the default text of the status bar """ default_text = "By your command" if e.type() == QEvent.StatusTip: if e.tip() == '': e = QStatusTipEvent(default_text) return super().event(e)
class PostProcessor(QMainWindow): sim_results_changed = pyqtSignal() post_results_changed = pyqtSignal() figures_changed = pyqtSignal(list, str) def __init__(self, parent=None): QMainWindow.__init__(self, parent) self._settings = QSettings() self._logger = logging.getLogger(self.__class__.__name__) self.setWindowTitle("Processing") self.setWindowIcon(QIcon(get_resource("processing.png"))) self.mainFrame = QWidget(self) self.resize(1000, 600) # toolbar self.toolBar = QToolBar("file control") self.toolBar.setIconSize(QSize(24, 24)) self.addToolBar(self.toolBar) self.actLoad = QAction(self) self.actLoad.setText("load result file") self.actLoad.setIcon(QIcon(get_resource("load.png"))) self.actLoad.setDisabled(False) self.actLoad.triggered.connect(self.load_result_files) self.actPostLoad = QAction(self) self.actPostLoad.setText("load post-result file") self.actPostLoad.setIcon(QIcon(get_resource("load.png"))) self.actPostLoad.setDisabled(False) self.actPostLoad.triggered.connect(self.load_post_result_files) self.actSwitch = QAction(self) self.actSwitch.setText("switch display mode") self.actSwitch.setIcon(QIcon(get_resource("left_mode.png"))) self.actSwitch.setDisabled(False) self.actSwitch.triggered.connect(self.switch_sides) self.displayLeft = True self.spacer1 = QWidget() self.spacer2 = QWidget() self.spacer1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.actReloadMethods = QAction(self) self.actReloadMethods.setText("reload methods") self.actReloadMethods.setIcon(QIcon(get_resource("reload.png"))) self.actReloadMethods.setDisabled(False) self.actReloadMethods.triggered.connect(self.update_post_method_list) self.actReloadMetaMethods = QAction(self) self.actReloadMetaMethods.setText("reload meta methods") self.actReloadMetaMethods.setIcon(QIcon(get_resource("reload.png"))) self.actReloadMetaMethods.setDisabled(False) self.actReloadMetaMethods.triggered.connect( self.update_meta_method_list) self.toolBar.addAction(self.actLoad) self.toolBar.addAction(self.actReloadMethods) self.toolBar.addWidget(self.spacer1) self.toolBar.addAction(self.actSwitch) self.toolBar.addWidget(self.spacer2) self.toolBar.addAction(self.actReloadMetaMethods) self.toolBar.addAction(self.actPostLoad) # main window self.grid = QGridLayout(self.mainFrame) self.grid.setColumnMinimumWidth(0, 70) self.grid.setColumnStretch(0, 0) self.grid.setColumnStretch(1, 1) self.methodList = QListWidget(self) self.methodList.itemDoubleClicked.connect( self.post_processor_clicked) self.update_post_method_list() self.metaMethodList = QListWidget(self) self.metaMethodList.itemDoubleClicked.connect( self.meta_processor_clicked) self.update_meta_method_list() self.sim_result_list = QListWidget(self) self.sim_results_changed.connect(self.update_result_list) self.results = [] self.delShort = QShortcut(QKeySequence(Qt.Key_Delete), self.sim_result_list) self.delShort.activated.connect(self.remove_result_item) # figures self._figure_dict = {} self.figures_changed.connect(self.update_figure_lists) self.post_figure_list = QListWidget(self) self.post_figure_list.currentItemChanged.connect( self.current_figure_changed) self.meta_figure_list = QListWidget(self) self.meta_figure_list.currentItemChanged.connect( self.current_figure_changed) self.plotView = QWidget() self.lastFigure = None self.post_result_list = QListWidget(self) self.post_results_changed.connect(self.update_post_result_list) self.post_results = [] self.delShortPost = QShortcut(QKeySequence(Qt.Key_Backspace), self.post_result_list) self.delShortPost.activated.connect(self.remove_post_result_item) # log dock self.logBox = QPlainTextEdit(self) self.logBox.setReadOnly(True) # init logger for logging box self.textLogger = PlainTextLogger(logging.INFO) self.textLogger.set_target_cb(self.logBox.appendPlainText) logging.getLogger().addHandler(self.textLogger) self.grid.addWidget(QLabel("Result Files:"), 0, 0) self.grid.addWidget(self.sim_result_list, 1, 0) self.grid.addWidget(QLabel("Postprocessors:"), 2, 0) self.grid.addWidget(self.methodList, 3, 0) self.grid.addWidget(QLabel("Figures:"), 4, 0) self.grid.addWidget(self.post_figure_list, 5, 0) self.grid.addWidget(QLabel("Selected Figure:"), 0, 1) self.grid.addWidget(QLabel("Postprocessor Files:"), 0, 2) self.grid.addWidget(self.post_result_list, 1, 2) self.grid.addWidget(QLabel("Metaprocessors:"), 2, 2) self.grid.addWidget(self.metaMethodList, 3, 2) self.grid.addWidget(QLabel("Figures:"), 4, 2) self.grid.addWidget(self.meta_figure_list, 5, 2) self.grid.addWidget(self.logBox, 6, 0, 1, 3) self.mainFrame.setLayout(self.grid) self.setCentralWidget(self.mainFrame) # status bar self.statusBar = QStatusBar(self) self.setStatusBar(self.statusBar) def load_result_files(self): path = self._settings.value("path/simulation_results") dialog = QFileDialog(self) dialog.setFileMode(QFileDialog.ExistingFiles) dialog.setDirectory(path) dialog.setNameFilter("PyMoskito Result files (*.pmr)") if dialog.exec_(): files = dialog.selectedFiles() for single_file in files: if single_file: self._load_result_file(single_file) def _load_result_file(self, file_name): """ loads a result file """ self._logger.info("loading result file {}".format(file_name)) with open(file_name.encode(), "rb") as f: self.results.append(pickle.load(f)) self.sim_results_changed.emit() def update_result_list(self): self.sim_result_list.clear() for res in self.results: name = res["regime name"] self.sim_result_list.addItem(name) def remove_result_item(self): if self.sim_result_list.currentRow() >= 0: del self.results[self.sim_result_list.currentRow()] self.sim_result_list.takeItem(self.sim_result_list.currentRow()) def load_post_result_files(self): path = self._settings.value("path/processing_results") dialog = QFileDialog(self) dialog.setFileMode(QFileDialog.ExistingFiles) dialog.setDirectory(path) dialog.setNameFilter("Postprocessing Output files (*.pof)") if dialog.exec_(): files = dialog.selectedFiles() for single_file in files: if single_file: self._load_post_result_file(single_file) def _load_post_result_file(self, file_name): """ loads a post-result file (.pof) """ name = os.path.split(file_name)[-1][:-4] self._logger.info("loading result file {}".format(file_name)) with open(file_name.encode(), "rb") as f: results = pickle.load(f) results.update({"name": name}) self.post_results.append(results) self.post_results_changed.emit() def update_post_result_list(self): self.post_result_list.clear() for res in self.post_results: name = res["name"] self.post_result_list.addItem(name) def remove_post_result_item(self): if self.post_result_list.currentRow() >= 0: del self.post_results[self.post_result_list.currentRow()] self.post_result_list.takeItem(self.post_result_list.currentRow()) def update_post_method_list(self): self.methodList.clear() modules = pm.get_registered_processing_modules(PostProcessingModule) for mod in modules: self.methodList.addItem(mod[1]) def update_meta_method_list(self): self.metaMethodList.clear() modules = pm.get_registered_processing_modules(MetaProcessingModule) for mod in modules: self.metaMethodList.addItem(mod[1]) def post_processor_clicked(self, item): self.run_processor(str(item.text()), "post") def meta_processor_clicked(self, item): self.run_processor(str(item.text()), "meta") def run_processor(self, name, processor_type): if processor_type == "post": result_files = self.results base_cls = PostProcessingModule elif processor_type == "meta": result_files = self.post_results base_cls = MetaProcessingModule else: self._logger.error("unknown processor type {0}".format( processor_type)) raise ValueError("unknown processor type {0}".format( processor_type)) if not result_files: self._logger.warning("run_processor() Error: no result file loaded") return processor_cls = pm.get_processing_module_class_by_name(base_cls, name) processor = processor_cls() figs = [] try: self._logger.info("executing processor '{0}'".format(name)) figs = processor.process(result_files) except Exception as err: self._logger.exception("Error in processor") self.figures_changed.emit(figs, processor_type) self._logger.info("finished postprocessing") def update_figure_lists(self, figures, target_type): # remove no longer needed elements for item, fig in [(key, val[0]) for key, val in self._figure_dict.items() if val[1] == target_type]: if fig not in [new_fig["figure"] for new_fig in figures]: if target_type == "post": old_item = self.post_figure_list.takeItem( self.post_figure_list.row(item)) del old_item elif target_type == "meta": old_item = self.meta_figure_list.takeItem( self.meta_figure_list.row(item)) del old_item del self._figure_dict[item] # add new ones to internal storage for fig in figures: if fig["figure"] not in self._figure_dict.values(): new_entry = [(fig["name"], (QListWidgetItem(fig["name"]), fig["figure"], target_type) )] self._figure_dict.update(new_entry) # add to display for key, val in self._figure_dict.items(): if val[2] == "post": self.post_figure_list.addItem(val[0]) elif val[2] == "meta": self.meta_figure_list.addItem(val[0]) self.post_figure_list.setCurrentItem(self.post_figure_list.item(0)) self.meta_figure_list.setCurrentItem(self.meta_figure_list.item(0)) def current_figure_changed(self, current_item, last_item=None): if current_item is None: return figures = self._figure_dict if self.lastFigure: self.grid.removeWidget(self.lastFigure) self.lastFigure.setVisible(False) if current_item.text() in figures: figure_widget = figures[current_item.text()][1] self.grid.addWidget(figure_widget, 1, 1, 5, 1) figure_widget.setVisible(True) self.lastFigure = figure_widget def switch_sides(self): self.displayLeft = not self.displayLeft if self.displayLeft: self.actSwitch.setIcon(QIcon(get_resource("left_mode.png"))) self.post_figure_list.setFocus() self.current_figure_changed(self.post_figure_list.currentItem()) else: self.actSwitch.setIcon(QIcon(get_resource("right_mode.png"))) self.meta_figure_list.setFocus() self.current_figure_changed(self.meta_figure_list.currentItem())
class MovieListWidget(GuiComponent): def __init__(self, parent=None): """ This widget displays a list of film :param parent: parent of the widget :type parent: QWidget """ super(MovieListWidget, self).__init__(parent) self.createWidgets() self.updateWidgets(Movie.query()) def onShowFrame(self): self.emit(ShowSearch()) def createWidgets(self): grid = QGridLayout(self) self.lstWidgets = QListWidget(self) self.lblNoFilm = QLabel("There is no film") font = QFont('', 15) self.lblNoFilm.setFont(font) grid.addWidget(self.lblNoFilm, 0, 0, 1, 1, Qt.Qt.AlignCenter) grid.addWidget(self.lstWidgets, 0, 0) self.setLayout(grid) def updateWidgets(self, data): """ update the list with the data parameter :param data: :type: list of movies model :return: """ hasFilm = False self.lstWidgets.clear() for film in data: hasFilm = True try: item = QListWidgetItem(self.lstWidgets) itemW = ResultRow(self, film) item.setSizeHint(itemW.sizeHint()) self.lstWidgets.setItemWidget(item, itemW) #itemW.show.connect(lambda x: self.clickedSee(film)) itemW.btnSee.clicked.connect( lambda ignore, f=film: self.clickedSee(f)) except Exception as e: log.info("ERROR WHILE UPDATING MOVIE LIST") log.info(e) if hasFilm is True: self.lblNoFilm.setVisible(False) else: self.lblNoFilm.setVisible(True) self.lblNoFilm.setText("There is no result for this research") if Movie.query().count() == 0: self.lblNoFilm.setVisible(True) self.lblNoFilm.setText( "No film in database, please add a folder (File - add folder)") log.info("List of widgets %s", len(self.lstWidgets)) def clickedSee(self, film): self.emit(ShowFrame(MovieWidget.__name__, film)) def handle(self, event): super().handle(event) #remember kids, always call super if isinstance(event, Response) and isinstance(event.request, SearchRequest): log.info("-------------- UPDATING LIST OF MOVIES ----------------") self.updateWidgets(event.data) event.stopPropagate() #self.emit(ShowFrame(self)) if isinstance( event, ShowFrame ) and event.frame == self.__class__.__name__ and event.data is not None: self.updateWidgets(event.data)
class ListEdit(QWidget): """A widget to edit a list of items (e.g. a list of directories).""" # emitted when anything changed in the listbox. changed = pyqtSignal() def __init__(self, *args, **kwargs): QWidget.__init__(self, *args, **kwargs) layout = QGridLayout(self) self.setLayout(layout) self.addButton = QPushButton(icons.get('list-add'), '') self.editButton = QPushButton(icons.get('document-edit'), '') self.removeButton = QPushButton(icons.get('list-remove'), '') self.listBox = QListWidget() layout.setContentsMargins(1, 1, 1, 1) layout.setSpacing(0) layout.addWidget(self.listBox, 0, 0, 8, 1) layout.addWidget(self.addButton, 0, 1) layout.addWidget(self.editButton, 1, 1) layout.addWidget(self.removeButton, 2, 1) @self.addButton.clicked.connect def addClicked(): item = self.createItem() if self.openEditor(item): self.addItem(item) @self.editButton.clicked.connect def editClicked(): item = self.listBox.currentItem() item and self.editItem(item) @self.removeButton.clicked.connect def removeClicked(): item = self.listBox.currentItem() if item: self.removeItem(item) @self.listBox.itemDoubleClicked.connect def itemDoubleClicked(item): item and self.editItem(item) self.listBox.model().layoutChanged.connect(self.changed) def updateSelection(): selected = bool(self.listBox.currentItem()) self.editButton.setEnabled(selected) self.removeButton.setEnabled(selected) self.changed.connect(updateSelection) self.listBox.itemSelectionChanged.connect(updateSelection) updateSelection() app.translateUI(self) def translateUI(self): self.addButton.setText(_("&Add...")) self.editButton.setText(_("&Edit...")) self.removeButton.setText(_("&Remove")) def createItem(self): return QListWidgetItem() def addItem(self, item): self.listBox.addItem(item) self.itemChanged(item) self.changed.emit() def removeItem(self, item): self.listBox.takeItem(self.listBox.row(item)) self.changed.emit() def editItem(self, item): if self.openEditor(item): self.itemChanged(item) self.changed.emit() def setCurrentItem(self, item): self.listBox.setCurrentItem(item) def setCurrentRow(self, row): self.listBox.setCurrentRow(row) def openEditor(self, item): """Opens an editor (dialog) for the item. Returns True if the dialog was accepted and the item edited. Returns False if the dialog was cancelled (the item must be left unedited). """ pass def itemChanged(self, item): """Called after an item has been added or edited. Re-implement to do something at this moment if needed, e.g. alter the text or display of other items. """ pass def setValue(self, strings): """Sets the listbox to a list of strings.""" self.listBox.clear() self.listBox.addItems(strings) self.changed.emit() def value(self): """Returns the list of paths in the listbox.""" return [self.listBox.item(i).text() for i in range(self.listBox.count())] def setItems(self, items): """Sets the listbox to a list of items.""" self.listBox.clear() for item in items: self.listBox.addItem(item) self.itemChanged(item) self.changed.emit() def items(self): """Returns the list of items in the listbox.""" return [self.listBox.item(i) for i in range(self.listBox.count())] def clear(self): """Clears the listbox.""" self.listBox.clear() self.changed.emit()
class MainWidget(QWidget): def __init__(self, parent=None): super().__init__() self.parent = parent self.template = None self.characters = [] self.charIndex = 0 self.init_UI() def connect_all(self): self.addChar.clicked.connect(self.add_character) self.removeChar.clicked.connect(self.remove_character) self.listWidget.currentItemChanged.connect(self.item_changed) self.listWidget.itemChanged.connect(self.item_text_changed) for r in range(self.tabs.count()): w = self.tabs.widget(r) w.connect_all() def disconnect_all(self): self.addChar.clicked.disconnect() self.removeChar.clicked.disconnect() self.listWidget.currentItemChanged.disconnect() self.listWidget.itemChanged.disconnect() for r in range(self.tabs.count()): w = self.tabs.widget(r) w.disconnect_all() def disable_stuff(self, disabled): self.addChar.setDisabled(disabled) self.removeChar.setDisabled(disabled) def init_UI(self): ## Just to make life easier get_icon = Icons().get_icon ## List of characters self.listWidget = QListWidget(self) ## Add character button self.addChar = QPushButton(QIcon(get_icon("list-add")), "") self.addChar.setToolTip("Add a character") ## Remove character button self.removeChar = QPushButton(QIcon(get_icon("list-remove")), "") self.removeChar.setToolTip("Remove selected character") ## Bullshit to make qsplitter work self.list = MyListWidget(self) ## Initial template self.template = self.parent.get_template() ## Tab widget self.tabs = QTabWidget() self.load_tabs() ## Tabs start out disabled self.tabs.setDisabled(True) ## Connect it up self.connect_all() ##============= LAYOUTS splitter = QSplitter() splitter.addWidget(self.list) splitter.addWidget(self.tabs) splitter.setSizes([(WINDOW_WIDTH * .25), (WINDOW_WIDTH * .75)]) ## Set the layout hbox = QHBoxLayout() hbox.addWidget(splitter) self.setLayout(hbox) def load_tabs(self): if self.template != None: tabIndex = 0 for tab in self.template.iter("tab"): widget = Tab(self, tabIndex, tab) tabIndex += 1 self.tabs.addTab(widget, tab.find("title").text) def add_character(self): char = CharacterInfo(self.template) self.characters.append(char) li = QListWidgetItem(char.listName) li.setFlags(li.flags() | Qt.ItemIsEditable) self.listWidget.addItem(li) self.listWidget.setCurrentItem(li) ## Enable the tabs widget self.tabs.setDisabled(False) def remove_character(self): idx = self.listWidget.currentRow() li = self.listWidget.item(idx) if li != None: ## Kill whatever character at the index null = self.characters.pop(idx) ni = self.listWidget.item(idx + 1) pi = self.listWidget.item(idx - 1) #self.listWidget.currentItemChanged.disconnect() self.disconnect_all() sip.delete(li) self.listWidget.currentItemChanged.connect(self.item_changed) if ni != None: self.listWidget.setCurrentItem(ni) idx = self.listWidget.currentRow() self.charIndex = idx self.load_values(self.characters[idx]) elif pi != None: self.listWidget.setCurrentItem(pi) idx = self.listWidget.currentRow() self.charIndex = idx self.load_values(self.characters[idx]) else: self.charIndex = -1 self.tabs.setDisabled(True) self.listWidget.currentItemChanged.connect(self.item_changed) self.clear_values() self.connect_all() def item_changed(self): li = self.listWidget.currentItem() if li != None: self.charIndex = self.listWidget.currentRow() self.load_values(self.characters[self.charIndex]) def item_text_changed(self): li = self.listWidget.currentItem() if li != None: self.characters[self.charIndex].listName = li.text() def load_values(self, char): for t in range(len(self.characters[self.charIndex].tabs)): tab = self.tabs.widget(t) tab.load_values(char) def clear_values(self): for t in range(self.tabs.count()): w = self.tabs.widget(t) w.clear_values() #if len( self.characters ) > 0: # for t in range( len(self.characters[ self.charIndex ].tabs )): # tab = self.tabs.widget( t ) # tab.clear_values() def clear_all(self): ## Kill characters and disable the tabs self.characters = [] self.tabs.setDisabled(True) ## Kill tabs self.tabs.clear() ## Kill the list self.listWidget.clear() def load_list(self): for char in self.characters: li = QListWidgetItem(char.listName) li.setFlags(li.flags() | Qt.ItemIsEditable) self.listWidget.addItem(li) def reload(self, template, characters): self.disconnect_all() self.clear_all() self.template = template #c = characters[ 0 ] #print( c.tabs[ 0 ][0][ "name" ] ) self.characters = characters self.load_list() self.load_tabs() self.connect_all() li = self.listWidget.item(0) if li != None: self.listWidget.setCurrentItem(li) self.tabs.setDisabled(False)