class MyForm(QtWidgets.QMainWindow): def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.test_btn.clicked.connect(self.btn_clicked) def btn_clicked(self): QtWidgets.QMessageBox.critical(self,"dshfs","fadsfasd")
class MainWindow(QtWidgets.QMainWindow): """ The main editor window. """ def __init__(self): super(MainWindow, self).__init__() self._scrapExtracter = ScrapExtracter() self._highlight = highlight_chunks # set up UI using generated code from designer file self._ui = Ui_MainWindow() self._ui.setupUi(self) # called on every change to the text document self._ui.textEdit.document().contentsChange.connect(self._update_tree) # handle save button click self._ui.actionSave.triggered.connect(self._save) def _update_tree(self, position, charsRemoved, charsAdded): """ Sync text in the document with the parse tree. """ self._scraps = self._scrapExtracter.extract_scraps( self._ui.textEdit.toPlainText()) self._update_document() def _update_document(self): """ Update the document to reflect the parse tree. """ self._highlight(self._ui.textEdit, self._scraps, YellowBackground()) def _save(self): pass
class DelphosWindow(QMainWindow): """Manages the main Delphos window interface (Ui_MainWindow) """ def __init__(self, gui_manager): QMainWindow.__init__(self, None) #Initialize myself as a widget self.ui = Ui_MainWindow() self.ui.setupUi(self) #Create the components of the window self.gui_manager = gui_manager self.dock_full_screen = False self.min_doc_dock_width = 200 #Maximize the display to full size #self.showMaximized() #Add status bar at bottom of window self.statusbar = QtGui.QStatusBar(self) self.statusbar.setObjectName("statusbar") self.setStatusBar(self.statusbar) #Add progress bar to status bar self.pb = QProgressBar(self.statusBar()) self.pb.setMinimum(0) self.pb.setMaximum(0) self.statusbar.addPermanentWidget(self.pb) self.pb.hide() QObject.connect(self.ui.menu_dock_visible, SIGNAL("triggered()"), self.toggle_documentation_window) QObject.connect(self.ui.dock_doc, SIGNAL("visibilityChanged(bool)"), self.toggle_dock_visible_menu) QObject.connect(self.ui.menu_dock_floating, SIGNAL("triggered()"), self.toggle_dock_float) QObject.connect(self.ui.dock_doc, SIGNAL("topLevelChanged(bool)"), self.toggle_dock_floating_menu) QObject.connect(self.ui.menu_open_full_doc, SIGNAL("triggered()"), self.load_full_doc) #self.ui.dock_doc.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) def load_full_doc(self, project_type=None, language=None): """Load full documentation in external application """ #Find which documentation subdir to look in if not project_type: project_type = self.gui_manager.project_manager.get_current_project_type( ) if not language: language = self.gui_manager.config_manager.get_language() if project_type == 'fisheries': if language == 'english': doc_subdir = 'fisheries' + os.sep + 'english' + os.sep else: doc_subdir = 'fisheries' + os.sep + 'spanish' + os.sep elif project_type == 'sites': if language == 'english': doc_subdir = 'sites' + os.sep + 'english' + os.sep else: doc_subdir = 'sites' + os.sep + 'spanish' + os.sep elif project_type == 'communities': if language == 'english': doc_subdir = 'communities' + os.sep + 'english' + os.sep else: doc_subdir = 'communities' + os.sep + 'spanish' + os.sep doc_path = os.getcwd( ) + os.sep + "documentation" + os.sep + doc_subdir + 'documentation.html' doc_url = "file:" + urllib.pathname2url(unicode(doc_path)) #file:///U|/dev/delphos/src/documentation/fisheries/english/letter_to_experts.doc self.gui_manager.desktop_services.openUrl(QUrl(doc_url)) def load_toc(self, project_type=None, language=None): """Loads the table of contents within the dock widget """ #Find which toc data to load if not project_type: project_type = self.gui_manager.project_manager.get_current_project_type( ) if not language: language = self.gui_manager.config_manager.get_language() toc = "" if project_type == 'fisheries': if language == 'english': toc = fisheries_english_toc else: toc = fisheries_spanish_toc elif project_type == 'communities': if language == 'english': toc = communities_english_toc else: toc = communities_spanish_toc elif project_type == 'sites': if language == 'english': toc = sites_english_toc else: toc = sites_spanish_toc self.process_toc(deepcopy(toc)) def process_toc(self, toc): self.ui.toc_tree.clear() #Make a copy as original will be destroyed for heading in toc: root_item = self.ui.toc_tree.invisibleRootItem() self.process_heading(heading, root_item) def process_heading(self, heading, parent): #print type(heading) if type(heading) == str: tree_item = QTreeWidgetItem(parent) tree_item.setText(0, heading) if type(heading) == dict: (heading_name, subheadings) = heading.popitem() tree_item = QTreeWidgetItem(parent) tree_item.setText(0, heading_name) for subheading in subheadings: self.process_heading(subheading, tree_item) def process_toc_click(self, item, column): """Builds URL from toc heading name and reloads doc editor """ heading = item.text(column) #Morph heading name into anchor label name label = heading.replace(' ', '_') label = heading.replace('/', '_') label = heading.replace('.', '') label = label.toLower() #Build URL project_type = self.gui_manager.project_manager.get_current_project_type( ) language = self.gui_manager.config_manager.get_language() #Load URL and go to anchor within it self.ui.doc_browser.load_anchor(label, project_type, language) def process_help_click(self, en_name, sp_name): """Uses the help type given to load a section of the documentation """ en_label = en_name.replace('help_', '') sp_label = sp_name.replace('help_', '') #Build URL project_type = self.gui_manager.project_manager.get_current_project_type( ) language = self.gui_manager.config_manager.get_language() #Load URL and go to anchor within it if language == 'english': self.ui.doc_browser.load_anchor(en_label, project_type, language) elif language == 'spanish': self.ui.doc_browser.load_anchor(sp_label, project_type, language) #Show the documentation if its hidden if not self.ui.dock_doc.isVisible(): self.ui.menu_dock_visible.trigger() def dock_full_screen(self): return self.dock_full_screen def toggle_dock(self): if self.dock_full_screen: self.ui.dock_doc.setMinimumSize(self.min_doc_dock_width, 0) self.ui.dock_doc.resize(self.min_doc_dock_width, self.ui.dock_doc.height()) doc_dock_size = self.ui.dock_doc.sizeHint() self.ui.toc_box.resize(100, self.ui.toc_box.height()) self.ui.toc_tree.resize(100, self.ui.toc_box.height()) self.ui.doc_box.resize(100, self.ui.doc_box.height()) self.ui.doc_browser.resize(100, self.ui.toc_box.height()) self.dock_full_screen = False else: self.ui.dock_doc.setMinimumSize(self.width(), 0) self.dock_full_screen = True def toggle_documentation_window(self): if self.ui.dock_doc.isVisible(): self.ui.dock_doc.hide() else: self.ui.dock_doc.show() def toggle_dock_visible_menu(self): if self.ui.dock_doc.isVisible(): self.ui.menu_dock_visible.setChecked(True) else: self.ui.menu_dock_visible.setChecked(False) def toggle_dock_float(self): if self.ui.dock_doc.isFloating(): self.ui.dock_doc.setFloating(False) else: self.ui.dock_doc.setFloating(True) def toggle_dock_floating_menu(self, isFloating): if isFloating: self.ui.menu_dock_floating.setChecked(False) else: self.ui.menu_dock_floating.setChecked(True)
class MainWindow(QtWidgets.QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.addToolBar(NavigationToolbar2QT(self.ui.MplWidget.canvas, self), ) self.ui.log_scaling_checkbox.setCheckState(QtCore.Qt.Unchecked) self.num_decimals = 4 self.limiting_exponent = 4 self.wavelength_axis = 'rows' self.time_axis = 'columns' # This should be adjustable outside the code to handle various types of data self.rows_values = 0 # the intention is that the values for "time" are in row 0 and wl are in column 0 self.columns_values = 0 # These might be stupid names and unnecessary in general self.plot_full = dict(Left=False, Right=False, Lower=False) @QtCore.pyqtSlot(int) def log_scaling_cb_state_changed(self, state): if state == 2: prefs.scaling = 'log' elif state == 0: prefs.scaling = 'linear' if self.plot_full['Left']: self.ui.MplWidget.canvas.axes_left.set_yscale(prefs.scaling) if self.plot_full['Right']: self.ui.MplWidget.canvas.axes_right.set_yscale(prefs.scaling) if self.plot_full['Lower']: self.ui.MplWidget.canvas.axes_lower.set_yscale(prefs.scaling) if self.plot_full['Left'] or self.plot_full['Right'] or self.plot_full[ 'Lower']: self.ui.MplWidget.canvas.draw() @QtCore.pyqtSlot() def load_btn_clicked(self): load_file_name, _ = QFileDialog.getOpenFileName(self, 'Load File') # If the user doesn't cancel if load_file_name != '': data_frame = pd.read_csv(load_file_name, delimiter='\t', header=None) full_contents = data_frame.to_numpy() row_ct, col_ct = full_contents.shape self.times = full_contents[0, 1:col_ct] self.wavelengths = full_contents[1:row_ct, 0] data = full_contents[1:row_ct, 1:col_ct] self.data_values = np.transpose(data) self.ui.MplWidget.canvas.axes_right.clear() self.ui.MplWidget.canvas.axes_lower.clear() self.update_surf_plot(x=self.wavelengths, y=self.times, z=self.data_values, side='Left') def help_btn_clicked(self): print( 'Does nothing at this time, see read-me file for some information') @QtCore.pyqtSlot() def clear_btn_clicked(self): self.ui.MplWidget.canvas.axes_left.clear() self.ui.MplWidget.canvas.axes_right.clear() self.ui.MplWidget.canvas.axes_lower.clear() @QtCore.pyqtSlot() def fit_btn_clicked(self): self.OpenFitWindow = FitWindow() self.OpenFitWindow.show() @QtCore.pyqtSlot() def prefs_btn_clicked(self): self.PrefsWindow = PreferencesWindow() self.PrefsWindow.show() def update_surf_plot(self, x=None, y=None, z=None, pad_axes=True, side='Left'): # , clear=False, label=None): if pad_axes is True: x_ct = len(x) y_ct = len(y) delta_x = x[x_ct - 1] - x[x_ct - 2] delta_y = y[y_ct - 1] - y[y_ct - 2] x = np.append(x, (x[x_ct - 1] + delta_x)) y = np.append(y, (y[y_ct - 1] + delta_y)) divnorm = colors.DivergingNorm(vcenter=0) if side == 'Left': self.ui.MplWidget.canvas.axes_left.clear() self.ui.MplWidget.canvas.axes_left.pcolormesh(x, y, z, norm=divnorm, cmap='bwr') if prefs.scaling == 'log': self.ui.MplWidget.canvas.axes_left.set_yscale('log') elif side == 'Right': self.ui.MplWidget.canvas.axes_right.clear() self.ui.MplWidget.canvas.axes_right.pcolormesh(x, y, z, norm=divnorm, cmap='bwr') if prefs.scaling == 'log': self.ui.MplWidget.canvas.axes_right.set_yscale('log') elif side == 'Lower': self.ui.MplWidget.canvas.axes_lower.clear() self.ui.MplWidget.canvas.axes_lower.pcolormesh(x, y, z, norm=divnorm, cmap='bwr') if prefs.scaling == 'log': self.ui.MplWidget.canvas.axes_left.set_yscale('log') print('side: ' + side) self.plot_full[side] = True print('plot_full: ' + str(self.plot_full)) self.ui.MplWidget.canvas.draw()
class MainApp(QtWidgets.QMainWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowTitle("Pomodoro") # all time here in seconds, in comments are default values self.study_time = 1500 # 1500 is 25 minutes self.short_break_time = 300 # 300 is 5 minutes self.long_break_time = 900 # 900 is 15 minutes self.remaining_seconds = self.study_time self.beep_noise = "bugle_tune.wav" # sound played self.last_countdown = "" self.history = {} self.studies_today = self.load_history() self.last_countdown = "study" self.setup_settings() self.setup_timer() self.ui.button.clicked.connect(self.start_timer) self.ui.actionSettings.triggered.connect(self.open_settings_window) self.ui.pushButton.clicked.connect(self.open_calendar_window) def open_settings_window(self): self.settings_dialog = SettingsWindow() self.settings_dialog.submitted.connect(self.change_times) def open_calendar_window(self): self.calendar_window = CalendarWindow(self.history) def setup_settings(self): config = ConfigParser() try: config.read("config.ini") self.study_time = int(config.get('main', 'study time')) self.short_break_time = int(config.get('main', 'short break')) self.long_break_time = int(config.get('main', 'long break')) self.remaining_seconds = int(config.get("main", 'study time')) except: config.read("config.ini") config.add_section("main") config.set("main", "study time", "1500") config.set("main", "short break", "300") config.set("main", "long break", "900") with open('config.ini', 'w') as f: config.write(f) def change_times(self, study_time, short_break_time, long_break_time): self.study_time = int(study_time) self.short_break_time = int(short_break_time) self.long_break_time = int(long_break_time) def setup_timer(self): self.ui.times_studied.setText(f"🍅 {self.studies_today} times today") def start_timer(self): self.ui.button.setText("Pause") self.ui.button.clicked.connect(self.pause_timer) self.timer = QtCore.QTimer() self.timer.timeout.connect(self.countdown) self.timer.start(1000) def pause_timer(self): self.timer.stop() self.ui.button.setText("Resume") self.ui.button.clicked.connect(self.start_timer) def countdown(self): if self.remaining_seconds == 0: self.timer.stop() self.ui.timer_display.setText("00:00") self.ui.button.setText("Start") self.ui.button.clicked.connect(self.start_timer) self.remaining_seconds = self.study_time if self.last_countdown == "study": self.studies_today += 1 self.save_history() if self.studies_today % 4 == 0: self.remaining_seconds = self.long_break_time else: self.remaining_seconds = self.short_break_time self.last_countdown = "break" self.ui.times_studied.setText( f"🍅 {self.studies_today} times today") QtMultimedia.QSound.play(self.beep_noise) elif self.last_countdown == "break": self.remaining_seconds = self.study_time self.last_countdown = "study" QtMultimedia.QSound.play(self.beep_noise) else: # countdown from 25 minutes to 0 minutes = int( (self.remaining_seconds - (self.remaining_seconds % 60)) / 60) # displaying 0 minutes as 00:00 not as 0:00 if minutes == 0: minutes = "00" else: minutes = str(minutes) seconds = self.remaining_seconds % 60 # displaying 0 seconds as 00:00 not as 00:0 if seconds == 0: seconds = "00" else: seconds = str(seconds) if len(minutes) == 1: minutes = "0" + minutes if len(seconds) == 1: seconds = "0" + seconds self.ui.timer_display.setText(f"{minutes}:{seconds}") self.remaining_seconds -= 1 def load_history(self): try: with open("history.json", 'r') as file: self.history = json.load(file) except FileNotFoundError: with open('history.json', 'w') as file: json.dump(self.history, file) if str(date.today()) in self.history.keys(): return int((self.history[str(date.today())])) else: return 0 def save_history(self): if str(date.today()) in self.history.keys(): self.history[str(date.today())] += 1 else: self.history[str(date.today())] = 1 with open("history.json", 'w') as file1: json.dump(self.history, file1)
class AppWindow(QMainWindow): def __init__(self): print('AppWindow::__init__()') super().__init__() self.settings = QSettings('./settings.ini', QSettings.IniFormat) self.defaultBboxesLandscape = [ QRectF(0, 0.1, 1, 0.8), QRectF(0.1, 0.1, 0.9, 0.8) ] self.defaultBboxesPortrait = [ QRectF(0, 0, 1, 0), QRectF(0.05, 0.05, 0.9, 0) ] self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.buttonDone.clicked.connect(self.slot_on_buttonDone_clicked) self.ui.buttonSwitchInOutEditor.clicked.connect( self.slot_on_buttonSwitchInOutEditor_clicked) self.ui.buttonSwapInOutEditor.clicked.connect( self.slot_on_buttonSwapInOutEditor_clicked) self.ui.buttonImageNext.clicked.connect( self.slot_on_buttonImageNext_clicked) self.ui.buttonImagePrev.clicked.connect( self.slot_on_buttonImagePrev_clicked) self.ui.buttonLoadKdenlive.clicked.connect( self.slot_on_buttonLoadKdenlive_clicked) self.ui.buttonLoadImages.clicked.connect( self.slot_on_buttonLoadImages_clicked) self.ui.buttonSaveKdenlive.clicked.connect( self.slot_on_buttonSaveKdenlive_clicked) self.ui.buttonSaveBboxesJson.clicked.connect( self.slot_on_buttonSaveBboxesJson_clicked) self.ui.buttonApplyBboxRatioMultiplier.clicked.connect( self.slot_on_buttonApplyBboxRatioMultiplier_clicked) self.ui.lineeditTargetVideoResolution.textChanged.connect( self.slot_on_lineeditTargetVideoResolution_textChanged) self.ui.checkboxStayInside.toggled.connect( self.slot_on_checkboxStayInside_toggled) self.ui.buttonLoadKdenlive.setShortcut(QKeySequence('Ctrl+o')) self.ui.buttonSwitchInOutEditor.setShortcut(QKeySequence('Tab')) self.ui.buttonSwapInOutEditor.setShortcut(QKeySequence('w')) self.ui.buttonImageNext.setShortcut(QKeySequence('Space')) self.ui.buttonImagePrev.setShortcut(QKeySequence('Backspace')) self.ui.checkboxStayInside.setShortcut(QKeySequence('s')) self.ui.buttonSaveKdenlive.setEnabled(False) self.ui.buttonImageNext.setEnabled(False) self.ui.buttonImagePrev.setEnabled(False) self.ui.lineeditTargetVideoResolution.setText('1920x1080') # self.ui.image.setTargetRatio(1920 / 1080) # Aspect ratio of the video slideshow self.ui.image.bboxesChanged.connect(self.bboxesChanged) self.fileFormats = [ 'All supported formats: *.kdenlive, *.json (*.kdenlive *.json)', 'Kdenlive Project Files: *.kdenlive (*.kdenlive)', 'Bboxes Json: *.json (*.json)', ] self.kdenliveFile = None self.images = [] self.imagesData = {} self.imageIdx = 0 if len(sys.argv) > 1: if re.match('.*\.kdenlive', sys.argv[1]): self.LoadKdenliveFile(sys.argv[1]) else: self.images = sys.argv[1:] print('images:', self.images) # Load bboxes from json try: self.LoadBboxesJson(self.getBboxesFilename()) except: print('WARNING: unable to parse json data') traceback.print_exc() # Override json bboxes with kdenlive clip transformations if self.kdenliveFile is not None: self.KdenliveFileToImagesData() img_path = self.images[self.imageIdx] print('imagesData:', self.imagesData) self.SetImageIdx(self.imageIdx) self.show() def setShortcut(button, shortcutStr): button.setShortcut(QKeySequence(shortcutStr)) button.setText(button.text() + ' [' + shortcutStr + ']') def closeEvent(self, e): print('closeEvent()') #self.save() def bboxesChanged(self): self.updateInfo() def updateInfo(self): if len(self.images) == 0: return bboxes = self.ui.image.getBboxes01() #print('images:', self.images) #print('bboxes:', bboxes) self.ui.labelInfoPath.setText(self.images[self.imageIdx]) self.ui.labelInfoScale.setText( 'in -> out scale: %02f' % (bboxes[1].width() / bboxes[0].width() if bboxes[0].width() > 0 else -1)) def getTargetRatio(self): a = self.ui.lineeditTargetVideoResolution.text().split('x') w = int(a[0]) h = int(a[1]) return w / h # Aspect ratio of the video slideshow def slot_on_lineeditTargetVideoResolution_textChanged(self, text): self.ui.image.setTargetRatio( self.getTargetRatio()) # Aspect ratio of the video slideshow def slot_on_checkboxStayInside_toggled(self, checked): print('toggled()', checked) # print('CHECK 611 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) self.ui.image.setStayInside(checked) # print('CHECK 612 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) img_path = self.images[self.imageIdx] # print('CHECK 613 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) self.imagesData[img_path]['stay_inside_image'] = checked # print('CHECK 614 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) def toJson(self): out = {} for img_path in self.imagesData: print('img_path:', img_path) out[img_path] = {} out[img_path]['stay_inside_image'] = self.imagesData[img_path][ 'stay_inside_image'] if 'stay_inside_image' in self.imagesData[ img_path] else True out[img_path]['bboxes'] = [] for bbox in self.imagesData[img_path]['bboxes']: out[img_path]['bboxes'].append({ 'x': bbox.x(), 'y': bbox.y(), 'w': bbox.width(), 'h': bbox.height() }) return json.dumps(out, indent=4) def fromJson(self, jsonStr): self.imagesData = {} jsonObj = json.loads(jsonStr) print('jsonObj:', jsonObj) for img_path in jsonObj: print('img_path:', img_path) bboxes = [] for bbox in jsonObj[img_path]['bboxes']: print('bbox:', bbox) bboxes.append( QRectF(bbox['x'], bbox['y'], bbox['w'], bbox['h'])) self.imagesData[img_path] = { 'stay_inside_image': jsonObj[img_path]['stay_inside_image'], 'bboxes': bboxes } if img_path not in self.images: self.images.append(img_path) print('imagesData:', self.imagesData) def slot_on_buttonDone_clicked(self): print('clicked') self.close() def slot_on_buttonSwitchInOutEditor_clicked(self): print('switch editor') #traceback.print_stack(file = sys.stdout) self.ui.image.switchEditor() def slot_on_buttonSwapInOutEditor_clicked(self): print('swap editor') self.ui.image.swapEditors() def areBboxesInsideImage(self, bboxes): inside = True for bbox in bboxes: if bbox.left() < 0 or bbox.top() < 0 or bbox.right( ) > 1 or bbox.bottom() > 1: inside = False print('areBboxesInsideImage() bbox:', bbox, 'inside:', inside) print('areBboxesInsideImage() return ', inside) return inside def SetImageIdx(self, idx): print('SetImageIdx() ', self.imageIdx, '->', idx) # print('CHECK 1 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) #print('SetImageIdx() imagesData:', self.imagesData) self.SaveCurrentImageData() # print('CHECK 2 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) # Temporarily don't restrict bboxes self.ui.checkboxStayInside.setChecked(False) # print('CHECK 3 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) self.imageIdx = max(0, min(len(self.images) - 1, idx)) print('SetImageIdx() imageIdx:', self.imageIdx) img_path = self.images[self.imageIdx] print('SetImageIdx() img_path:', img_path) self.ui.image.openImage(img_path) # print('CHECK 4 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) bboxes = [] if img_path in self.imagesData: print('SetImageIdx() img_path:', img_path, 'bboxes:', self.imagesData[img_path]) #self.ui.checkboxStayInside.setChecked(self.imagesData[img_path]['stay_inside_image']) bboxes = [] if 'bboxes' in self.imagesData[img_path]: bboxes = self.imagesData[img_path]['bboxes'] # print('CHECK 5 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) print('SetImageIdx() bboxes 1:', bboxes) if len(bboxes) != 2: print('SetImageIdx() no bboxes found -> creating default bboxes') bboxes = [] img_size = self.ui.image.getImageSize() if img_size.width() > img_size.height(): for bbox in self.defaultBboxesLandscape: bboxes.append(QRectF(bbox)) print('SetImageIdx() bboxes 2:', bboxes) else: ratio_img = img_size.height() / img_size.width() ratio_target = self.getTargetRatio() print('SetImageIdx() ratio_img:', ratio_img) for bbox in self.defaultBboxesPortrait: bbox_copy = QRectF(bbox) bbox_copy.setWidth(bbox_copy.width() * ratio_img * ratio_target) bbox_copy.setHeight(bbox_copy.width() / ratio_img / ratio_target) print('SetImageIdx() bbox_copy: ', bbox_copy) bbox_copy.moveCenter(QPointF(0.5, 0.5)) print('SetImageIdx() bbox_copy: ', bbox_copy) bboxes.append(bbox_copy) print('SetImageIdx() bboxes 3:', bboxes) # print('CHECK 6 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) if len(bboxes) == 2: print('SetImageIdx() bboxes:', bboxes) self.ui.image.setBboxes01(bboxes) # print('CHECK 61 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) stay_inside = self.areBboxesInsideImage(bboxes) print('SetImageIdx() stay_inside:', stay_inside) # print('CHECK 62 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) self.ui.checkboxStayInside.setChecked(stay_inside) # print('CHECK 63 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) # print('CHECK 7 3567_IMG.jpg bboxes: ',self.imagesData['clips/3567_IMG.jpg']['bboxes']) self.ui.buttonImagePrev.setEnabled(self.imageIdx > 0) self.ui.buttonImageNext.setEnabled( self.imageIdx + 1 < len(self.images)) self.updateInfo() def slot_on_buttonImageNext_clicked(self): print('on_buttonImageNext_clicked()') self.SetImageIdx(self.imageIdx + 1) def slot_on_buttonImagePrev_clicked(self): print('on_buttonImagePrev_clicked()') self.SetImageIdx(self.imageIdx - 1) def LoadKdenliveFile(self, filename): print('LoadKdenliveFile()') self.kdenliveFile = KdenliveFile() self.kdenliveFile.Load(filename) self.ui.buttonSaveKdenlive.setEnabled(True) def KdenliveFileToImagesData(self): images_data = self.kdenliveFile.GetImagesData() images_data = dict( filter(lambda elem: re.match('.*\.jpg', elem[0]), images_data.items())) for img_path in images_data: if img_path not in self.images: self.images.append(img_path) for img_path in images_data: print('img_path:', img_path) if 'bboxes' in images_data[img_path] and len( images_data[img_path]['bboxes']) > 0: if img_path in self.imagesData: print('overriding json bboxes:', self.imagesData[img_path], ' with clip transform bboxes:', images_data[img_path]) self.imagesData[img_path] = images_data[img_path] self.imagesData = {**self.imagesData, **images_data} def LoadBboxesJson(self, filename): with open(filename, 'r') as f: json_str = f.read() print('json_str:', json_str) self.fromJson(json_str) def slot_on_buttonLoadKdenlive_clicked(self): print('slot_on_buttonLoadKdenlive_clicked()') #filename, filt = QFileDialog.getOpenFileName(self, "Load .kdenlive", "", "Kdenlive Project Files (*.kdenlive)") filename, filt = QFileDialog.getOpenFileName( self, "Load .kdenlive", self.settings.value('filedialog_path', ''), ';;'.join(self.fileFormats), self.fileFormats[0]) if filename is None or filename == '': return self.settings.setValue('filedialog_path', os.path.dirname(filename)) ext = os.path.splitext(filename)[1].lower() print('filename:', filename) print('filt:', filt) print('ext:', ext) if ext == '.kdenlive': self.LoadKdenliveFile(filename) self.KdenliveFileToImagesData() elif ext == '.json': self.LoadBboxesJson(filename) self.SetImageIdx(0) def LoadImages(self, filenames): self.images = filanemes self.SetImageIdx(0) def slot_on_buttonLoadImages_clicked(self): print('slot_on_buttonLoadImages_clicked()') filenames, filt = QFileDialog.getOpenFileNames( self, "Load images", self.settings.value('filedialog_path', ''), "Image Files (*.jpg, *.png, *.tiff)") if filename is None or filename == '': return self.settings.setValue('filedialog_path', os.path.dirname(filename)) print('filenames:', filenames) self.LoadImages(filenames) def SaveKdenlive(self, filename): self.SaveCurrentImageData() if self.kdenliveFile is None: return #self.setBboxesRatioMultiplier(0.5) self.kdenliveFile.GroupClipsWithSameBoundaries() #self.kdenliveFile.AddBeats('Radioactive- Gatsby Souns live.mp3', '/media/miso/data/mp3/Dali Hornak/Radioactive- Gatsby Souns live.mp3.downbeats') self.kdenliveFile.AddBeatsForAllMusicClips() self.kdenliveFile.AddBeatGuides() self.kdenliveFile.SynchronizeToBeats() # Note: SetImagesData() has to be applied after SynchronizeToBeats() which modifies duration of clips self.kdenliveFile.SetImagesData(self.imagesData) self.kdenliveFile.Save(filename) self.kdenliveFile.DumpClipsLength() print('filename:', filename) # Check saved file: #f_saved = KdenliveFile() #f_saved.Load(filename) #print('f_saved:') #f_saved.DumpClipsLength() def slot_on_buttonSaveKdenlive_clicked(self): print('slot_on_buttonSaveKdenlive_clicked()') filename, filt = QFileDialog.getSaveFileName( self, "Save .kdenlive", self.settings.value('filedialog_path', ''), "Kdenlive Project Files (*.kdenlive)") if filename is None or filename == '': return self.settings.setValue('filedialog_path', os.path.dirname(filename)) print('filename:', filename) self.SaveKdenlive(filename) def SaveBboxesJson(self, filename): self.SaveCurrentImageData() json_str = self.toJson() print('json_str:', json_str) with open(filename, "w") as text_file: text_file.write(json_str) def slot_on_buttonSaveBboxesJson_clicked(self): print('slot_on_buttonSaveBboxesJson_clicked()') filename, filt = QFileDialog.getSaveFileName( self, "Save bboxes .json", self.settings.value('filedialog_path', ''), "Bboxes json (*.json)") if filename is None or filename == '': return self.settings.setValue('filedialog_path', os.path.dirname(filename)) print('filename:', filename) self.SaveBboxesJson(filename) def SaveCurrentImageData(self): bboxes = self.ui.image.getBboxes01() for bbox in bboxes: if bbox.isEmpty(): return img_path = self.images[self.imageIdx] if not img_path in self.imagesData: self.imagesData[img_path] = {} self.imagesData[img_path]['bboxes'] = bboxes print('SaveCurrentImageData() img_path:', img_path, 'bboxes:', bboxes) def getBboxesFilename(self): if self.kdenliveFile is None: return 'image_bboxes.json' else: return re.sub(r'\.kdenlive', '_bboxes.json', self.kdenliveFile.inputFilename) def setBboxesRatioMultiplier(self, ratioMultiplier): print('setBboxesRatioMultiplier() len:', len(self.imagesData)) for img_path in self.imagesData: print('setBboxesRatioMultiplier() img_path:', img_path) if 'bboxes' not in self.imagesData[img_path]: continue bboxes = self.imagesData[img_path]['bboxes'] if len(bboxes) != 2: continue bbox_small = bboxes[0] bbox_large = bboxes[1] if bbox_small.width() > bbox_large.width(): # swap bbox_small, bbox_large = bbox_large, bbox_small print('setBboxesRatioMultiplier() bbox_small:', bbox_small) print('setBboxesRatioMultiplier() bbox_large:', bbox_large) diff_l = bbox_small.left() - bbox_large.left() diff_r = bbox_small.right() - bbox_large.right() diff_t = bbox_small.top() - bbox_large.top() diff_b = bbox_small.bottom() - bbox_large.bottom() bbox_small.setLeft(bbox_large.left() + diff_l * ratioMultiplier) bbox_small.setTop(bbox_large.top() + diff_t * ratioMultiplier) bbox_small.setRight(bbox_large.right() + diff_r * ratioMultiplier) bbox_small.setBottom(bbox_large.bottom() + diff_b * ratioMultiplier) print('setBboxesRatioMultiplier() bbox_small adjusted:', bbox_small) print('setBboxesRatioMultiplier() bboxes:', bboxes) # Update view self.SetImageIdx(self.imageIdx) def slot_on_buttonApplyBboxRatioMultiplier_clicked(self): print('slot_on_buttonApplyBboxRatioMultiplier_clicked()') mul = self.ui.spinboxBboxRatioMultiplier.value() print('slot_on_buttonApplyBboxRatioMultiplier_clicked() mul:', mul) self.setBboxesRatioMultiplier(mul)
class MainWindow(QtGui.QMainWindow): def __init__(self, parent=None): """Initializes the Main Window""" self.logger = logging.getLogger('pymetadatamanager.main_window') self.logger.info('Creating the main window.') QtGui.QWidget.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) #Create a dom representing the shows in the database self.shows = dbTV.make_shows_list() #Turn that into a model model = ShowListModel(self.shows) #Set that as the model for the listView self.ui.listView_shows.setModel(model) #Set the initial tabs to be shown self.ui.tabWidget_main.setCurrentIndex(0) self.ui.tabWidget_tv_info.setCurrentIndex(0) #Create a progress dialog for downloading images self.progress = QtGui.QProgressDialog() self.progress.setCancelButtonText(QtCore.QString()) self.progress.setMinimum(0) self.progress.setGeometry(500, 500, 50, 100) self.progress.setMinimumDuration(500) self.progress.setWindowModality(QtCore.Qt.WindowModal) self.progress.setWindowTitle("Information") #Create a dialog window self.input_dialog = QtGui.QInputDialog() self.input_dialog.setGeometry(1000, 1000, 50, 100) self.input_dialog.setWindowTitle("Multiple Matches") #Set up the thread for saving files self.save_files = SaveFiles() # Connect sockets to slots self.ui.listView_shows.clicked.connect(self.list_view_clicked) self.ui.columnView_season_episode.clicked.connect(\ self.column_view_clicked) # self.ui.combo_actors.currentIndexChanged.connect(self.set_actor_thumb) self.ui.lineEdit_series_name.textEdited.connect(\ self.set_series_name_updated) self.ui.plainTextEdit_overview.textChanged.connect(\ self.set_series_overview_updated) self.ui.lineEdit_network.textEdited.connect(\ self.set_series_network_updated) self.ui.lineEdit_airtime.textEdited.connect(\ self.set_series_airtime_updated) self.ui.lineEdit_runtime.textEdited.connect(\ self.set_series_runtime_updated) self.ui.lineEdit_status.textEdited.connect(\ self.set_series_status_updated) self.ui.pushButton_save_series_changes.pressed.connect(\ self.update_series) self.ui.pushButton_revert_series_changes.pressed.connect(\ self.revert_series) self.ui.pushButton_load_local_series_nfo.pressed.connect(\ self.load_series_nfo) self.ui.pushButton_update_series_from_tvdb.pressed.connect(\ self.update_series_from_tvdb) self.ui.line_episode_name.textEdited.connect(\ self.set_episode_name_updated) self.ui.text_episode_plot.textChanged.connect(\ self.set_episode_plot_updated) self.ui.line_airdate.textEdited.connect(\ self.set_episode_airdate_updated) self.ui.line_tvdb_id.textEdited.connect(\ self.set_episode_id_updated) self.ui.line_tvdb_rating.textEdited.connect(\ self.set_episode_tvdb_rating_updated) self.ui.pushButton_save_episode_changes.pressed.connect(\ self.update_episode) self.ui.pushButton_revert_episode_changes.pressed.connect(\ self.revert_episode) self.ui.pushButton_load_local_episode_nfo.pressed.connect(\ self.load_episode_nfo) self.ui.pushButton_update_episode_from_tvdb.pressed.connect(\ self.update_episode_from_tvdb) self.ui.pushButton_new_series_poster.pressed.connect(\ self.select_series_poster) self.ui.pushButton_new_series_wide_banner.pressed.connect(\ self.select_series_wide_banner) self.ui.pushButton_new_season_poster.pressed.connect(\ self.select_season_poster) self.ui.pushButton_new_season_wide.pressed.connect(\ self.select_season_wide_banner) self.ui.pushButton_new_series_fanart.pressed.connect(\ self.select_series_fanart) self.ui.actionScan_Files.triggered.connect(\ self.scan_files) self.ui.actionEdit_Preferences.triggered.connect(\ self.edit_preferences) self.ui.actionClear_Cache.triggered.connect(\ self.clear_cache) self.ui.actionSave_all.triggered.connect(\ self.save_all) self.ui.actionSave_series_artwork.triggered.connect(\ self.save_series_artwork) self.ui.actionSave_series_nfo.triggered.connect(\ self.save_series_nfo) self.ui.actionSave_series_both.triggered.connect(\ self.save_series_both) self.ui.actionSave_episode_artwork.triggered.connect(\ self.save_episode_artwork) self.ui.actionSave_episode_nfo.triggered.connect(\ self.save_episode_nfo) self.ui.actionSave_episode_both.triggered.connect(\ self.save_episode_both) self.save_files.started.connect(self.started_status) self.save_files.finished.connect(self.finished_status) self.save_files.terminated.connect(self.terminated_status) self.connect(self.save_files, \ QtCore.SIGNAL("updateStatus(QString)"), \ self.update_status) self.connect(self.save_files, \ QtCore.SIGNAL("updateProgress(int)"), \ self.update_progress) self.connect(self.save_files, \ QtCore.SIGNAL("setupProgress(int)"), \ self.setup_progress) #Initialize some variables self.series_name_updated = 0 self.series_overview_updated = 0 self.series_network_updated = 0 self.series_airtime_updated = 0 self.series_runtime_updated = 0 self.series_status_updated = 0 self.episode_name_updated = 0 self.episode_plot_updated = 0 self.episode_airdate_updated = 0 self.episode_tvdb_rating_updated = 0 #Create some empty lists for later self.series_banners_url = [] self.series_banners_wide_url = [] self.series_fanart_banners_url = [] self.season_banners_url = [] self.season_banners_wide_url = [] #Initialize the configuration dialog self.config_dialog = ConfigDialog() self.config_dialog.accepted.connect(self.read_config) self.ui.pushButton_save_series_changes.setEnabled(0) self.ui.pushButton_revert_series_changes.setEnabled(0) self.ui.pushButton_save_episode_changes.setEnabled(0) self.ui.pushButton_revert_episode_changes.setEnabled(0) self.ui.pushButton_new_series_poster.setEnabled(0) self.ui.pushButton_new_series_wide_banner.setEnabled(0) self.ui.pushButton_new_season_poster.setEnabled(0) self.ui.pushButton_new_season_wide.setEnabled(0) self.ui.pushButton_load_local_series_nfo.setEnabled(0) self.ui.pushButton_load_local_episode_nfo.setEnabled(0) self.ui.pushButton_update_series_from_tvdb.setEnabled(0) self.ui.pushButton_update_episode_from_tvdb.setEnabled(0) #Put a progress bar on the status bar self.pb = QtGui.QProgressBar() self.statusBar().addPermanentWidget(self.pb) def list_view_clicked(self, index): """Determines what was clicked in the column view tree""" #other functions need to know where we are in the tree self.index = index #Find the series we are working with self.series_name = index.data().toString() self.clear_season_info() self.clear_episode_info() self.set_column_view() self.set_series_info(0) self.ui.pushButton_save_series_changes.setEnabled(0) self.ui.pushButton_revert_series_changes.setEnabled(0) self.ui.pushButton_new_series_poster.setEnabled(1) self.ui.pushButton_new_series_wide_banner.setEnabled(1) self.ui.pushButton_new_season_poster.setEnabled(0) self.ui.pushButton_new_season_wide.setEnabled(0) def column_view_clicked(self, index): """Determines what was clicked in the column view tree""" #other functions need to know where we are in the tree self.index = index #Find the series we are working with this_node_data = index.data().toString() parent = index.parent() parent_data = parent.data().toString() if parent_data == "": #we are at the season level season_number = this_node_data if str(season_number) == 'Specials': self.season_number = 0 else: self.season_number = int(season_number) self.clear_episode_info() self.set_season_info() self.ui.pushButton_new_season_poster.setEnabled(1) self.ui.pushButton_new_season_wide.setEnabled(1) else: #we are at the episode level season_number = parent_data if str(season_number) == 'Specials': self.season_number = 0 else: self.season_number = int(season_number) self.episode_number = \ int(str(this_node_data.split("-")[0]).rstrip()) self.set_season_info() self.set_episode_info() self.ui.pushButton_save_episode_changes.setEnabled(0) self.ui.pushButton_revert_episode_changes.setEnabled(0) def set_series_name_updated(self, text): self.series_name_updated = 1 self.new_series_name = str(text) self.ui.pushButton_save_series_changes.setEnabled(1) self.ui.pushButton_revert_series_changes.setEnabled(1) def set_series_overview_updated(self): self.series_overview_updated = 1 self.new_series_overview = \ unicode(self.ui.plainTextEdit_overview.toPlainText(), "latin-1") self.ui.pushButton_save_series_changes.setEnabled(1) self.ui.pushButton_revert_series_changes.setEnabled(1) def set_series_network_updated(self, text): self.series_network_updated = 1 self.new_series_network = str(text) self.ui.pushButton_save_series_changes.setEnabled(1) self.ui.pushButton_revert_series_changes.setEnabled(1) def set_series_airtime_updated(self, text): self.series_airtime_updated = 1 self.new_series_airtime = str(text) self.ui.pushButton_save_series_changes.setEnabled(1) self.ui.pushButton_revert_series_changes.setEnabled(1) def set_series_runtime_updated(self, text): self.series_runtime_updated = 1 self.new_series_runtime = str(text) self.ui.pushButton_save_series_changes.setEnabled(1) self.ui.pushButton_revert_series_changes.setEnabled(1) def set_series_status_updated(self, text): self.series_status_updated = 1 self.new_series_status = str(text) self.ui.pushButton_save_series_changes.setEnabled(1) self.ui.pushButton_revert_series_changes.setEnabled(1) def update_series(self): series_id = dbTV.get_series_id(self.series_name) if self.series_name_updated == 1: dbTV.update_series_field('name', self.new_series_name, series_id) self.series_name=self.new_series_name if self.series_overview_updated == 1: dbTV.update_series_field('overview', \ self.new_series_overview, series_id) if self.series_network_updated == 1: pass if self.series_airtime_updated == 1: new_series_airs_time = self.new_series_airtime.split(' at ')[1] new_series_airs_day = self.new_series_airtime.split(' at ')[0] dbTV.update_series_field('airs_time', \ new_series_airs_time, series_id) dbTV.update_series_field('airs_day', \ new_series_airs_day, series_id) if self.series_runtime_updated == 1: dbTV.update_series_field('runtime', \ self.new_series_runtime, series_id) if self.series_status_updated == 1: dbTV.update_series_field('status', \ self.new_series_status, series_id) self.ui.pushButton_save_series_changes.setEnabled(0) self.ui.pushButton_revert_series_changes.setEnabled(0) def revert_series(self): self.set_series_info(0) self.ui.pushButton_save_series_changes.setEnabled(0) self.ui.pushButton_revert_series_changes.setEnabled(0) def load_series_nfo(self): series_id = dbTV.get_series_id(self.series_name) series_nfo = dbTV.get_series_nfo_filename(series_id) series_doc = nfo_reader.readNfo(series_nfo) self.set_series_info_from_dom(series_doc, 0) self.ui.pushButton_save_series_changes.setEnabled(1) self.ui.pushButton_revert_series_changes.setEnabled(1) def update_series_from_tvdb(self): series_id = dbTV.get_series_id(self.series_name) series = TVDB.get_series_info(series_id) dom = dom_from_series(series) self.set_series_info_from_dom(dom, 0) self.ui.pushButton_save_series_changes.setEnabled(1) self.ui.pushButton_revert_series_changes.setEnabled(1) def set_episode_name_updated(self, text): self.episode_name_updated = 1 self.new_episode_name = str(text) self.ui.pushButton_save_episode_changes.setEnabled(1) self.ui.pushButton_revert_episode_changes.setEnabled(1) def set_episode_plot_updated(self): self.episode_plot_updated = 1 self.new_episode_plot = \ str(self.ui.text_episode_plot.toPlainText().toUtf8()) self.ui.pushButton_save_episode_changes.setEnabled(1) self.ui.pushButton_revert_episode_changes.setEnabled(1) def set_episode_airdate_updated(self, text): self.episode_airdate_updated = 1 self.new_episode_airdate = str(text) self.ui.pushButton_save_episode_changes.setEnabled(1) self.ui.pushButton_revert_episode_changes.setEnabled(1) def set_episode_id_updated(self, text): ### FIXME ### self.episode_id_updated = 1 self.new_episode_id = str(text) self.ui.pushButton_save_episode_changes.setEnabled(1) self.ui.pushButton_revert_episode_changes.setEnabled(1) def set_episode_tvdb_rating_updated(self, text): self.episode_tvdb_rating_updated = 1 self.new_episode_tvdb_rating = str(text) self.ui.pushButton_save_episode_changes.setEnabled(1) self.ui.pushButton_revert_episode_changes.setEnabled(1) def update_episode(self): episode_id = dbTV.get_episode_id(self.series_name, \ self.season_number, \ self.episode_number) if self.episode_name_updated == 1: dbTV.update_episode_field('name', \ self.new_episode_name, episode_id) if self.episode_plot_updated == 1: dbTV.update_episode_field('overview', \ self.new_episode_plot, episode_id) if self.episode_airdate_updated == 1: dbTV.update_episode_field('first_aired', \ self.new_episode_airdate, episode_id) if self.episode_tvdb_rating_updated == 1: dbTV.update_episode_field('rating', \ self.new_episode_tvdb_rating, episode_id) self.ui.pushButton_save_episode_changes.setEnabled(0) self.ui.pushButton_revert_episode_changes.setEnabled(0) def revert_episode(self): self.set_episode_info() self.ui.pushButton_save_episode_changes.setEnabled(0) self.ui.pushButton_revert_episode_changes.setEnabled(0) def load_episode_nfo(self): episode_id = dbTV.get_episode_id(self.series_name, \ self.season_number, \ self.episode_number) episode_nfo = dbTV.get_episode_nfo_filename(episode_id) dom = nfo_reader.readNfo(episode_nfo) if dom is not None: self.set_episode_info_from_dom(dom) self.ui.pushButton_save_episode_changes.setEnabled(1) self.ui.pushButton_revert_episode_changes.setEnabled(1) def update_episode_from_tvdb(self): episode_id = dbTV.get_episode_id(self.series_name, \ self.season_number, \ self.episode_number) episode = TVDB.get_episode_info(episode_id) dom = dom_from_episode(episode) self.set_episode_info_from_dom(dom) self.ui.pushButton_save_episode_changes.setEnabled(1) self.ui.pushButton_revert_episode_changes.setEnabled(1) def set_column_view(self): dom = dbTV.make_seasons_episodes_dom(self.series_name) model = SeasonEpisodeModel(dom) self.ui.columnView_season_episode.setModel(model) self.ui.columnView_season_episode.setColumnWidths([300,550,50]) def set_season_info(self): """Sets the info for the current season in the display window""" series_id = dbTV.get_series_id(self.series_name) season_list = dbTV.make_episodes_list(series_id, self.season_number) model = SeasonListModel(season_list) self.ui.listView_season_episode_full.setModel(model) self.selected_season_poster = dbTV.get_selected_banner_url(\ series_id, 'season', self.season_number) if not self.selected_season_poster == "": filename = TVDB.retrieve_banner(self.selected_season_poster) season_poster_pixmap = QtGui.QPixmap(filename).scaled(300, 450,\ QtCore.Qt.KeepAspectRatio) self.ui.label_season_poster.setPixmap(season_poster_pixmap) else: self.ui.label_season_poster.clear() self.ui.label_season_poster.setText("No season poster selected") self.selected_season_banner_wide = dbTV.get_selected_banner_url(\ series_id, 'seasonwide', self.season_number) if not self.selected_season_banner_wide == "": filename = TVDB.retrieve_banner(self.selected_season_banner_wide) season_banner_wide_pixmap = \ QtGui.QPixmap(filename).scaledToHeight(140) self.ui.label_season_banner_wide.setPixmap(\ season_banner_wide_pixmap) else: self.ui.label_season_banner_wide.clear() self.ui.label_season_banner_wide.setText(\ "No season wide banner selected") def set_series_info(self, tab_index): #Get the series id from the database series_id = dbTV.get_series_id(self.series_name) #Create a QDomDocument containing the series details series_doc = dbTV.make_series_dom(series_id) self.set_series_info_from_dom(series_doc, tab_index) self.ui.pushButton_load_local_series_nfo.setEnabled(1) self.ui.pushButton_update_series_from_tvdb.setEnabled(1) def set_series_info_from_dom(self, series_doc, tab_index): """Sets the info for the current series in the display window""" series_root = series_doc.firstChildElement('tvshow') #Extract the details and fill in the display elem_series_name = series_root.firstChildElement('title') series_name = elem_series_name.text() self.ui.lineEdit_series_name.setText(series_name) elem_series_plot = series_root.firstChildElement('plot') series_plot = QtCore.QString(elem_series_plot.text()) self.ui.plainTextEdit_overview.setPlainText(series_plot) series_actors = [] self.ui.combo_actors.clear() elem_series_actor = series_root.firstChildElement('actor') while not elem_series_actor.isNull(): elem_series_actor_name = \ elem_series_actor.firstChildElement('name') series_actor_name = elem_series_actor_name.text() if not series_actor_name in series_actors: series_actors.append(series_actor_name) elem_series_actor = elem_series_actor.nextSiblingElement('actor') series_actors.sort() for series_actor in series_actors: self.ui.combo_actors.addItem(series_actor) elem_series_network = series_root.firstChildElement('network') series_network = elem_series_network.text() self.ui.lineEdit_network.setText(series_network) elem_series_airs_day = series_root.firstChildElement('airsday') series_airs_day = elem_series_airs_day.text() elem_series_airs_time = series_root.firstChildElement('airstime') series_airs_time = elem_series_airs_time.text() if not series_airs_day == '': series_airtime = series_airs_day + " at " + series_airs_time else: series_airtime = '' self.ui.lineEdit_airtime.setText(series_airtime) elem_series_runtime = series_root.firstChildElement('runtime') series_runtime = elem_series_runtime.text() self.ui.lineEdit_runtime.setText(series_runtime) elem_series_status = series_root.firstChildElement('status') series_status = elem_series_status.text() self.ui.lineEdit_status.setText(series_status) series_id = dbTV.get_series_id(self.series_name) self.ui.lineEdit_tvdb_series_id.setText(str(series_id)) self.selected_series_poster = \ dbTV.get_selected_banner_url(series_id, 'poster', '') if not self.selected_series_poster == "": filename = TVDB.retrieve_banner(self.selected_series_poster) series_poster_pixmap = QtGui.QPixmap(filename).scaledToHeight(450) self.ui.label_series_banner.setPixmap(series_poster_pixmap) else: self.ui.label_series_banner.clear() self.ui.label_series_banner.setText("No series poster selected") self.selected_series_wide_banner = \ dbTV.get_selected_banner_url(series_id, 'series', '') if not self.selected_series_wide_banner == "": filename = TVDB.retrieve_banner(self.selected_series_wide_banner) series_wide_pixmap = QtGui.QPixmap(filename).scaledToHeight(140) self.ui.label_banner_wide.setPixmap(series_wide_pixmap) else: self.ui.label_banner_wide.clear() self.ui.label_banner_wide.setText("No series wide banner selected") self.selected_series_fanart = \ dbTV.get_selected_banner_url(series_id, 'fanart', '') if not self.selected_series_fanart == "": filename = TVDB.retrieve_banner(self.selected_series_fanart) series_fanart_pixmap = QtGui.QPixmap(filename).scaledToHeight(480) self.ui.label_series_fanart.setPixmap(series_fanart_pixmap) else: self.ui.label_series_fanart.clear() self.ui.label_series_fanart.setText("No fanart selected") self.ui.tabWidget_tv_info.setCurrentIndex(tab_index) def set_episode_info(self): """Sets the info for the show in the display window""" #Get the episode_id from the database episode_id = dbTV.get_episode_id(self.series_name, \ self.season_number, \ self.episode_number) #Create a QDomDocument containing the episode details dom = dbTV.make_episode_dom(episode_id) self.set_episode_info_from_dom(dom) self.ui.pushButton_load_local_episode_nfo.setEnabled(1) self.ui.pushButton_update_episode_from_tvdb.setEnabled(1) def set_episode_info_from_dom(self, dom): """Sets the info for the show in the display window""" episode_root = dom.firstChildElement('episodedetails') #Extract the details and fill in the display elem_episode_title = episode_root.firstChildElement('title') episode_title = elem_episode_title.text() self.ui.line_episode_name.setText(episode_title) elem_episode_plot = episode_root.firstChildElement('plot') episode_plot = QtCore.QString(elem_episode_plot.text()) self.ui.text_episode_plot.setPlainText(episode_plot) elem_episode_thumb = episode_root.firstChildElement('thumb') if not elem_episode_thumb.isNull(): episode_thumb = elem_episode_thumb.text() else: episode_thumb = "none" #Set the preview image image_file = TVDB.retrieve_banner(str(episode_thumb)) if image_file is not None: image = QtGui.QPixmap(image_file) self.ui.label_episode_thumb.setPixmap(image) elem_episode_airdate = episode_root.firstChildElement('aired') episode_airdate = elem_episode_airdate.text() self.ui.line_airdate.setText(episode_airdate) elem_episode_id = episode_root.firstChildElement('id') episode_id = elem_episode_id.text() self.ui.line_tvdb_id.setText(episode_id) elem_episode_rating = episode_root.firstChildElement('rating') episode_rating = elem_episode_rating.text() self.ui.line_tvdb_rating.setText(episode_rating) elem_episode_directors = episode_root.firstChildElement('director') episode_directors = unicode(elem_episode_directors.text(), \ "latin-1").split('|') self.ui.combo_directors.clear() for director in episode_directors: self.ui.combo_directors.addItem(director) elem_episode_writers = episode_root.firstChildElement('credits') episode_writers = unicode(elem_episode_writers.text(), \ "latin-1").split('|') self.ui.combo_writers.clear() for writer in episode_writers: self.ui.combo_writers.addItem(writer) episode_actors = [] elem_episode_actor = episode_root.firstChildElement('actor') self.ui.combo_guests.clear() while not elem_episode_actor.isNull(): elem_episode_actor_name = \ elem_episode_actor.firstChildElement('name') episode_actor_name = elem_episode_actor_name.text() episode_actors.append(episode_actor_name) elem_episode_actor = elem_episode_actor.nextSiblingElement('actor') episode_actors = set(episode_actors) for episode_actor in episode_actors: if self.ui.combo_actors.findText(episode_actor) < 0: self.ui.combo_guests.addItem(episode_actor) self.ui.tabWidget_tv_info.setCurrentIndex(3) def clear_episode_info(self): """Clears the episode info from the display window""" self.ui.line_episode_name.clear() self.ui.text_episode_plot.clear() self.ui.line_airdate.clear() self.ui.line_tvdb_id.clear() self.ui.line_tvdb_rating.clear() self.ui.combo_directors.clear() self.ui.combo_writers.clear() self.ui.combo_guests.clear() self.ui.label_episode_thumb.clear() def clear_season_info(self): model = EmptyListModel() self.ui.listView_season_episode_full.setModel(model) self.ui.label_season_poster.clear() self.ui.label_season_banner_wide.clear() def select_series_poster(self): self.logger.info("Selecting new series poster") banner_dialog = BannerDialog(self.series_name, "series_posters", 0) accepted = banner_dialog.exec_() if accepted: self.set_series_info(0) self.ui.pushButton_new_series_poster.setDown(False) def select_series_wide_banner(self): banner_dialog = BannerDialog(self.series_name, "series_wide", 0) accepted = banner_dialog.exec_() if accepted: self.set_series_info(0) self.ui.pushButton_new_series_wide_banner.setDown(False) def select_series_fanart(self): banner_dialog = BannerDialog(self.series_name, "series_fanart", 0) accepted = banner_dialog.exec_() if accepted: self.set_series_info(1) self.ui.pushButton_new_series_fanart.setDown(False) def select_season_poster(self): banner_dialog = BannerDialog(self.series_name, \ "season_posters", \ self.season_number) accepted = banner_dialog.exec_() if accepted: self.set_season_info() self.ui.pushButton_new_season_poster.setDown(False) def select_season_wide_banner(self): banner_dialog = BannerDialog(self.series_name, \ "season_wide", \ self.season_number) accepted = banner_dialog.exec_() if accepted: self.set_season_info() self.ui.pushButton_new_season_wide.setDown(False) def scan_files(self): for video_dir in config.tv_dirs: self.progress.setLabelText("Scanning Files from %s into DB..." \ % (video_dir)) self.logger.info("Scanning files") scanner = Scanner(video_dir) scanner.set_series_list() self.progress.setMaximum(len(scanner.series_list)) self.progress.setValue(0) self.logger.debug(scanner.series_list) for series_name in scanner.series_list: self.progress.setValue(scanner.series_list.index(series_name)) self.progress.show() match_list = scanner.get_series_id_list(series_name) if len(match_list) == 0: self.logger.info("No matches found on thetvdb.com for '%s'." % (series_name)) ### FIXME ### series_id = raw_input("Please input the ID for the correct series:") elif len(match_list) == 1: self.logger.info("Found match for '%s'." % (series_name)) series_id = match_list[0][0] else: match = False list = '' for i in range(0,len(match_list)): if match_list[i][1] == series_name: self.logger.info("Found match for '%s'." % (series_name)) series_id = match_list[i][0] match = True else: list += "[%d] %s (%s)\n " % (i, match_list[i][1], \ match_list[i][0]) if not match: selection = self.input_dialog.getInt(self, '', \ "Select best match:\n %s" % (list), \ 0, 0, len(match_list) - 1)[0] try: series_id = match_list[selection][0] except IndexError: self.logger.info("That is not an option.") if config.prefer_local: self.logger.info("Adding info from local nfo files") scanner.add_series_to_db_by_nfo(series_name) else: self.logger.info("Adding info from thetvdb.com") scanner.add_series_to_db_by_id(series_id) self.logger.info("Adding files to db.") scanner.add_files_to_db(series_id, series_name) dbTV.remove_shows_with_no_files() scanner.__del__() self.progress.setValue(len(scanner.series_list)) self.logger.info("Finished Scanning") #Create a dom representing the shows in the database shows = dbTV.make_shows_list() #Turn that into a model model = ShowListModel(shows) #Set that as the model for the listView self.ui.listView_shows.setModel(model) def edit_preferences(self): self.config_dialog.show() def read_config(self): config.read_config_file() def clear_cache(self): top = os.path.join(config.config_dir, "cache") for root, dirs, files in os.walk(top, topdown=False): for name in files: os.remove(os.path.join(root, name)) for name in dirs: os.rmdir(os.path.join(root, name)) def save_all(self): self.save_files.save_all(self.shows) def save_series_artwork(self): series_id = dbTV.get_series_id(self.series_name) self.save_files.save_series_artwork(series_id) def save_series_nfo(self): series_id = dbTV.get_series_id(self.series_name) self.save_files.save_series_nfos(series_id) def save_series_both(self): series_id = dbTV.get_series_id(self.series_name) self.save_files.save_series_both(series_id) def save_episode_artwork(self): episode_id = dbTV.get_episode_id(self.series_name, \ self.season_number, \ self.episode_number) dbTV.write_episode_thumb(episode_id) def save_episode_nfo(self): episode_id = dbTV.get_episode_id(self.series_name, \ self.season_number, \ self.episode_number) dbTV.write_episode_nfo(episode_id) def save_episode_both(self): episode_id = dbTV.get_episode_id(self.series_name, \ self.season_number, \ self.episode_number) dbTV.write_episode_nfo(episode_id) dbTV.write_episode_thumb(episode_id) def started_status(self): self.statusBar().showMessage("Saving files.") self.pb.show() def finished_status(self): self.pb.hide() self.statusBar().showMessage("File saving finished.") def terminated_status(self): self.pb.hide() self.statusBar().showMessage("File saving terminated.") def update_status(self, show): self.statusBar().showMessage("Saving info and artwork for %s" % (show,)) def update_progress(self, progress): self.pb.setValue(progress) def setup_progress(self, max): self.pb.setRange(0, max)
class DelphosWindow(QMainWindow): """Manages the main Delphos window interface (Ui_MainWindow) """ def __init__(self, gui_manager): QMainWindow.__init__(self, None) #Initialize myself as a widget self.ui = Ui_MainWindow() self.ui.setupUi(self) #Create the components of the window self.gui_manager = gui_manager self.dock_full_screen = False self.min_doc_dock_width = 200 #Maximize the display to full size #self.showMaximized() #Add status bar at bottom of window self.statusbar = QtGui.QStatusBar(self) self.statusbar.setObjectName("statusbar") self.setStatusBar(self.statusbar) #Add progress bar to status bar self.pb = QProgressBar(self.statusBar()) self.pb.setMinimum(0) self.pb.setMaximum(0) self.statusbar.addPermanentWidget(self.pb) self.pb.hide() QObject.connect(self.ui.menu_dock_visible, SIGNAL("triggered()"), self.toggle_documentation_window) QObject.connect(self.ui.dock_doc, SIGNAL("visibilityChanged(bool)"), self.toggle_dock_visible_menu) QObject.connect(self.ui.menu_dock_floating, SIGNAL("triggered()"), self.toggle_dock_float) QObject.connect(self.ui.dock_doc, SIGNAL("topLevelChanged(bool)"), self.toggle_dock_floating_menu) QObject.connect(self.ui.menu_open_full_doc, SIGNAL("triggered()"), self.load_full_doc) #self.ui.dock_doc.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) def load_full_doc(self, project_type=None, language=None): """Load full documentation in external application """ #Find which documentation subdir to look in if not project_type: project_type = self.gui_manager.project_manager.get_current_project_type() if not language: language = self.gui_manager.config_manager.get_language() if project_type == 'fisheries': if language == 'english': doc_subdir = 'fisheries'+os.sep+'english'+os.sep else: doc_subdir = 'fisheries'+os.sep+'spanish'+os.sep elif project_type == 'sites': if language == 'english': doc_subdir = 'sites'+os.sep+'english'+os.sep else: doc_subdir = 'sites'+os.sep+'spanish'+os.sep elif project_type == 'communities': if language == 'english': doc_subdir = 'communities'+os.sep+'english'+os.sep else: doc_subdir = 'communities'+os.sep+'spanish'+os.sep doc_path = os.getcwd()+os.sep+"documentation"+os.sep+doc_subdir+'documentation.html' doc_url = "file:"+urllib.pathname2url(unicode(doc_path)) #file:///U|/dev/delphos/src/documentation/fisheries/english/letter_to_experts.doc self.gui_manager.desktop_services.openUrl(QUrl(doc_url)) def load_toc(self, project_type=None, language=None): """Loads the table of contents within the dock widget """ #Find which toc data to load if not project_type: project_type = self.gui_manager.project_manager.get_current_project_type() if not language: language = self.gui_manager.config_manager.get_language() toc = "" if project_type == 'fisheries': if language == 'english': toc = fisheries_english_toc else: toc = fisheries_spanish_toc elif project_type == 'communities': if language == 'english': toc = communities_english_toc else: toc = communities_spanish_toc elif project_type == 'sites': if language == 'english': toc = sites_english_toc else: toc = sites_spanish_toc self.process_toc(deepcopy(toc)) def process_toc(self, toc): self.ui.toc_tree.clear() #Make a copy as original will be destroyed for heading in toc: root_item = self.ui.toc_tree.invisibleRootItem() self.process_heading(heading, root_item) def process_heading(self, heading, parent): #print type(heading) if type(heading) == str: tree_item = QTreeWidgetItem(parent) tree_item.setText(0, heading) if type(heading) == dict: (heading_name, subheadings) = heading.popitem() tree_item = QTreeWidgetItem(parent) tree_item.setText(0, heading_name) for subheading in subheadings: self.process_heading(subheading, tree_item) def process_toc_click(self, item, column): """Builds URL from toc heading name and reloads doc editor """ heading = item.text(column) #Morph heading name into anchor label name label = heading.replace(' ', '_') label = heading.replace('/', '_') label = heading.replace('.', '') label = label.toLower() #Build URL project_type = self.gui_manager.project_manager.get_current_project_type() language = self.gui_manager.config_manager.get_language() #Load URL and go to anchor within it self.ui.doc_browser.load_anchor(label, project_type, language) def process_help_click(self, en_name, sp_name): """Uses the help type given to load a section of the documentation """ en_label = en_name.replace('help_', '') sp_label = sp_name.replace('help_', '') #Build URL project_type = self.gui_manager.project_manager.get_current_project_type() language = self.gui_manager.config_manager.get_language() #Load URL and go to anchor within it if language == 'english': self.ui.doc_browser.load_anchor(en_label, project_type, language) elif language == 'spanish': self.ui.doc_browser.load_anchor(sp_label, project_type, language) #Show the documentation if its hidden if not self.ui.dock_doc.isVisible(): self.ui.menu_dock_visible.trigger() def dock_full_screen(self): return self.dock_full_screen def toggle_dock(self): if self.dock_full_screen: self.ui.dock_doc.setMinimumSize(self.min_doc_dock_width, 0) self.ui.dock_doc.resize(self.min_doc_dock_width, self.ui.dock_doc.height()) doc_dock_size = self.ui.dock_doc.sizeHint() self.ui.toc_box.resize(100, self.ui.toc_box.height()) self.ui.toc_tree.resize(100, self.ui.toc_box.height()) self.ui.doc_box.resize(100, self.ui.doc_box.height()) self.ui.doc_browser.resize(100, self.ui.toc_box.height()) self.dock_full_screen = False else: self.ui.dock_doc.setMinimumSize(self.width(), 0) self.dock_full_screen = True def toggle_documentation_window(self): if self.ui.dock_doc.isVisible(): self.ui.dock_doc.hide() else: self.ui.dock_doc.show() def toggle_dock_visible_menu(self): if self.ui.dock_doc.isVisible(): self.ui.menu_dock_visible.setChecked(True) else: self.ui.menu_dock_visible.setChecked(False) def toggle_dock_float(self): if self.ui.dock_doc.isFloating(): self.ui.dock_doc.setFloating(False) else: self.ui.dock_doc.setFloating(True) def toggle_dock_floating_menu(self, isFloating): if isFloating: self.ui.menu_dock_floating.setChecked(False) else: self.ui.menu_dock_floating.setChecked(True)
class LpdFemGuiMainWindow(QtGui.QMainWindow): messageSignal = QtCore.pyqtSignal(object) runStateSignal = QtCore.pyqtSignal() run_status_signal = QtCore.pyqtSignal(object) powerStatusSignal = QtCore.pyqtSignal(object) def __init__(self, app_main): # Create main window UI QtGui.QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.app_main = app_main self.asyncCmd = None self.asyncCmdRunning = False # Create helper objects to manage main window tabs self.daqTab = LpdFemGuiMainDaqTab(app_main, self) self.pwrTab = LpdFemGuiMainPowerTab(app_main, self) self.configTab = LpdFemGuiMainConfigTab(app_main, self) self.evrTab = LpdFemGuiMainEvrTab(app_main, self) self.testTab = LpdFemGuiMainTestTab(app_main, self) self.ui.operatorEdit.text() if (self.app_main.asic_testing_enabled): pass else: # ASIC testing disabled, remove test tab testIdx = self.ui.verticalTabWidget.indexOf(self.ui.testTab) self.ui.verticalTabWidget.removeTab(testIdx) # Initialise default fields based on app_main object self.ui.connectAddr.setText(self.app_main.getCachedParam('femAddr')) self.ui.connectPort.setText( str(self.app_main.getCachedParam('femPort'))) # Create a status bar with a progress bar self.createStatusBar("Not connected") # Connect signals and slots QtCore.QObject.connect(self.ui.connectButton, QtCore.SIGNAL("clicked()"), self.deviceConnectToggle) self.connect(self.ui.actionQuit, QtCore.SIGNAL('triggered()'), self.quitApplication) # Connect msgRecv function to message signal to allow other non-GUI threads to print messages self.messageSignal.connect(self.msgRecv) # Connect runStateUpdate function to signal to allow other non-GUI threads to push state updates self.runStateSignal.connect(self.runStateUpdate) # Connect run status update function to signal to data recevier to push updates self.run_status_signal.connect(self.daqTab.runStatusUpdate) # Connect power status update function to signal self.powerStatusSignal.connect(self.pwrTab.powerStatusUpdateDisplay) def msgRecv(self, message): self.msgPrint(message) def runStateUpdate(self): self.daqTab.runStateUpdate(self.app_main.device_state) self.updateEnabledWidgets() def executeAsyncCmd(self, message, cmdHandler, completionHandler): if self.asyncCmdRunning == True: ret = QtGui.QMessageBox.critical( self, "System busy", "Please wait for the current operation to complete") else: self.asyncCmd = AsyncExecutionThread(cmdHandler, self.completeAsyncCmd) self.asyncCompletion = completionHandler self.msgPrint(message) self.statusBar().showMessage(self.tr(message)) self.progressBar.show() self.progressBar.setRange(0, 0) self.asyncCmdRunning = True self.asyncCmd.start() def completeAsyncCmd(self): self.asyncCompletion() self.progressBar.hide() self.statusBar().showMessage("Done") self.asyncCmdRunning = False def updateEnabledWidgets(self): if self.app_main.device_state == LpdFemState.DeviceDisconnected: self.ui.configGroupBox.setEnabled(False) self.ui.operateGroupBox.setEnabled(False) elif self.app_main.device_state == LpdFemState.DeviceIdle: self.ui.configGroupBox.setEnabled(True) self.ui.operateGroupBox.setEnabled(True) self.ui.configBtn.setEnabled(True) self.ui.runBtn.setEnabled(False) self.ui.stopBtn.setEnabled(False) elif self.app_main.device_state == LpdFemState.DeviceConfiguring: self.ui.configGroupBox.setEnabled(True) self.ui.operateGroupBox.setEnabled(True) self.ui.configBtn.setEnabled(False) self.ui.runBtn.setEnabled(False) self.ui.stopBtn.setEnabled(False) elif self.app_main.device_state == LpdFemState.DeviceReady: self.ui.configGroupBox.setEnabled(True) self.ui.operateGroupBox.setEnabled(True) self.ui.configBtn.setEnabled(True) self.ui.runBtn.setEnabled(True) self.ui.stopBtn.setEnabled(False) elif self.app_main.device_state == LpdFemState.DeviceRunning: self.ui.configGroupBox.setEnabled(True) self.ui.operateGroupBox.setEnabled(True) self.ui.configBtn.setEnabled(False) self.ui.runBtn.setEnabled(False) self.ui.stopBtn.setEnabled(True) self.daqTab.updateEnabledWidgets() self.pwrTab.updateEnabledWidgets() self.evrTab.updateEnabledWidgets() def createStatusBar(self, defaultMessage): sb = QtGui.QStatusBar() sb.setFixedHeight(18) self.setStatusBar(sb) self.statusBar().showMessage(self.tr(defaultMessage)) self.progressBar = QtGui.QProgressBar(self.statusBar()) self.statusBar().addPermanentWidget(self.progressBar) self.progressBar.hide() def deviceConnectToggle(self): if self.app_main.device_state == LpdFemState.DeviceDisconnected: # Extract address and port from GUI fields and validate deviceAddress = str(self.ui.connectAddr.text()) devicePort = str(self.ui.connectPort.text()) if not validIpAddress(deviceAddress) or not validPort(devicePort): ret = QtGui.QMessageBox.critical( self, "Connection error", "Please enter a valid address and port") return self.app_main.setCachedParam('femAddress', deviceAddress) self.app_main.setCachedParam('femPort', devicePort) self.ui.connectButton.setEnabled(False) cmdMsg = "Connecting to LPD device at address %s port %s ..." % ( deviceAddress, devicePort) self.executeAsyncCmd( cmdMsg, partial(self.app_main.deviceConnect, deviceAddress, devicePort), self.connectDone) else: self.app_main.deviceDisconnect() self.msgPrint("Device disconnected") self.statusBar().showMessage(self.tr("Not connected")) self.ui.connectStatus.setText("NO") self.ui.connectButton.setText("Connect") self.ui.lvStatus.setText("Unknown") self.ui.hvStatus.setText("Unknown") self.updateEnabledWidgets() def connectDone(self): self.progressBar.hide() self.ui.connectButton.setEnabled(True) # Toggle button text according to state if self.app_main.device_state != LpdFemState.DeviceDisconnected: self.msgPrint("Connected to device OK") self.statusBar().showMessage(self.tr("Connected to device")) self.ui.connectButton.setText("Disconnect") self.ui.connectStatus.setText("YES") self.app_main.femConfigGet() self.configTab.showConfig() self.app_main.pwr_card.statusUpdate() self.pwrTab.lvEnableToggleDone() self.pwrTab.hvEnableToggleDone() self.ui.configGroupBox.setEnabled(True) self.ui.operateGroupBox.setEnabled(True) else: self.statusBar().showMessage(self.tr("Not connected")) self.msgPrint(self.app_main.device_err_string) self.ui.connectButton.setText("Connect") self.ui.connectStatus.setText("NO") self.ui.lvStatus.setText("Unknown") self.ui.hvStatus.setText("Unknown") self.ui.configGroupBox.setEnabled(False) self.ui.operateGroupBox.setEnabled(False) self.updateEnabledWidgets() def msgPrint(self, msg): self.ui.messageBox.appendPlainText( "%s %s" % (time.strftime("%H:%M:%S"), str(msg))) self.ui.messageBox.verticalScrollBar().setValue( self.ui.messageBox.verticalScrollBar().maximum()) self.ui.messageBox.repaint() self.app_main.app.processEvents() def quitApplication(self): if self.app_main.device_state != LpdFemState.DeviceDisconnected: self.app_main.deviceDisconnect() self.app_main.cleanup() self.app_main.app.quit() def closeEvent(self, theCloseEvent): if self.app_main.device_state != LpdFemState.DeviceDisconnected: self.app_main.deviceDisconnect() self.app_main.cleanup() theCloseEvent.accept()
class MainWindow(QMainWindow): settings_button_clicked = pyqtSignal() status_table_clicked = pyqtSignal(str) export_accounting = pyqtSignal(str, str, str) def __init__(self): # Init the base class QMainWindow.__init__(self) self._settings = load_settings(Config.DEFAULT_SETTINGS) # Init the processed .ui file self._ui = Ui_MainWindow() self._ui.setupUi(self) self.setWindowTitle("TradeSkillMaster Application r{}".format(Config.CURRENT_VERSION)) # connect signals / slots self._ui.addon_status_table.doubleClicked.connect(self._addon_status_table_clicked) self._ui.backup_status_table.doubleClicked.connect(self._backup_status_table_clicked) self._ui.settings_button.clicked.connect(self.settings_button_clicked.emit) self._ui.accounts_dropdown.activated['QString'].connect(self.accounts_dropdown_changed) self._ui.realm_dropdown.activated['QString'].connect(self.realm_dropdown_changed) self._ui.export_button.clicked.connect(self.export_button_clicked) self._ui.help_button.setProperty("url", "http://tradeskillmaster.com/site/getting-help") self._ui.help_button.clicked.connect(self._link_button_clicked) self._ui.premium_button.setProperty("url", "http://tradeskillmaster.com/premium") self._ui.premium_button.clicked.connect(self._link_button_clicked) self._ui.logo_button.setProperty("url", "http://tradeskillmaster.com") self._ui.logo_button.clicked.connect(self._link_button_clicked) self._ui.twitter_button.setProperty("url", "http://twitter.com/TSMAddon") self._ui.twitter_button.clicked.connect(self._link_button_clicked) # Apply the stylesheet file = QFile(":/resources/main_window.css") file.open(QIODevice.ReadOnly) data = str(file.readAll(), encoding="ascii") self.setStyleSheet(data) # set properties which are necessary for tweaking the style self._ui.help_button.setProperty("id", "premiumButton") self._ui.premium_button.setProperty("id", "premiumButton") self._ui.header_text.setProperty("id", "headerText") # stylesheet tweaks for things which don't work when put into the .css for some unknown reason self._ui.accounting_tab.setStyleSheet("QCheckBox:disabled { color : #666; } QCheckBox { color : white; }"); self._sync_status_table_model = TableModel(self, ['Region/Realm', 'AuctionDB', 'Great Deals', 'Last Updated']) self._ui.sync_status_table.setModel(self._sync_status_table_model) self._addon_status_table_model = TableModel(self, ['Name', 'Version', 'Status']) self._ui.addon_status_table.setModel(self._addon_status_table_model) self._backup_status_table_model = TableModel(self, ['System ID', 'Account', 'Timestamp', 'Sync Status']) self._ui.backup_status_table.setModel(self._backup_status_table_model) self._accounting_info = {} self._accounting_current_account = "" self._accounting_current_realm = "" if Config.IS_WINDOWS: # create the system tray icon / menu self._tray_icon = QSystemTrayIcon(QIcon(":/resources/logo.png"), self) self._tray_icon.setToolTip("TradeSkillMaster Application r{}".format(Config.CURRENT_VERSION)) self._tray_icon.activated.connect(self._icon_activated) tray_icon_menu = QMenu(self) restore_action = QAction("Restore", tray_icon_menu) restore_action.triggered.connect(self._restore_from_tray) tray_icon_menu.addAction(restore_action) tray_icon_menu.addSeparator() quit_action = QAction("Quit", tray_icon_menu) quit_action.triggered.connect(self.close) tray_icon_menu.addAction(quit_action) self._tray_icon.setContextMenu(tray_icon_menu) self._tray_icon.hide() def __del__(self): if Config.IS_WINDOWS: self._tray_icon.hide() def changeEvent(self, event): if not Config.IS_WINDOWS: return if event.type() == QEvent.WindowStateChange: if self.isMinimized() and self._settings.minimize_to_tray: logging.getLogger().info("Minimizing to the system tray") self._tray_icon.show() self.hide() event.ignore() def closeEvent(self, event): if self._settings.confirm_exit: msg_box = QMessageBox() msg_box.setWindowIcon(QIcon(":/resources/logo.png")) msg_box.setWindowModality(Qt.ApplicationModal) msg_box.setIcon(QMessageBox.Information) msg_box.setText("Are you sure you want to exit?") msg_box.setStandardButtons(QMessageBox.Cancel | QMessageBox.Yes) if msg_box.exec_() != QMessageBox.Yes: event.ignore() return event.accept() def set_visible(self, visible): self.setVisible(visible) if self._settings.start_minimized and Config.IS_WINDOWS: self.showMinimized() self.setWindowState(Qt.WindowMinimized) if self._settings.minimize_to_tray: logging.getLogger().info("Minimizing to the system tray") self._tray_icon.show() self.hide() else: logging.getLogger().info("Minimizing") def _restore_from_tray(self): if not Config.IS_WINDOWS: return logging.getLogger().info("Restoring from the system tray") self.show() self.setWindowState(Qt.WindowActive) self._tray_icon.hide() def _icon_activated(self, reason): if not Config.IS_WINDOWS: return if reason == QSystemTrayIcon.Trigger or reason == QSystemTrayIcon.DoubleClick: self._restore_from_tray() def _link_button_clicked(self): QDesktopServices.openUrl(QUrl(self.sender().property("url"))) def _addon_status_table_clicked(self, index): key = self._addon_status_table_model.get_click_key(index) if key: self.status_table_clicked.emit(key) def _backup_status_table_clicked(self, index): key = self._backup_status_table_model.get_click_key(index) if key: self.status_table_clicked.emit(key) def set_sync_status_data(self, data): self._sync_status_table_model.set_info(data) self._ui.sync_status_table.resizeColumnsToContents() self._ui.sync_status_table.sortByColumn(0, Qt.AscendingOrder) def set_addon_status_data(self, data): self._addon_status_table_model.set_info(data) self._ui.addon_status_table.resizeColumnsToContents() self._ui.addon_status_table.sortByColumn(0, Qt.AscendingOrder) def set_backup_status_data(self, data): system_text = "The system ID is unique to the computer you are running the desktop app from. " \ "<a href=\"http://tradeskillmaster.com/user/backups\" style=\"color: #EC7800\">Premium users " \ "can sync backups</a> to the cloud and across multiple computers. Otherwise, only backups from " \ "the local system (<font style=\"color: cyan\">{}</font>) will be listed below.<br><br>To " \ "restore a backup, double-click on the row in the table below.".format(Config.SYSTEM_ID) self._ui.backup_system_text.setText(system_text) self._backup_status_table_model.set_info(data) self._ui.backup_status_table.resizeColumnsToContents() self._ui.backup_status_table.sortByColumn(2, Qt.DescendingOrder) def show_notification(self, message, critical): if not Config.IS_WINDOWS: return icon = QSystemTrayIcon.Critical if critical else QSystemTrayIcon.NoIcon if self._tray_icon.isVisible(): self._tray_icon.showMessage("TradeSkillMaster Desktop Application", message, icon) else: # The tray icon needs to be visible to show the message, but we can immediately hide it afterwards # This is the behavior on Windows 10 at least...need to confirm on other operating systems self._tray_icon.show() self._tray_icon.showMessage("TradeSkillMaster Desktop Application", message, icon) self._tray_icon.hide() def _update_dropdown(self, dropdown, items, selected_item): items = [""] + items selected_index = 0 dropdown.clear() for index, item in enumerate(items): if item == selected_item: selected_index = index dropdown.addItem(item) dropdown.setCurrentIndex(selected_index) def _update_accounting_tab(self): # update the accounts dropdown accounts = [x for x in self._accounting_info if self._accounting_info[x]] self._update_dropdown(self._ui.accounts_dropdown, accounts, self._accounting_current_account) # update the realm dropdown self._ui.realm_dropdown.setEnabled(self._accounting_current_account != "") if self._accounting_current_account != "": self._update_dropdown(self._ui.realm_dropdown, self._accounting_info[self._accounting_current_account], self._accounting_current_realm) # update the export button self._ui.export_button.setEnabled(self._accounting_current_realm != "") def set_accounting_accounts(self, info): self._accounting_info = info self._update_accounting_tab() def accounts_dropdown_changed(self, account): self._accounting_current_account = account self._accounting_current_realm = "" self._update_accounting_tab() def realm_dropdown_changed(self, realm): assert(self._accounting_current_account) self._accounting_current_realm = realm self._update_accounting_tab() def export_button_clicked(self): self._ui.export_button.setEnabled(False) self._ui.export_button.setText("Exporting...") def do_export(): if self._ui.sales_checkbox.checkState(): self.export_accounting.emit(self._accounting_current_account, self._accounting_current_realm, "sales") if self._ui.purchases_checkbox.checkState(): self.export_accounting.emit(self._accounting_current_account, self._accounting_current_realm, "purchases") if self._ui.income_checkbox.checkState(): self.export_accounting.emit(self._accounting_current_account, self._accounting_current_realm, "income") if self._ui.expenses_checkbox.checkState(): self.export_accounting.emit(self._accounting_current_account, self._accounting_current_realm, "expenses") if self._ui.expired_checkbox.checkState(): self.export_accounting.emit(self._accounting_current_account, self._accounting_current_realm, "expired") if self._ui.canceled_checkbox.checkState(): self.export_accounting.emit(self._accounting_current_account, self._accounting_current_realm, "canceled") self._ui.export_button.setEnabled(True) self._ui.export_button.setText("Export to CSV") # show a popup saying we've exported everything msg_box = QMessageBox() msg_box.setWindowIcon(QIcon(":/resources/logo.png")) msg_box.setWindowModality(Qt.ApplicationModal) msg_box.setIcon(QMessageBox.Information) msg_box.setText("The TSM_Accounting data has been successfully exported to your desktop.") msg_box.setStandardButtons(QMessageBox.Ok) msg_box.exec_() # slight delay so the button gets disabled QTimer.singleShot(1, do_export)
class MainWindow(QMainWindow): ROLE_MANGA_OBJ = Qt.UserRole ROLE_MANGA_URL = Qt.UserRole + 1 ROLE_MANGA_TITLE = Qt.UserRole + 2 def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) # NOTE: методом подбора получились эти значения self.ui.splitter_main.setSizes([80, 500]) self.setWindowTitle('Client http://readmanga.me') self.ui.line_edit_search.textEdited.connect(self.on_manga_search) self.ui.list_widget_search_result.itemDoubleClicked.connect( self.on_search_item_double_clicked) self.ui.push_button_next_page.clicked.connect(self.next_page) self.ui.push_button_prev_page.clicked.connect(self.prev_page) self.ui.combo_box_manga_chapters.currentIndexChanged.connect( self.on_manga_chapters_current_index_changed) self.ui.combo_box_pages.currentIndexChanged.connect( self.set_chapter_page) self.url_images_chapter = list() # Кэш страниц манги, чтобы не качать их каждый раз при смене страницы на просмотренную в главе self.cache_page_chapter_by_image = dict() self.last_item_chapter = None self.last_page_number = -1 self.image_viewer = ImageViewer() self.ui.scroll_area_image_page.setWidget(self.image_viewer) self.ui.scroll_area_image_page.setWidgetResizable(True) self.ui.scroll_area_image_page.installEventFilter(self) self.download_progress_bar = QProgressBar() self.download_progress_bar.hide() self.ui.statusbar.addPermanentWidget(self.download_progress_bar) self._update_states() def _clear_states(self): self.last_page_number = -1 self.last_item_chapter = None self.url_images_chapter.clear() self.cache_page_chapter_by_image.clear() self.ui.combo_box_manga_chapters.clear() self.ui.combo_box_pages.clear() self.image_viewer.clear() self._update_states() def _update_states(self): pages = self.ui.combo_box_pages.count() current_page = self.ui.combo_box_pages.currentIndex() self.ui.push_button_next_page.setEnabled(current_page < pages - 1) self.ui.push_button_prev_page.setEnabled(current_page > 0) def on_manga_search(self, query_text): self.ui.list_widget_search_result.clear() manga_list = search_manga_on_readmanga(query_text) for manga_obj in manga_list: data = manga_obj['data'] # Думаю, у любой манги найдется автор, иначе игнорируем if 'authors' not in data: continue text = manga_obj['value'] another_names = data['names'] if another_names: text += " | " + ', '.join(another_names) authors = data['authors'] if authors: text += " (" + authors + ")" url = data['link'] item = QListWidgetItem(text) item.setData(self.ROLE_MANGA_OBJ, manga_obj) item.setData(self.ROLE_MANGA_URL, url) item.setData(self.ROLE_MANGA_TITLE, text) self.ui.list_widget_search_result.addItem(item) def next_page(self): current_index = self.ui.combo_box_pages.currentIndex() if current_index < self.ui.combo_box_pages.maxCount(): self.ui.combo_box_pages.setCurrentIndex(current_index + 1) self._update_states() def prev_page(self): current_index = self.ui.combo_box_pages.currentIndex() if current_index > 0: self.ui.combo_box_pages.setCurrentIndex(current_index - 1) self._update_states() def on_manga_chapters_current_index_changed(self, index): if not self.ui.combo_box_manga_chapters.count(): return url = self.ui.combo_box_manga_chapters.itemData(index) self.fill_chapter_viewer(url) def on_search_item_double_clicked(self, item): # Чтобы нельзя было выбрать повторно мангу if item == self.last_item_chapter: return self.last_item_chapter = item self._clear_states() url = item.data(self.ROLE_MANGA_URL) title = item.data(self.ROLE_MANGA_TITLE) content_as_bytes = self._download_by_url(url) from bs4 import BeautifulSoup root = BeautifulSoup(content_as_bytes, 'lxml') description = root.select_one('.manga-description') if not description: QMessageBox.information(self, "Внимание", "Похоже у манги нет описания") return description = description.text.strip() # Удаление множества подряд идущих пробелов import re description = re.sub(r'\s{2,}', ' ', description) self.ui.label_manga_name.setText(title) self.ui.text_edit_description.setText(description) url_first_chapter = root.select_one('.read-first > a[href]') if not url_first_chapter: QMessageBox.information(self, "Внимание", "Похоже у манги нет глав") return url_first_chapter = url_first_chapter['href'] from urllib.parse import urljoin url_first_chapter = urljoin(url, url_first_chapter) self.fill_chapter_viewer(url_first_chapter) def fill_chapter_viewer(self, url_chapter): self._clear_states() # Загрузка первой главы для получения списка глав и показа первой страницы главы content_as_bytes = self._download_by_url(url_chapter) from bs4 import BeautifulSoup root = BeautifulSoup(content_as_bytes, 'lxml') from urllib.parse import urljoin chapter_list = [ (option.text.strip(), urljoin(url_chapter, option['value'])) for option in root.select('#chapterSelectorSelect > option') ] # Чтобы напрасно не вызывался сигнал currentIndexChanged при настройке комбобокса self.ui.combo_box_manga_chapters.blockSignals(True) # Заполнение списка глав for title_chapter, _url_chapter in chapter_list: self.ui.combo_box_manga_chapters.addItem(title_chapter, _url_chapter) # Выбор текущей главы в комбобоксе index = -1 for i in range(self.ui.combo_box_manga_chapters.count()): item_url = self.ui.combo_box_manga_chapters.itemData(i) if item_url.startswith(url_chapter): index = i break self.ui.combo_box_manga_chapters.setCurrentIndex(index) self.ui.combo_box_manga_chapters.blockSignals(False) # Для получения ссылок на картинки глав: html = str(root) self.url_images_chapter = get_url_images_from_chapter(html) # Заполнение списка с страницами главы self.ui.combo_box_pages.blockSignals(True) for i in range(len(self.url_images_chapter)): self.ui.combo_box_pages.addItem(str(i + 1)) self.ui.combo_box_pages.blockSignals(False) current_page = self.ui.combo_box_pages.currentIndex() self.set_chapter_page(current_page) self._update_states() def _download_by_url(self, url): import requests rs = requests.get(url, stream=True) self.download_progress_bar.show() if 'Content-Length' in rs.headers: img_size = int(rs.headers['Content-Length']) self.download_progress_bar.setMaximum(img_size) else: # Прогресс бар становится бесконечным self.download_progress_bar.setMaximum(0) size = 0 byte_array_img = bytearray() for buf in rs.iter_content(1024): if buf: byte_array_img += buf size += len(buf) self.download_progress_bar.setValue(size) self.download_progress_bar.hide() return bytes(byte_array_img) def set_chapter_page(self, page_number): if page_number == -1 or page_number == self.last_page_number: return self.last_page_number = page_number if page_number not in self.cache_page_chapter_by_image: url_first_page = self.url_images_chapter[page_number] content_as_bytes = self._download_by_url(url_first_page) img = QImage.fromData(content_as_bytes) self.cache_page_chapter_by_image[page_number] = img else: img = self.cache_page_chapter_by_image[page_number] self.image_viewer.set_image(img) # Возврат ползунка на положенное место self.ui.scroll_area_image_page.verticalScrollBar().setValue(0) self._update_states() def eventFilter(self, obj, event): # Для изменения ширины картинки if obj == self.ui.scroll_area_image_page and event.type( ) == QEvent.Resize: # Чтобы был небольшой отступ по краям margin = 40 self.image_viewer.setFixedWidth( self.ui.scroll_area_image_page.width() - margin) return super().eventFilter(obj, event)
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.mdiArea.setOption(QMdiArea.DontMaximizeSubWindowOnActivation, True) @pyqtSlot(int) def show_child_window(self, widget_number): if widget_number == 0: self.deliver_widget = DeliverWindow() self.deliver_widget = self.ui.mdiArea.addSubWindow(self.deliver_widget) self.deliver_widget.showMaximized() elif widget_number == 1: self.sale_widget = SaleWindow() self.ui.mdiArea.addSubWindow(self.sale_widget) self.sale_widget.showMaximized() elif widget_number == 2: self.drugs_widget = AllDrugsWindow() self.ui.mdiArea.addSubWindow(self.drugs_widget) self.drugs_widget.showMaximized() elif widget_number == 3: self.delivers_widget = AllDeliversWindow(self.ui.mdiArea) self.ui.mdiArea.addSubWindow(self.delivers_widget) self.delivers_widget.showMaximized() elif widget_number == 4: self.sales_widget = AllSalesWindow(self.ui.mdiArea) self.ui.mdiArea.addSubWindow(self.sales_widget) self.sales_widget.showMaximized() elif widget_number == 5: self.patients_widget = AllPatientsWindow() self.ui.mdiArea.addSubWindow(self.patients_widget) self.patients_widget.showMaximized() elif widget_number == 6: self.distributors_widget = AllDistributorsWindow() self.ui.mdiArea.addSubWindow(self.distributors_widget) self.distributors_widget.showMaximized() elif widget_number == 7: self.medorg_widget = AllMedorgWindow() self.ui.mdiArea.addSubWindow(self.medorg_widget) self.medorg_widget.showMaximized() elif widget_number == 8: self.doctors_widget = AllDoctorsWindow() self.doctors_widget = self.ui.mdiArea.addSubWindow(self.doctors_widget) self.doctors_widget.showMaximized() elif widget_number == 9: self.manufacters_widget = AllManufactersWindow() self.manufacters_widget = self.ui.mdiArea.addSubWindow(self.manufacters_widget) self.manufacters_widget.showMaximized() # QObject.connect(self.manufacters_widget, SIGNAL("closed()"), self.ui.mdiArea.removeSubWindow) elif widget_number == 10: self.ills_widget = AllIllsWindow() self.ills_widget = self.ui.mdiArea.addSubWindow(self.ills_widget) self.ills_widget.showMaximized() elif widget_number == 11: self.recipes_widget = AllRecipesWindow() self.recipes_widget = self.ui.mdiArea.addSubWindow(self.recipes_widget) self.recipes_widget.showMaximized()