def show_settings_dialog(self): settings_dlg = SettingsDialog() settings_dlg.exec_() # apply settings self.remove_menu_buttons() self.build_menu_tree() self.append_menu_buttons()
def create_views(self): """ Create all the views used by the application """ self.settings_dialog = SettingsDialog(controller=self) self.feedlist_view = FeedListView(controller=self) self.itemlist_view = ItemListView(controller=self) self.itemview_view = ItemViewView(controller=self)
def __init__(self, application): self.app = application #signal that experiment is running self.experiment_mode = False self.app.print_comment("Starting GUI interface:") self.app.print_comment("please wait while the application loads...") #build the GUI interface as a seperate window win = tk.Tk() Pmw.initialise(win) #initialize Python MegaWidgets win.withdraw() win.wm_title(WINDOW_TITLE) win.focus_set() #put focus on this new window self.win = win #handle the user hitting the 'X' button self.win.protocol("WM_DELETE_WINDOW", self._close) #FIXME bind some debugging keystrokes to the window #self.win.bind('<Control-f>', lambda e: self.app.force_experiment()) #build the left panel left_panel = tk.Frame(win) #capture controls tk.Label(left_panel, text="Capture Controls:", font = "Helvetica 14 bold").pack(side='top',fill='x', anchor="nw") self.change_settings_button = tk.Button(left_panel,text='Change Settings',command = self.change_settings) self.change_settings_button.pack(side='top',fill='x', anchor="sw") self.run_continually_button = tk.Button(left_panel,text='Run Continually',command = self.run_continually) self.run_continually_button.pack(side='top',fill='x', anchor="nw") self.stop_button = tk.Button(left_panel,text='Stop',command = self.stop, state='disabled') self.stop_button.pack(side='top',fill='x', anchor="nw") self.run_once_button = tk.Button(left_panel,text='Run Once',command = self.run_once) self.run_once_button.pack(side='top',fill='x', anchor="nw") self.export_data_button = tk.Button(left_panel,text='Export Data',command = self.export_data, state='disabled') self.export_data_button.pack(side='bottom',anchor="sw") left_panel.pack(fill='y',expand='no',side='left', padx = 10) #create an tk embedded figure for temperature display mid_panel = tk.Frame(win) self.temperature_plot_template = TemperaturePlot() self.temperature_figure_widget = EmbeddedFigure(mid_panel, figsize=TEMPERATURE_FIGSIZE) self.temperature_figure_widget.pack(side='left',fill='both', expand='yes') mid_panel.pack(fill='both', expand='yes',side='left') #build the right panel right_panel = tk.Frame(win) self.text_display = TextDisplayBox(right_panel,text_height=15, buffer_size = TEXT_BUFFER_SIZE) self.text_display.pack(side='left',fill='both',expand='yes') right_panel.pack(fill='both', expand='yes',side='right') #build the confirmation dialog self.settings_dialog = SettingsDialog(self.win) self.settings_dialog.withdraw() self._load_settings() #run modes self._is_running = False
def action_settings(self): sett_dialog = SettingsDialog() sett_dialog.show() sett_dialog.exec_() self.reinit_tree()
def create_settings_dialog(self): self.settings_dialog = SettingsDialog(controller=self)
class Controller(QObject): def __init__(self): """ Create the Controller, inialize all things (settings, signals...) """ super(Controller, self).__init__(parent=None) self.is_running = False # the current Google Reader account self.account = Account() # views self.views = [] self.current_view = None # connect signals QObject.connect(self, SIGNALS["settings_updated"], self.settings_updated) QObject.connect(self.account.operations_manager, SIGNALS["operation_started"], self.update_titles, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["operation_ended"], self.update_titles, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["authenticate_error"], self.cannot_authenticate, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["get_account_feeds_started"], self.feeds_fetching_started, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["get_account_feeds_done"], self.feeds_fetched, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["get_account_feeds_error"], self.feeds_not_fetched, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["get_feed_content_started"], self.feed_content_fetching_started, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["get_more_feed_content_started"], self.feed_content_fetching_started, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["get_feed_content_done"], self.feed_content_fetched, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["get_more_feed_content_done"], self.feed_content_fetched, Qt.QueuedConnection) def create_views(self): """ Create all the views used by the application """ self.create_feedlist_view() self.create_itemlist_view() self.create_itemview_view() def create_feedlist_view(self): self.feedlist_view = FeedListView(controller=self) def create_itemlist_view(self): self.itemlist_view = ItemListView(controller=self) def create_itemview_view(self): self.itemview_view = ItemViewView(controller=self) def create_dialogs(self): """ Create all the dialogs used by the application """ self.create_settings_dialog() self.create_filter_feeds_dialog() def create_settings_dialog(self): self.settings_dialog = SettingsDialog(controller=self) def create_filter_feeds_dialog(self): self.filter_feeds_dialog = FilterFeedsDialog(controller=self) def run(self): """ Initialize graphic things and show the application by displaying the feed list window """ if self.is_running: return self.is_running = True self.create_dialogs() self.create_views() self.current_view = self.feedlist_view self.current_view.show(app_just_launched=True) def settings_updated(self, auth_changed=False): """ When settings are updated, call same method for all views, and if the auth_changed parameter is true, ask for a resync """ for view in self.views: try: view.settings_updated() except: pass if auth_changed: if not self.account.is_authenticated: self.account.authenticate() elif not self.account.operations_manager.count_running(): self.account.fetch_feeds(fetch_unread_content=True) def add_view(self, view): """ Add a view to the list of manages views """ self.views.append(view) def get_title_operations_part(self): """ Get the part of the title which will handle the running operations counter """ nb = self.account.operations_manager.count_running() if nb: return "%d operations" % nb else: return "" def update_titles(self): """ Update titles for all views """ for view in self.views: try: view.update_title() except: pass def set_current_view(self, view): """ Set the specified view as the current one """ if view != self.current_view: self.current_view = view self.current_view.show() def is_current_view(self, view): return view == self.current_view def switch_view(self, name): """ Swith to the a view specified by its name """ if name == 'feedlist': view = self.feedlist_view elif name == 'itemlist': view = self.itemlist_view elif name == 'itemview': view = self.itemview_view else: return self.set_current_view(view) def display_message(self, message, level="information"): """ Display a message for the current view """ if self.current_view: self.current_view.display_message(message, level) def display_feed(self, feed): """ Display a feed by displaying the itemlist view. If the specified feed cannot be selected, return to the previous view """ self.switch_view('itemlist') if not self.itemlist_view.set_current_feed(feed): self.switch_view('feedlist') def trigger_settings(self): """ Will display the settings dialog box """ self.settings_dialog.open() def start_loading(self): """ Activate the loading indicator in the current view """ if self.current_view: self.current_view.start_loading() def stop_loading(self): """ Stop the loading indicator in the current view """ if self.current_view: self.current_view.stop_loading() def cannot_authenticate(self, operation_id): """ Called when the authentication cannot be done """ try: account = Operation.get_by_id(operation_id).params['object'] except: pass else: if account == self.account: for view in self.views: try: view.cannot_authenticate() except: pass def feeds_fetching_started(self, operation_id): """ Actions when feeds will be fetched """ try: account = Operation.get_by_id(operation_id).params['object'] except: pass else: if account == self.account: for view in self.views: try: view.feeds_fetching_started() except: pass def feeds_fetched(self, operation_id): """ Actions when feeds are just fetched """ try: account = Operation.get_by_id(operation_id).params['object'] except: pass else: if account == self.account: for view in self.views: try: view.feeds_fetched() except: pass def feeds_not_fetched(self, operation_id): """ Actions when feeds couldn't be fetched """ try: account = Operation.get_by_id(operation_id).params['object'] except: pass else: if account == self.account: for view in self.views: try: view.feeds_not_fetched() except: pass def feed_content_fetching_started(self, operation_id): """ Action when some of a feed's content will be fetched """ try: feed = Operation.get_by_id(operation_id).params['object'] except: pass else: if feed.account == self.account: for view in self.views: try: view.feed_content_fetching_started(feed) except: pass def feed_content_fetched(self, operation_id): """ Action when some of a feed's content was just fetched """ try: feed = Operation.get_by_id(operation_id).params['object'] except: pass else: if feed.account == self.account: for view in self.views: try: view.feed_content_fetched(feed) except: pass def display_item(self, item): """ Display an item by displaying the itemview view. If the specified item cannot be selected, return to the previous view """ self.switch_view('itemview') if not self.itemview_view.set_current_item(item): self.switch_view('itemlist') def get_next_item(self): """ Returnthe next available item """ return self.itemlist_view.get_next_item() def get_previous_item(self): """ Returnthe previous available item """ return self.itemlist_view.get_previous_item() def display_next_item(self): """ Display the next available item """ self.itemlist_view.activate_next_item() def display_previous_item(self): """ Display the previous available item """ self.itemlist_view.activate_previous_item() def item_read(self, item): """ Called when an item was marked as read/unread """ for view in self.views: try: view.item_read(item) except: pass def item_shared(self, item): """ Called when an item was shared/unshared """ for view in self.views: try: view.item_shared(item) except: pass def item_starred(self, item): """ Called when an item was starred/unstarred """ for view in self.views: try: view.item_starred(item) except: pass def feed_read(self, feed): """ Called when an feed was marked as read """ for view in self.views: try: view.feed_read(feed) except: pass def trigger_filter_feeds(self): """ Will display the filter feeds dialog """ self.filter_feeds_dialog.open() def trigger_help(self): self.display_message(self.compose_help_message()) def compose_help_message(self): help = [ self.help_keys(), self.feedlist_view.help_keys(), self.itemlist_view.help_keys(), self.itemview_view.help_keys(), ] text = "" for cat in help: text += "%s:\n" % cat['title'] for key in cat['keys']: text += " %s\t= %s\n" % (key[0], key[1]) text += "\n" return text def help_keys(self): return { 'title': 'General', 'keys': [ ('shift-SPACE', 'Feeds filter dialog'), ('H', 'This help'), ('I', 'Toggle informations banner visibility'), ] }
class MainWindow(QMainWindow, Ui_MainWindow): docLabelTemplate = "Documents for {}:" docLabelTemplateEmpty = "Documents:" def __init__(self, app, list_manager, parent=None): super(MainWindow, self).__init__(parent) self.app = app # this must be defined before the setupUi is called # cause widgets in the interface need to reference it # in there __init__ methods self.listeners = [] self.list_manager = list_manager self.list_is_dirty = False self.setupUi(self) self.setWindowTitle("Assembly Document Tracker") QCoreApplication.setOrganizationName('Charles Cognato') QCoreApplication.setApplicationName('Assembly Doc Tracker') self.settings = QSettings() open_on_add = self.settings.value('open_on_add', 'false') if open_on_add == "true": self.actionOpen_on_Add.setChecked(True) else: self.actionOpen_on_Add.setChecked(False) # force at least one product to be on the list before documents can be added if self.listWidget.count() <= 0: self.listWidget_2.setEnabled(False) self.listWidget.setContextMenuPolicy(Qt.NoContextMenu) self.productContextActionRename = QAction(QIcon(":/filesaveas.png"), "rename", self) self.listWidget.addAction(self.productContextActionRename) self.connect(self.productContextActionRename, SIGNAL("triggered()"), self.on_assembly_context_action_rename_triggered) self.productContextActionDelete = QAction(QIcon(":/delete.png"), "delete", self) self.productContextActionDelete.setStatusTip(assembly_context_delete_status_tip) self.listWidget.addAction(self.productContextActionDelete) self.connect(self.productContextActionDelete, SIGNAL("triggered()"), self.on_assembly_context_action_delete_triggered) self.connect(self.listWidget, SIGNAL("itemClicked(QListWidgetItem*)"), self.on_list_widget_item_clicked) self.connect(self.listWidget, SIGNAL("currentItemChanged (QListWidgetItem*,QListWidgetItem*)"), self._update_gui) self.connect(self.listWidget, SIGNAL("pdfMoved"), self._transfer_docs) self.listWidget_2.setContextMenuPolicy(Qt.NoContextMenu) self.listWidget_2.addAction(self.action_Open) self.connect(self.action_Open, SIGNAL("triggered()"), self.open_pdf) self.documentContextActionDelete = QAction(QIcon(":/delete.png"), "delete", self) self.listWidget_2.addAction(self.documentContextActionDelete) self.connect(self.documentContextActionDelete, SIGNAL("triggered()"), self.on_document_context_action_delete_activated) self.connect(self.listWidget_2, SIGNAL("itemDoubleClicked (QListWidgetItem*)"), self.on_pdf_double_clicked) self.connect(self.listWidget_2, SIGNAL("pdfAdded"), self.pdf_added) self.connect(self.listWidget_2, SIGNAL("itemSelectionChanged()"), self.on_docs_selection_changed) self.connect(self.listWidget_2, SIGNAL("removeDocs"), self.on_list_widget2_removeDocs) self.connect(self.action_New, SIGNAL("triggered()"), self.on_pbAddAssembly_clicked) self.connect(self.action_Save, SIGNAL("triggered()"), self._save_assembly_data) self.connect(self.actionPreferences, SIGNAL("triggered()"), self.on_preferences_clicked) self.input_dialog = InputDialog(parent=self) self.confirm_dialog = ConfirmDialog(self) self.settings_dialog = SettingsDialog(self) self.usage_dialog = UsageDialog(self) self.show() self.__is_first_run() QTimer.singleShot(0, self._load_assembly_data) # Fixed: bug-0004 def closeEvent(self, QCloseEvent): if self.list_is_dirty: print('saving data...') self._save_assembly_data() self.settings.setValue('open_on_add', self.actionOpen_on_Add.isChecked()) QCloseEvent.accept() def __is_first_run(self): first_run = self.settings.value('first_run', None) if first_run is None: print('first run of the program...') QMessageBox.warning(self, "PDF Viewer", "You need to select a PDF viewer before opening documents.") result = self.settings_dialog.exec_() if result == QDialog.Accepted: self.settings.setValue('first_run', 'complete') @pyqtSignature("") def on_actionUsage_triggered(self): self.usage_dialog.exec_() def on_list_widget2_removeDocs(self, docs): doc_list = self._current_doc_list() """:type doc_list : dict """ for doc in docs: del doc_list[doc] self._update_gui() # Fixed: bug-0001 def on_pbAddAssembly_clicked(self): assembly_text = self._get_input("Enter an assembly part number:") if assembly_text in self.list_manager: QMessageBox.warning(self, "- Warning -", "That assembly is already on the list.") elif assembly_text: self.list_manager[assembly_text] = {} self._add_new_assembly(assembly_text, self.listWidget) # self._update_gui() QTimer.singleShot(0, self._update_gui) self.list_is_dirty = True def on_document_context_action_delete_activated(self): if len(self.listWidget_2.selectedItems()): doc_list = self._current_doc_list() for item in self.listWidget_2.selectedItems(): row = self.listWidget_2.row(item) self.listWidget_2.takeItem(row) del doc_list[item.text()] self._update_gui() self.list_is_dirty = True def on_docs_selection_changed(self): if len(self.listWidget_2.selectedItems()): self.listWidget_2.setContextMenuPolicy(Qt.ActionsContextMenu) else: self.listWidget_2.setContextMenuPolicy(Qt.NoContextMenu) # Fixed: bug-0002 def on_list_widget_item_clicked(self, list_item): self._update_gui() def on_assembly_context_action_delete_triggered(self): if not self._ok_to_continue(): return if self.listWidget.count(): self.remove_assembly() self.list_is_dirty = True # fixed : bug-0005 def on_assembly_context_action_rename_triggered(self): new_assembly = self._get_input("Enter an assembly part number:") if new_assembly: current_assembly, doc_list = self._current_assembly_info() del self.list_manager[current_assembly.text()] self.listWidget.takeItem(self.listWidget.currentRow()) self.list_manager[new_assembly] = doc_list list_item = QListWidgetItem(QIcon(':/assembly.png'), new_assembly, self.listWidget) self.listWidget.setCurrentItem(list_item) self._update_gui() self.list_is_dirty = True def on_pdf_double_clicked(self, *args, **kwargs): print("openng '{}'".format(args[0].get_full_name())) viewer = self.settings.value('viewer/viewer') if viewer: util.open_pdf((args[0].get_full_name(),), viewer) else: QMessageBox.warning(self, '- Warning -', 'PDF Viewer not defined.') def on_preferences_clicked(self): self.settings_dialog.exec_() def open_pdf(self): selected_pdf_list_items = self.listWidget_2.selectedItems() if len(selected_pdf_list_items): pdf_files = [pdf.get_full_name() for pdf in selected_pdf_list_items] util.open_pdf(tuple(pdf_files), self.settings.value('viewer/viewer')) def pdf_added(self, pdf): assembly, doc_list = self._current_assembly_info() short_name = pdf.split('/')[-1] if short_name in doc_list.keys(): return doc_list[short_name] = {'path': pdf, 'short_name': short_name} self._update_gui() # should we open it automatically as well? if self.actionOpen_on_Add.isChecked(): util.open_pdf((pdf,), self.settings.value('viewer/viewer')) self.list_is_dirty = True def remove_assembly(self): assembly, doc_list = self._current_assembly_info() if assembly is not None: # get rid of the assembly del self.list_manager[assembly.text()] self.listWidget.takeItem(self.listWidget.currentRow()) self.listWidget_2.clear() self._update_gui() self.list_is_dirty = True def _add_new_assembly(self, assembly_text, list_widget, make_current=True): list_widget_item = QListWidgetItem(QIcon(':/assembly.png'), assembly_text, list_widget) # list_widget.addItem(list_widget_item) if make_current: list_widget.setCurrentItem(list_widget_item) def _current_assembly(self): return self.listWidget.currentItem() def _current_assembly_info(self): assembly = self._current_assembly() doc_list = self._current_doc_list() return assembly, doc_list def _current_doc_list(self): assembly = self._current_assembly() if assembly is not None: doc_list = self.list_manager[assembly.text()] return doc_list else: return None def _get_input(self, prompt): self.input_dialog.setPrompt(prompt) self.input_dialog.lineEdit.setFocus() self.input_dialog.lineEdit.selectAll() result = self.input_dialog.exec_() if result == QDialog.Accepted: return self.input_dialog.getText() else: return "" def _load_assembly_data(self): path = os.path.join(data_base_path, assembly_data_file) if os.path.isfile(path): with open(path, 'rb') as in_f: self.list_manager = pickle.load(in_f) self._populate_assembly_list(self.list_manager) def _ok_to_continue(self): result = self.confirm_dialog.exec_() if result == QDialog.Rejected: return False else: return True def _populate_assembly_list(self, assemblies): if len(assemblies): for assembly in assemblies.keys(): self._add_new_assembly(assembly, self.listWidget, False) assembly = self.listWidget.item(0) self.listWidget.setCurrentItem(assembly) def _populate_document_list(self, doc_obj_list, assembly): self.listWidget_2.clear() for key in doc_obj_list.keys(): list_item = DocListWidgetItem(QIcon(":/pdf.png"), doc_obj_list[key]['short_name'], doc_obj_list[key]['path'], self.listWidget_2) def _save_assembly_data(self): path = os.path.join(data_base_path, assembly_data_file) with open(path, 'wb') as out_f: pickle.dump(self.list_manager, out_f) def _transfer_docs(self, target_assembly, data): """ transfer documents from one assembly to another :param target_assembly: the assembly to transfer the documents to :param data: a QByteArray containing the documents in the format "file_name:path" :return: returns nothing """ print("moving docs to '{}'...".format(target_assembly)) doc_list = self.list_manager[target_assembly] stream = QDataStream(data, QIODevice.ReadOnly) doc = stream.readQString() while doc != "": file_name, path = doc.split(":") doc_list[file_name] = {'path': path, 'short_name': file_name} doc = stream.readQString() self.list_is_dirty = True def _update_gui(self): if self.listWidget.count(): self.listWidget.setContextMenuPolicy(Qt.ActionsContextMenu) if len(self.listWidget_2.selectedItems()): self.listWidget_2.setContextMenuPolicy(Qt.ActionsContextMenu) self.listWidget_2.setEnabled(True) assembly, doc_list = self._current_assembly_info() if assembly is not None: self._populate_document_list(doc_list, assembly.text()) self.label_2.setText(MainWindow.docLabelTemplate.format(assembly.text())) self.statusbar.showMessage("Doc Count = {}".format(self.listWidget_2.count())) else: self.listWidget.setContextMenuPolicy(Qt.NoContextMenu) self.listWidget_2.setContextMenuPolicy(Qt.NoContextMenu) self.listWidget_2.setEnabled(False) self.label_2.setText(MainWindow.docLabelTemplateEmpty) self.statusbar.clearMessage()
class HashmalMain(QMainWindow): # Signals # Emitted when the list of user's layouts changes. layoutsChanged = QtCore.pyqtSignal() def __init__(self, app): super(HashmalMain, self).__init__() self.app = app self.app.setStyleSheet(hashmal_style()) self.changes_saved = True # {Qt.DockWidgetArea: [dock0, dock1, ...], ...} self.dock_orders = defaultdict(list) self.setCorner(QtCore.Qt.BottomRightCorner, QtCore.Qt.RightDockWidgetArea) self.config = Config() self.init_logger() self.config.optionChanged.connect(self.on_option_changed) QtCore.QCoreApplication.setOrganizationName('mazaclub') QtCore.QCoreApplication.setApplicationName('hashmal') self.qt_settings = QtCore.QSettings() active_params = self.config.get_option('chainparams', 'Bitcoin') # True if chainparams needs to be set after plugins load. needs_params_change = False # An exception is thrown if the last-active chainparams preset # only exists due to a plugin that defines it. try: chainparams.set_to_preset(active_params) except KeyError: chainparams.set_to_preset('Bitcoin') needs_params_change = True self.download_controller = DownloadController() self.setDockNestingEnabled(True) # Plugin Handler loads plugins and handles their dock widgets. self.plugin_handler = PluginHandler(self) self.plugin_handler.load_plugins() self.plugin_handler.do_default_layout() # Attempt to load chainparams preset again if necessary. if needs_params_change: try: chainparams.set_to_preset(active_params) except KeyError: self.log_message('Core', 'Chainparams preset "%s" does not exist. Setting chainparams to Bitcoin.', logging.ERROR) self.config.set_option('chainparams', 'Bitcoin') # Filename of script being edited. self.filename = '' # The last text that we saved. self.last_saved = '' self.create_script_editor() # Set up script editor font. script_font = self.qt_settings.value('editor/font', defaultValue=QtCore.QVariant('default')).toString() if script_font == 'default': font = monospace_font else: font = QFont() font.fromString(script_font) self.script_editor.setFont(font) self.settings_dialog = SettingsDialog(self) self.create_menubar() self.create_toolbar() self.create_actions() self.new_script() self.statusBar().setVisible(True) self.statusBar().messageChanged.connect(self.change_status_bar) self.restoreState(self.qt_settings.value('toolLayout/default/state').toByteArray()) self.restoreGeometry(self.qt_settings.value('toolLayout/default/geometry').toByteArray()) self.script_editor.setFocus() if self.qt_settings.value('quickTipsOnStart', defaultValue=QtCore.QVariant(True)).toBool(): QtCore.QTimer.singleShot(500, self.do_quick_tips) def sizeHint(self): return QtCore.QSize(800, 500) def init_logger(self): """Initialize logger.""" handler = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s', '%Y-%m-%d %H:%M:%S') handler.setFormatter(formatter) logger = logging.getLogger() logger.addHandler(handler) self.change_log_level(self.config.get_option('log_level', 'INFO')) def change_log_level(self, level_str): level_str = level_str.upper() if level_str not in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']: level_str = 'INFO' level = getattr(logging, level_str) logging.getLogger().setLevel(level) def create_menubar(self): menubar = QMenuBar() file_menu = menubar.addMenu('&File') file_menu.addAction('&New', self.new_script).setShortcut(QKeySequence.New) file_menu.addAction('Save As...', self.save_script_as).setShortcut(QKeySequence.SaveAs) file_menu.addAction('&Open', self.open_script).setShortcut(QKeySequence.Open) file_menu.addAction('&Save', self.save_script).setShortcut(QKeySequence.Save) file_menu.addAction('&Quit', self.close) # Script actions script_menu = menubar.addMenu('&Script') script_menu.addAction('&Evaluate', self.plugin_handler.evaluate_current_script) script_menu.addAction('&Copy Hex', self.script_editor.copy_hex) # Settings and tool toggling tools_menu = menubar.addMenu('&Tools') tools_menu.addAction('&Settings', self.show_settings_dialog) tools_menu.addAction('&Plugin Manager', lambda: PluginManager(self).exec_()) tools_menu.addSeparator() self.plugin_handler.create_menu(tools_menu) help_menu = menubar.addMenu('&Help') help_menu.addAction('&About', self.do_about) help_menu.addAction('&Quick Tips', self.do_quick_tips) self.setMenuBar(menubar) def show_settings_dialog(self): self.settings_dialog.show() def show_status_message(self, msg, error=False): self.statusBar().showMessage(msg, 3000) if error: self.statusBar().setProperty('hasError', True) else: self.statusBar().setProperty('hasError', False) self.style().polish(self.statusBar()) def log_message(self, plugin_name, msg, level): message = '[%s] -> %s' % (plugin_name, msg) logging.log(level, message) self.show_status_message(message, True if level == logging.ERROR else False) log_plugin = self.plugin_handler.get_plugin('Log') if log_plugin: log_plugin.ui.add_log_message(time.time(), level, plugin_name, msg) def change_status_bar(self, new_msg): # Unset hasError if an error is removed. if not new_msg and self.statusBar().property('hasError'): self.statusBar().setProperty('hasError', False) self.style().polish(self.statusBar()) def on_text_changed(self): s = str(self.script_editor.toPlainText()) saved = False if s == self.last_saved and self.filename: saved = True title = ''.join(['Hashmal - ', self.filename]) if not saved: title = ''.join([title, ' *']) self.setWindowTitle(title) self.changes_saved = saved def closeEvent(self, event): # Save layout if configured to. if self.qt_settings.value('saveLayoutOnExit', defaultValue=QtCore.QVariant(False)).toBool(): self.qt_settings.setValue('toolLayout/default', self.saveState()) if self.close_script(): logging.shutdown() event.accept() else: event.ignore() def close_script(self): # Confirm discarding changes if an unsaved file is open. if str(self.script_editor.toPlainText()) and not self.changes_saved: msgbox = QMessageBox(self) msgbox.setWindowTitle('Hashmal - Save Changes') text = 'Do you want to save this script before closing?' if self.filename: text = 'Do you want to save your changes to ' + self.filename + ' before closing?' msgbox.setText(text) msgbox.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) msgbox.setDefaultButton(QMessageBox.Save) msgbox.setIcon(QMessageBox.Question) result = msgbox.exec_() if result == QMessageBox.Save: self.save_script() elif result == QMessageBox.Cancel: return False self.filename = '' self.changes_saved = True self.script_editor.clear() return True def new_script(self, filename=''): if not self.close_script(): return if not filename: base_name = ''.join(['Untitled-', str(time.time()), '.coinscript']) filename = os.path.expanduser(base_name) self.load_script(filename) def save_script(self): filename = self.filename if not filename: filename = str(QFileDialog.getSaveFileName(self, 'Save script', filter=script_file_filter)) if not filename: return if not filename.endswith('.coinscript'): filename += '.coinscript' self.filename = filename with open(self.filename, 'w') as file: file.write(str(self.script_editor.toPlainText())) self.last_saved = str(self.script_editor.toPlainText()) self.on_text_changed() def save_script_as(self): filename = str(QFileDialog.getSaveFileName(self, 'Save script as', filter=script_file_filter)) if not filename: return if not filename.endswith('.coinscript'): filename += '.coinscript' self.filename = filename self.save_script() def open_script(self): filename = str(QFileDialog.getOpenFileName(self, 'Open script', '.', filter=script_file_filter)) if not filename: return if self.close_script(): self.load_script(filename) def load_script(self, filename): if os.path.exists(filename): self.filename = filename with open(self.filename,'r') as file: self.script_editor.setPlainText(file.read()) else: self.script_editor.clear() self.last_saved = str(self.script_editor.toPlainText()) self.on_text_changed() def create_script_editor(self): vbox = QVBoxLayout() self.format_combo = QComboBox() self.format_combo.setWhatsThis('Use this to change the format that script editor displays and writes scripts in.') self.format_combo.addItems(known_script_formats) self.script_editor = ScriptEditor(self) self.script_editor.textChanged.connect(self.on_text_changed) self.script_editor.setWhatsThis('The script editor lets you write transaction scripts in a human-readable format. You can also write and edit scripts in their raw, hex-encoded format if you prefer.') self.format_combo.currentIndexChanged.connect(lambda index: self.script_editor.set_format(known_script_formats[index])) hbox = QHBoxLayout() hbox.addWidget(QLabel('Format: ')) hbox.addWidget(self.format_combo) hbox.addStretch(1) vbox.addLayout(hbox) vbox.addWidget(self.script_editor) w = QWidget() w.setLayout(vbox) self.setCentralWidget(w) def create_toolbar(self): toolbar = ToolBar(self, 'Toolbar') self.addToolBar(toolbar) def create_actions(self): hide_dock = QAction('Hide Dock', self) hide_dock.setShortcut(QKeySequence(QKeySequence.Close)) hide_dock.triggered.connect(self.hide_current_dock) self.addAction(hide_dock) move_left_dock = QAction('Move Left', self) move_left_dock.setShortcut(QKeySequence(QKeySequence.Back)) move_left_dock.triggered.connect(lambda: self.move_one_dock(reverse=True)) self.addAction(move_left_dock) move_right_dock = QAction('Move Right', self) move_right_dock.setShortcut(QKeySequence(QKeySequence.Forward)) move_right_dock.triggered.connect(self.move_one_dock) self.addAction(move_right_dock) def move_one_dock(self, reverse=False): """Move focus to the next or previous dock.""" w = get_active_dock() if not w: return docks = filter(lambda dock: dock.isVisible(), self.dock_orders[self.dockWidgetArea(w)]) index = docks.index(w) if reverse: if index == 0: index = len(docks) docks[index - 1].needsFocus.emit() else: if index >= len(docks) - 1: index = -1 docks[index + 1].needsFocus.emit() def tabifyDockWidget(self, bottom, top): """Overloaded method for purposes of remembering dock positions.""" docks = self.dock_orders[self.dockWidgetArea(bottom)] area = self.dockWidgetArea(bottom) if len(docks) == 0: docks.append(bottom) super(HashmalMain, self).tabifyDockWidget(bottom, top) idx = docks.index(bottom) docks.insert(idx + 1, top) def createPopupMenu(self): menu = QMenu(self) plugins_menu = menu.addMenu('All Plugins') for p in sorted(self.plugin_handler.loaded_plugins, key = lambda x: x.name): if not p.has_gui: continue plugins_menu.addAction(p.ui.toggleViewAction()) return menu def do_about(self): d = QDialog(self) vbox = QVBoxLayout() about_label = QLabel() about_label.setWordWrap(True) txt = [] txt.append(' '.join([ 'Hashmal is an IDE for Bitcoin transaction scripts and a general cryptocurrency development toolbox.', 'Its primary purpose is to make it easier to write, evaluate, and learn about transaction scripts.', ])) txt.append('Hashmal is intended for cryptocurrency developers and power users.') txt = '\n\n'.join(txt) about_label.setText(txt) close_button = QPushButton('Close') close_button.clicked.connect(d.close) btn_box = floated_buttons([close_button]) vbox.addWidget(about_label) vbox.addLayout(btn_box) d.setLayout(vbox) d.setWindowTitle('About Hashmal') d.exec_() def do_quick_tips(self): QuickTips(self).exec_() def hide_current_dock(self): w = get_active_dock() if not w: return docks = filter(lambda dock: dock.isVisible(), self.tabifiedDockWidgets(w)) w.toggleViewAction().trigger() if docks: docks[0].needsFocus.emit() def on_option_changed(self, key): if key == 'log_level': self.change_log_level(self.config.get_option('log_level', 'INFO'))
def __init__(self, app): super(HashmalMain, self).__init__() self.app = app self.app.setStyleSheet(hashmal_style()) self.changes_saved = True # {Qt.DockWidgetArea: [dock0, dock1, ...], ...} self.dock_orders = defaultdict(list) self.setCorner(QtCore.Qt.BottomRightCorner, QtCore.Qt.RightDockWidgetArea) self.config = Config() self.init_logger() self.config.optionChanged.connect(self.on_option_changed) QtCore.QCoreApplication.setOrganizationName('mazaclub') QtCore.QCoreApplication.setApplicationName('hashmal') self.qt_settings = QtCore.QSettings() active_params = self.config.get_option('chainparams', 'Bitcoin') # True if chainparams needs to be set after plugins load. needs_params_change = False # An exception is thrown if the last-active chainparams preset # only exists due to a plugin that defines it. try: chainparams.set_to_preset(active_params) except KeyError: chainparams.set_to_preset('Bitcoin') needs_params_change = True self.download_controller = DownloadController() self.setDockNestingEnabled(True) # Plugin Handler loads plugins and handles their dock widgets. self.plugin_handler = PluginHandler(self) self.plugin_handler.load_plugins() self.plugin_handler.do_default_layout() # Attempt to load chainparams preset again if necessary. if needs_params_change: try: chainparams.set_to_preset(active_params) except KeyError: self.log_message( 'Core', 'Chainparams preset "%s" does not exist. Setting chainparams to Bitcoin.', logging.ERROR) self.config.set_option('chainparams', 'Bitcoin') # Filename of script being edited. self.filename = '' # The last text that we saved. self.last_saved = '' self.create_script_editor() # Set up script editor font. script_font = self.qt_settings.value( 'editor/font', defaultValue=QtCore.QVariant('default')).toString() if script_font == 'default': font = monospace_font else: font = QFont() font.fromString(script_font) self.script_editor.setFont(font) self.settings_dialog = SettingsDialog(self) self.create_menubar() self.create_toolbar() self.create_actions() self.new_script() self.statusBar().setVisible(True) self.statusBar().messageChanged.connect(self.change_status_bar) self.restoreState( self.qt_settings.value('toolLayout/default/state').toByteArray()) self.restoreGeometry( self.qt_settings.value( 'toolLayout/default/geometry').toByteArray()) self.script_editor.setFocus() if self.qt_settings.value('quickTipsOnStart', defaultValue=QtCore.QVariant(True)).toBool(): QtCore.QTimer.singleShot(500, self.do_quick_tips)
def show_settings(self): config_handler.get_config_parser().getboolean('DEFAULT', 'AlwaysTop') self.init_window_flags(allow_top=False) SettingsDialog().exec() self.init_window_flags(allow_top=True) self.show()
def do_change_settings(self): dlg_settings = SettingsDialog() dlg_settings.show() dlg_settings.projectsDatabaseHasChanged.connect( self.do_load_projects_database) result = dlg_settings.exec_()
logo = QPixmap('./ui/png/tasklogo.png') app.setWindowIcon(QIcon(logo)) style = qdarkstyle.load_stylesheet() app.setStyleSheet(style) try: lbl = _show_splash_screen() istgutgelaufen = True app.loadConfig() app.connectServer() except Exception as ex: istgutgelaufen = False QMessageBox.critical(None, "ma", str(ex)) finally: lbl.hide() if istgutgelaufen: app.mainWindow = MainWindow() app.mainWindow.show() app.exec_() app.closeConnection() else: # wenns nicht gut geht, dialog auftun, dass man connection aendern kann dlg = SettingsDialog(app.settings) dlg.show() app.exec_() if dlg.result() == SettingsDialog.Accepted: app.settings = dlg.getData() app.saveConfig()
class Controller(QObject): def __init__(self): """ Create the Controller, inialize all things (settings, signals...) """ super(Controller, self).__init__(parent=None) self.is_running = False # the current Google Reader account self.account = Account() # views self.views = [] self.current_view = None # connect signals QObject.connect(self, SIGNALS["settings_updated"], self.settings_updated) QObject.connect(self.account.operations_manager, SIGNALS["operation_started"], self.update_titles, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["operation_ended"], self.update_titles, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["get_account_feeds_started"], self.feeds_fetching_started, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["get_account_feeds_done"], self.feeds_fetched, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["get_feed_content_started"], self.feed_content_fetching_started, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["get_more_feed_content_started"], self.feed_content_fetching_started, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["get_feed_content_done"], self.feed_content_fetched, Qt.QueuedConnection) QObject.connect(self.account.operations_manager, SIGNALS["get_more_feed_content_done"], self.feed_content_fetched, Qt.QueuedConnection) def create_views(self): """ Create all the views used by the application """ self.settings_dialog = SettingsDialog(controller=self) self.feedlist_view = FeedListView(controller=self) self.itemlist_view = ItemListView(controller=self) self.itemview_view = ItemViewView(controller=self) def run(self): """ Initialize graphic things and show the application by displaying the feed list window """ if self.is_running: return self.is_running = True self.create_views() self.current_view = self.feedlist_view self.current_view.show(app_just_launched=True) def settings_updated(self, auth_unverified_changed=False): """ When settings are updated, call same method for all views, and if the auth_unverified_changed parameter is true, ask for a resync """ for view in self.views: try: view.settings_updated() except: pass if auth_unverified_changed: self.account.fetch_feeds(fetch_unread_content=True) def add_view(self, view): """ Add a view to the list of manages views """ self.views.append(view) def get_title_operations_part(self): """ Get the part of the title which will handle the running operations counter """ nb = self.account.operations_manager.count_running() if nb: return "%d operations" % nb else: return "" def update_titles(self): """ Update titles for all views """ for view in self.views: try: view.update_title() except: pass def timeout_title_timer(self): """ Called when the title timer delay is done """ if self.current_view: self.current_view.update_display_title() def hide_children(self, view): """ Hide all views which are children of the specified one """ for child in self.views: if child.win.parent() == view.win and child.win.isVisible(): self.hide_children(child) child.win.hide() def set_current_view(self, view): """ Set the specified view as the current one """ if view != self.current_view: old_current_view = self.current_view self.current_view = view self.hide_children(self.current_view) self.current_view.show() def is_current_view(self, view): return view == self.current_view def switch_view(self, name): """ Swith to the a view specified by its name """ if name == 'feedlist': view = self.feedlist_view elif name == 'itemlist': view = self.itemlist_view elif name == 'itemview': view = self.itemview_view else: return self.set_current_view(view) def display_message(self, message, level="information"): """ Display a message for the current view """ if self.current_view: self.current_view.display_message(message, level) def display_feed(self, feed): """ Display a feed by displaying the itemlist view. If the specified feed cannot be selected, return to the previous view """ self.switch_view('itemlist') if not self.itemlist_view.set_current_feed(feed): self.switch_view('feedlist') def trigger_settings(self): """ Will display the settings dialog box """ self.settings_dialog.open() def start_loading(self): """ Activate the loading indicator in the current view """ if self.current_view: self.current_view.start_loading() def stop_loading(self): """ Stop the loading indicator in the current view """ if self.current_view: self.current_view.stop_loading() def feeds_fetching_started(self, operation_id): """ Actions when feeds will be fetched """ try: account = Operation.get_by_id(operation_id).params['object'] except: pass else: if account == self.account: for view in self.views: try: view.feeds_fetching_started() except: pass def feeds_fetched(self, operation_id): """ Actions when feeds are just fetched """ try: account = Operation.get_by_id(operation_id).params['object'] except: pass else: if account == self.account: for view in self.views: try: view.feeds_fetched() except: pass def feed_content_fetching_started(self, operation_id): """ Action when some of a feed's content will be fetched """ try: feed = Operation.get_by_id(operation_id).params['object'] except: pass else: if feed.account == self.account: for view in self.views: try: view.feed_content_fetching_started(feed) except: pass def feed_content_fetched(self, operation_id): """ Action when some of a feed's content was just fetched """ try: feed = Operation.get_by_id(operation_id).params['object'] except: pass else: if feed.account == self.account: for view in self.views: try: view.feed_content_fetched(feed) except: pass def display_item(self, item): """ Display an item by displaying the itemview view. If the specified iem cannot be selected, return to the previous view """ self.switch_view('itemview') if not self.itemview_view.set_current_item(item): self.switch_view('itemlist', hide_current=True) def get_next_item(self): """ Returnthe next available item """ return self.itemlist_view.get_next_item() def get_previous_item(self): """ Returnthe previous available item """ return self.itemlist_view.get_previous_item() def display_next_item(self): """ Display the next available item """ self.itemlist_view.activate_next_item() def display_previous_item(self): """ Display the previous available item """ self.itemlist_view.activate_previous_item() def item_read(self, item): """ Called when an item was marked as read/unread """ for view in self.views: try: view.item_read(item) except: pass def item_shared(self, item): """ Called when an item was shared/unshared """ for view in self.views: try: view.item_shared(item) except: pass def item_starred(self, item): """ Called when an item was starred/unstarred """ for view in self.views: try: view.item_starred(item) except: pass def feed_read(self, feed): """ Called when an feed was marked as read """ for view in self.views: try: view.feed_read(feed) except: pass
def __init__(self, app, list_manager, parent=None): super(MainWindow, self).__init__(parent) self.app = app # this must be defined before the setupUi is called # cause widgets in the interface need to reference it # in there __init__ methods self.listeners = [] self.list_manager = list_manager self.list_is_dirty = False self.setupUi(self) self.setWindowTitle("Assembly Document Tracker") QCoreApplication.setOrganizationName('Charles Cognato') QCoreApplication.setApplicationName('Assembly Doc Tracker') self.settings = QSettings() open_on_add = self.settings.value('open_on_add', 'false') if open_on_add == "true": self.actionOpen_on_Add.setChecked(True) else: self.actionOpen_on_Add.setChecked(False) # force at least one product to be on the list before documents can be added if self.listWidget.count() <= 0: self.listWidget_2.setEnabled(False) self.listWidget.setContextMenuPolicy(Qt.NoContextMenu) self.productContextActionRename = QAction(QIcon(":/filesaveas.png"), "rename", self) self.listWidget.addAction(self.productContextActionRename) self.connect(self.productContextActionRename, SIGNAL("triggered()"), self.on_assembly_context_action_rename_triggered) self.productContextActionDelete = QAction(QIcon(":/delete.png"), "delete", self) self.productContextActionDelete.setStatusTip(assembly_context_delete_status_tip) self.listWidget.addAction(self.productContextActionDelete) self.connect(self.productContextActionDelete, SIGNAL("triggered()"), self.on_assembly_context_action_delete_triggered) self.connect(self.listWidget, SIGNAL("itemClicked(QListWidgetItem*)"), self.on_list_widget_item_clicked) self.connect(self.listWidget, SIGNAL("currentItemChanged (QListWidgetItem*,QListWidgetItem*)"), self._update_gui) self.connect(self.listWidget, SIGNAL("pdfMoved"), self._transfer_docs) self.listWidget_2.setContextMenuPolicy(Qt.NoContextMenu) self.listWidget_2.addAction(self.action_Open) self.connect(self.action_Open, SIGNAL("triggered()"), self.open_pdf) self.documentContextActionDelete = QAction(QIcon(":/delete.png"), "delete", self) self.listWidget_2.addAction(self.documentContextActionDelete) self.connect(self.documentContextActionDelete, SIGNAL("triggered()"), self.on_document_context_action_delete_activated) self.connect(self.listWidget_2, SIGNAL("itemDoubleClicked (QListWidgetItem*)"), self.on_pdf_double_clicked) self.connect(self.listWidget_2, SIGNAL("pdfAdded"), self.pdf_added) self.connect(self.listWidget_2, SIGNAL("itemSelectionChanged()"), self.on_docs_selection_changed) self.connect(self.listWidget_2, SIGNAL("removeDocs"), self.on_list_widget2_removeDocs) self.connect(self.action_New, SIGNAL("triggered()"), self.on_pbAddAssembly_clicked) self.connect(self.action_Save, SIGNAL("triggered()"), self._save_assembly_data) self.connect(self.actionPreferences, SIGNAL("triggered()"), self.on_preferences_clicked) self.input_dialog = InputDialog(parent=self) self.confirm_dialog = ConfirmDialog(self) self.settings_dialog = SettingsDialog(self) self.usage_dialog = UsageDialog(self) self.show() self.__is_first_run() QTimer.singleShot(0, self._load_assembly_data)
def show_settings_dialog(self): settings_dlg = SettingsDialog() settings_dlg.exec_() # apply settings # self.remove_menu_buttons() self.build_menu_tree()
def open_settings(self, _): settings_dialog = SettingsDialog(self.settings, self) settings_dialog.exec()
def settings(self): sett_dialog = SettingsDialog() sett_dialog.show() result = sett_dialog.exec_()
class HashmalMain(QMainWindow): # Signals # Emitted when the list of user's layouts changes. layoutsChanged = QtCore.pyqtSignal() def __init__(self, app): super(HashmalMain, self).__init__() self.app = app self.app.setStyleSheet(hashmal_style()) self.changes_saved = True # {Qt.DockWidgetArea: [dock0, dock1, ...], ...} self.dock_orders = defaultdict(list) self.setCorner(QtCore.Qt.BottomRightCorner, QtCore.Qt.RightDockWidgetArea) self.config = Config() self.init_logger() self.config.optionChanged.connect(self.on_option_changed) QtCore.QCoreApplication.setOrganizationName('mazaclub') QtCore.QCoreApplication.setApplicationName('hashmal') self.qt_settings = QtCore.QSettings() active_params = self.config.get_option('chainparams', 'Bitcoin') # True if chainparams needs to be set after plugins load. needs_params_change = False # An exception is thrown if the last-active chainparams preset # only exists due to a plugin that defines it. try: chainparams.set_to_preset(active_params) except KeyError: chainparams.set_to_preset('Bitcoin') needs_params_change = True self.download_controller = DownloadController() self.setDockNestingEnabled(True) # Plugin Handler loads plugins and handles their dock widgets. self.plugin_handler = PluginHandler(self) self.plugin_handler.load_plugins() self.plugin_handler.do_default_layout() # Attempt to load chainparams preset again if necessary. if needs_params_change: try: chainparams.set_to_preset(active_params) except KeyError: self.log_message( 'Core', 'Chainparams preset "%s" does not exist. Setting chainparams to Bitcoin.', logging.ERROR) self.config.set_option('chainparams', 'Bitcoin') # Filename of script being edited. self.filename = '' # The last text that we saved. self.last_saved = '' self.create_script_editor() # Set up script editor font. script_font = self.qt_settings.value( 'editor/font', defaultValue=QtCore.QVariant('default')).toString() if script_font == 'default': font = monospace_font else: font = QFont() font.fromString(script_font) self.script_editor.setFont(font) self.settings_dialog = SettingsDialog(self) self.create_menubar() self.create_toolbar() self.create_actions() self.new_script() self.statusBar().setVisible(True) self.statusBar().messageChanged.connect(self.change_status_bar) self.restoreState( self.qt_settings.value('toolLayout/default/state').toByteArray()) self.restoreGeometry( self.qt_settings.value( 'toolLayout/default/geometry').toByteArray()) self.script_editor.setFocus() if self.qt_settings.value('quickTipsOnStart', defaultValue=QtCore.QVariant(True)).toBool(): QtCore.QTimer.singleShot(500, self.do_quick_tips) def sizeHint(self): return QtCore.QSize(800, 500) def init_logger(self): """Initialize logger.""" handler = logging.StreamHandler() formatter = logging.Formatter( '%(asctime)s - %(levelname)s - %(message)s', '%Y-%m-%d %H:%M:%S') handler.setFormatter(formatter) logger = logging.getLogger() logger.addHandler(handler) self.change_log_level(self.config.get_option('log_level', 'INFO')) def change_log_level(self, level_str): level_str = level_str.upper() if level_str not in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']: level_str = 'INFO' level = getattr(logging, level_str) logging.getLogger().setLevel(level) def create_menubar(self): menubar = QMenuBar() file_menu = menubar.addMenu('&File') file_menu.addAction('&New', self.new_script).setShortcut(QKeySequence.New) file_menu.addAction('Save As...', self.save_script_as).setShortcut( QKeySequence.SaveAs) file_menu.addAction('&Open', self.open_script).setShortcut(QKeySequence.Open) file_menu.addAction('&Save', self.save_script).setShortcut(QKeySequence.Save) file_menu.addAction('&Quit', self.close) # Script actions script_menu = menubar.addMenu('&Script') script_menu.addAction('&Evaluate', self.plugin_handler.evaluate_current_script) script_menu.addAction('&Copy Hex', self.script_editor.copy_hex) # Settings and tool toggling tools_menu = menubar.addMenu('&Tools') tools_menu.addAction('&Settings', self.show_settings_dialog) tools_menu.addAction('&Plugin Manager', lambda: PluginManager(self).exec_()) tools_menu.addSeparator() self.plugin_handler.create_menu(tools_menu) help_menu = menubar.addMenu('&Help') help_menu.addAction('&About', self.do_about) help_menu.addAction('&Quick Tips', self.do_quick_tips) self.setMenuBar(menubar) def show_settings_dialog(self): self.settings_dialog.show() def show_status_message(self, msg, error=False): self.statusBar().showMessage(msg, 3000) if error: self.statusBar().setProperty('hasError', True) else: self.statusBar().setProperty('hasError', False) self.style().polish(self.statusBar()) def log_message(self, plugin_name, msg, level): message = '[%s] -> %s' % (plugin_name, msg) logging.log(level, message) self.show_status_message(message, True if level == logging.ERROR else False) log_plugin = self.plugin_handler.get_plugin('Log') if log_plugin: log_plugin.ui.add_log_message(time.time(), level, plugin_name, msg) def change_status_bar(self, new_msg): # Unset hasError if an error is removed. if not new_msg and self.statusBar().property('hasError'): self.statusBar().setProperty('hasError', False) self.style().polish(self.statusBar()) def on_text_changed(self): s = str(self.script_editor.toPlainText()) saved = False if s == self.last_saved and self.filename: saved = True title = ''.join(['Hashmal - ', self.filename]) if not saved: title = ''.join([title, ' *']) self.setWindowTitle(title) self.changes_saved = saved def closeEvent(self, event): # Save layout if configured to. if self.qt_settings.value( 'saveLayoutOnExit', defaultValue=QtCore.QVariant(False)).toBool(): self.qt_settings.setValue('toolLayout/default', self.saveState()) if self.close_script(): logging.shutdown() event.accept() else: event.ignore() def close_script(self): # Confirm discarding changes if an unsaved file is open. if str(self.script_editor.toPlainText()) and not self.changes_saved: msgbox = QMessageBox(self) msgbox.setWindowTitle('Hashmal - Save Changes') text = 'Do you want to save this script before closing?' if self.filename: text = 'Do you want to save your changes to ' + self.filename + ' before closing?' msgbox.setText(text) msgbox.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) msgbox.setDefaultButton(QMessageBox.Save) msgbox.setIcon(QMessageBox.Question) result = msgbox.exec_() if result == QMessageBox.Save: self.save_script() elif result == QMessageBox.Cancel: return False self.filename = '' self.changes_saved = True self.script_editor.clear() return True def new_script(self, filename=''): if not self.close_script(): return if not filename: base_name = ''.join(['Untitled-', str(time.time()), '.coinscript']) filename = os.path.expanduser(base_name) self.load_script(filename) def save_script(self): filename = self.filename if not filename: filename = str( QFileDialog.getSaveFileName(self, 'Save script', filter=script_file_filter)) if not filename: return if not filename.endswith('.coinscript'): filename += '.coinscript' self.filename = filename with open(self.filename, 'w') as file: file.write(str(self.script_editor.toPlainText())) self.last_saved = str(self.script_editor.toPlainText()) self.on_text_changed() def save_script_as(self): filename = str( QFileDialog.getSaveFileName(self, 'Save script as', filter=script_file_filter)) if not filename: return if not filename.endswith('.coinscript'): filename += '.coinscript' self.filename = filename self.save_script() def open_script(self): filename = str( QFileDialog.getOpenFileName(self, 'Open script', '.', filter=script_file_filter)) if not filename: return if self.close_script(): self.load_script(filename) def load_script(self, filename): if os.path.exists(filename): self.filename = filename with open(self.filename, 'r') as file: self.script_editor.setPlainText(file.read()) else: self.script_editor.clear() self.last_saved = str(self.script_editor.toPlainText()) self.on_text_changed() def create_script_editor(self): vbox = QVBoxLayout() self.format_combo = QComboBox() self.format_combo.setWhatsThis( 'Use this to change the format that script editor displays and writes scripts in.' ) self.format_combo.addItems(known_script_formats) self.script_editor = ScriptEditor(self) self.script_editor.textChanged.connect(self.on_text_changed) self.script_editor.setWhatsThis( 'The script editor lets you write transaction scripts in a human-readable format. You can also write and edit scripts in their raw, hex-encoded format if you prefer.' ) self.format_combo.currentIndexChanged.connect( lambda index: self.script_editor.set_format(known_script_formats[ index])) hbox = QHBoxLayout() hbox.addWidget(QLabel('Format: ')) hbox.addWidget(self.format_combo) hbox.addStretch(1) vbox.addLayout(hbox) vbox.addWidget(self.script_editor) w = QWidget() w.setLayout(vbox) self.setCentralWidget(w) def create_toolbar(self): toolbar = ToolBar(self, 'Toolbar') self.addToolBar(toolbar) def create_actions(self): hide_dock = QAction('Hide Dock', self) hide_dock.setShortcut(QKeySequence(QKeySequence.Close)) hide_dock.triggered.connect(self.hide_current_dock) self.addAction(hide_dock) move_left_dock = QAction('Move Left', self) move_left_dock.setShortcut(QKeySequence(QKeySequence.Back)) move_left_dock.triggered.connect( lambda: self.move_one_dock(reverse=True)) self.addAction(move_left_dock) move_right_dock = QAction('Move Right', self) move_right_dock.setShortcut(QKeySequence(QKeySequence.Forward)) move_right_dock.triggered.connect(self.move_one_dock) self.addAction(move_right_dock) def move_one_dock(self, reverse=False): """Move focus to the next or previous dock.""" w = get_active_dock() if not w: return docks = filter(lambda dock: dock.isVisible(), self.dock_orders[self.dockWidgetArea(w)]) index = docks.index(w) if reverse: if index == 0: index = len(docks) docks[index - 1].needsFocus.emit() else: if index >= len(docks) - 1: index = -1 docks[index + 1].needsFocus.emit() def tabifyDockWidget(self, bottom, top): """Overloaded method for purposes of remembering dock positions.""" docks = self.dock_orders[self.dockWidgetArea(bottom)] area = self.dockWidgetArea(bottom) if len(docks) == 0: docks.append(bottom) super(HashmalMain, self).tabifyDockWidget(bottom, top) idx = docks.index(bottom) docks.insert(idx + 1, top) def createPopupMenu(self): menu = QMenu(self) plugins_menu = menu.addMenu('All Plugins') for p in sorted(self.plugin_handler.loaded_plugins, key=lambda x: x.name): if not p.has_gui: continue plugins_menu.addAction(p.ui.toggleViewAction()) return menu def do_about(self): d = QDialog(self) vbox = QVBoxLayout() about_label = QLabel() about_label.setWordWrap(True) txt = [] txt.append(' '.join([ 'Hashmal is an IDE for Bitcoin transaction scripts and a general cryptocurrency development toolbox.', 'Its primary purpose is to make it easier to write, evaluate, and learn about transaction scripts.', ])) txt.append( 'Hashmal is intended for cryptocurrency developers and power users.' ) txt = '\n\n'.join(txt) about_label.setText(txt) close_button = QPushButton('Close') close_button.clicked.connect(d.close) btn_box = floated_buttons([close_button]) vbox.addWidget(about_label) vbox.addLayout(btn_box) d.setLayout(vbox) d.setWindowTitle('About Hashmal') d.exec_() def do_quick_tips(self): QuickTips(self).exec_() def hide_current_dock(self): w = get_active_dock() if not w: return docks = filter(lambda dock: dock.isVisible(), self.tabifiedDockWidgets(w)) w.toggleViewAction().trigger() if docks: docks[0].needsFocus.emit() def on_option_changed(self, key): if key == 'log_level': self.change_log_level(self.config.get_option('log_level', 'INFO'))
def show_settings_dialog(self, widget): settings_dialog = SettingsDialog() settings_dialog.run() settings_dialog.destroy()
class AdaplinControl: def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface self.canvas = self.iface.mapCanvas() # Create dialog form self.dlg = AdaplinDialog() # Create settings dialog self.settingsDialog = SettingsDialog() def initGui(self): mc = self.canvas layer = mc.currentLayer() # Create action for the plugin icon and the plugin menu self.action = QAction(QIcon(":/plugins/AdaplinTool/icon.png"), "Adaplin", self.iface.mainWindow()) # Button starts disabled and unchecked self.action.setEnabled(False) self.action.setCheckable(True) self.action.setChecked(False) # Add Settings to the [Vector] Menu self.settingsAction = QAction("Settings", self.iface.mainWindow()) #self.iface.addPluginToVectorMenu("&Adaplin Settings", self.settingsAction) self.iface.addPluginToMenu("&Adaplin", self.settingsAction) self.settingsAction.triggered.connect(self.openSettings) # Add the plugin to Plugin Menu and the Plugin Icon to the Toolbar self.iface.addPluginToMenu("&Adaplin", self.action) self.iface.addToolBarIcon(self.action) # Connect signals for button behaviour (map layer change, run the tool and change of QGIS map tool set) self.iface.currentLayerChanged['QgsMapLayer*'].connect(self.toggle) self.action.triggered.connect(self.run) QObject.connect(mc, SIGNAL("mapToolSet(QgsMapTool*)"), self.deactivate) # Connect the change of the Raster Layer in the ComboBox to function trata_combo self.dlg.comboBox.currentIndexChanged.connect(self.trata_combo) def toggle(self): # Get current layer mc = self.canvas layer = mc.currentLayer() #print "Adaplin layer = ", layer.name() # In case the current layer is None we do nothing if layer is None: return #print 'raster type = ', layer.type() #print 'e vector = ', layer.type() == layer.VectorLayer # This is to decide when the plugin button is enabled or disabled # The layer must be a Vector Layer if layer.type() == layer.VectorLayer: # We only care about the Line and Polygon layers if layer.geometryType() == QGis.Line or layer.geometryType( ) == QGis.Polygon: # First we disconnect all possible previous signals associated with this layer # If layer is editable, SIGNAL "editingStopped()" is connected to toggle # If it is not editable, SIGNAL "editingStarted()" is connected to toggle try: layer.editingStarted.disconnect(self.toggle) except: pass try: layer.editingStopped.disconnect(self.toggle) except: pass # If current layer is editable, the button is enabled if layer.isEditable(): self.action.setEnabled(True) # If we stop editing, we run toggle function to disable the button layer.editingStopped.connect(self.toggle) # Layer is not editable else: self.action.setEnabled(False) # In case we start editing, we run toggle function to enable the button layer.editingStarted.connect(self.toggle) else: self.action.setEnabled(False) else: self.action.setEnabled(False) def deactivate(self): self.action.setChecked(False) def unload(self): # Removes item from Plugin Menu, Vector Menu and removes the toolbar icon self.iface.removePluginMenu("&Adaplin", self.action) self.iface.removePluginMenu("&Adaplin", self.settingsAction) self.iface.removeToolBarIcon(self.action) def trata_combo(self): # ComboBox Selected Raster Layer indiceCamada = self.dlg.comboBox.currentIndex() camadaSelecionada = self.camadas_raster[indiceCamada] # Clear ComboBoxs of Bands self.dlg.comboBox_2.clear() self.dlg.comboBox_3.clear() self.dlg.comboBox_4.clear() # Get number of raster bands numBandas = camadaSelecionada.bandCount() # List image bands by numbers and add them to Bands ComboBoxs lista_bandas = [str(b) for b in range(1, numBandas + 1)] self.dlg.comboBox_2.addItems(lista_bandas) self.dlg.comboBox_3.addItems(lista_bandas) self.dlg.comboBox_4.addItems(lista_bandas) def run(self): # Unpress the button if it is pressed if not self.action.isChecked(): print self.action.isChecked() self.action.setChecked(False) return # On-the-fly SRS must be Projected mapCanvasSrs = self.iface.mapCanvas().mapRenderer().destinationCrs() if mapCanvasSrs.geographicFlag(): QMessageBox.information( self.iface.mainWindow(), 'Error', '<h2> Please choose an On-the-Fly Projected Coordinate System</h2>' ) return # Clear ComboBox of Raster Selection. # This command generate a bug sometimes (for example, when using the plugin with a raster, removing this raster and adding it again) # when trying to clear the comboBox when it is triggered with trata_combo # Disconnect and connect the signal is possible but not elegant self.dlg.comboBox.clear() # List rasters of Legend Interface self.camadas_raster = [] camadas = self.iface.legendInterface().layers() for camada in camadas: if camada.type() == QgsMapLayer.RasterLayer: self.camadas_raster.append(camada) self.dlg.comboBox.addItem(camada.name()) # Error in case there are no raster layers in the Legend Interface if not self.camadas_raster: QMessageBox.information( self.iface.mainWindow(), 'Error', '<h2>There are no raster layers in the Legend Interace</h2>') return # Finish the dialog box and run the dialog event loop self.dlg.show() result = self.dlg.exec_() # See if OK was pressed if result: # Get Raster Selected from ComboBox indiceCamada = self.dlg.comboBox.currentIndex() camadaSelecionada = self.camadas_raster[indiceCamada] # Get Bands selected for this Raster numBandas = camadaSelecionada.bandCount() lista_bandas = [str(b) for b in range(1, numBandas + 1)] indiceCombo2 = self.dlg.comboBox_2.currentIndex() indiceCombo3 = self.dlg.comboBox_3.currentIndex() indiceCombo4 = self.dlg.comboBox_4.currentIndex() bandas_selecao = (lista_bandas[indiceCombo2], lista_bandas[indiceCombo3], lista_bandas[indiceCombo4]) # Activate our tool if OK is pressed self.adaplin = Adaplin(self.iface, camadaSelecionada, bandas_selecao) mc = self.canvas layer = mc.currentLayer() mc.setMapTool(self.adaplin) self.action.setChecked(True) else: self.action.setChecked(False) def openSettings(self): # Default settings to reload def valoresPadrao(): self.settingsDialog.doubleSpinBox.setValue(DEFAULT_ESPACAMENTO) self.settingsDialog.spinBox.setValue(DEFAULT_QPONTOS) # Connect button to function that reload default values self.settingsDialog.pushButton.clicked.connect(valoresPadrao) self.settingsDialog.show() result = self.settingsDialog.exec_() # If OK is pressed we update the settings if result: QSettings().setValue(SETTINGS_NAME + "/qpontos", self.settingsDialog.spinBox.value()) QSettings().setValue(SETTINGS_NAME + "/espacamento", self.settingsDialog.doubleSpinBox.value()) # Disconnect signal connected previously self.settingsDialog.pushButton.clicked.disconnect(valoresPadrao)
class GUI: def __init__(self, application): self.app = application #signal that experiment is running self.experiment_mode = False self.app.print_comment("Starting GUI interface:") self.app.print_comment("please wait while the application loads...") #build the GUI interface as a seperate window win = tk.Tk() Pmw.initialise(win) #initialize Python MegaWidgets win.withdraw() win.wm_title(WINDOW_TITLE) win.focus_set() #put focus on this new window self.win = win #handle the user hitting the 'X' button self.win.protocol("WM_DELETE_WINDOW", self._close) #FIXME bind some debugging keystrokes to the window #self.win.bind('<Control-f>', lambda e: self.app.force_experiment()) #build the left panel left_panel = tk.Frame(win) #capture controls tk.Label(left_panel, text="Capture Controls:", font = "Helvetica 14 bold").pack(side='top',fill='x', anchor="nw") self.change_settings_button = tk.Button(left_panel,text='Change Settings',command = self.change_settings) self.change_settings_button.pack(side='top',fill='x', anchor="sw") self.run_continually_button = tk.Button(left_panel,text='Run Continually',command = self.run_continually) self.run_continually_button.pack(side='top',fill='x', anchor="nw") self.stop_button = tk.Button(left_panel,text='Stop',command = self.stop, state='disabled') self.stop_button.pack(side='top',fill='x', anchor="nw") self.run_once_button = tk.Button(left_panel,text='Run Once',command = self.run_once) self.run_once_button.pack(side='top',fill='x', anchor="nw") self.export_data_button = tk.Button(left_panel,text='Export Data',command = self.export_data, state='disabled') self.export_data_button.pack(side='bottom',anchor="sw") left_panel.pack(fill='y',expand='no',side='left', padx = 10) #create an tk embedded figure for temperature display mid_panel = tk.Frame(win) self.temperature_plot_template = TemperaturePlot() self.temperature_figure_widget = EmbeddedFigure(mid_panel, figsize=TEMPERATURE_FIGSIZE) self.temperature_figure_widget.pack(side='left',fill='both', expand='yes') mid_panel.pack(fill='both', expand='yes',side='left') #build the right panel right_panel = tk.Frame(win) self.text_display = TextDisplayBox(right_panel,text_height=15, buffer_size = TEXT_BUFFER_SIZE) self.text_display.pack(side='left',fill='both',expand='yes') right_panel.pack(fill='both', expand='yes',side='right') #build the confirmation dialog self.settings_dialog = SettingsDialog(self.win) self.settings_dialog.withdraw() self._load_settings() #run modes self._is_running = False def launch(self): #run the GUI handling loop IgnoreKeyboardInterrupt() self.win.deiconify() self.win.mainloop() NoticeKeyboardInterrupt() def change_settings(self): self.app.print_comment("changing capture settings...") self.settings_dialog.activate() def run_continually(self): #cache the GUI settings FIXME - is this necessary? self._cache_settings() #disable all the buttons, except the stop button self.run_once_button.config(state='disabled') self.run_continually_button.config(state='disabled') self.stop_button.config(state='normal') self._is_running = True self._run_continually_loop() def _run_continually_loop(self): if self._is_running: self.run_once() run_interval = int(1000*float(self.settings_dialog.form['run_interval'])) #convert to milliseconds #reschedule loop self.win.after(run_interval,self._run_continually_loop) else: #enable all the buttons, except the stop button self.run_once_button.config(state='normal') self.run_continually_button.config(state='normal') self.stop_button.config(state='disabled') #do not reschedule loop def run_once(self): self.app.acquire_temperature_sample() self._update_temperature_plot() self.export_data_button.config(state='normal') #data can now be exported def stop(self): self._is_running = False def export_data(self): self.app.print_comment("Exporting data...") dt_now = datetime.datetime.utcnow() dt_now_str = dt_now.strftime("%Y-%m-%d-%H_%m_%S") default_filename = "%s_temperature.csv" % (dt_now_str,) fdlg = SaveFileDialog(self.win,title="Save Temperature Data") userdata_path = self.app.config['paths']['data_dir'] filename = fdlg.go(dir_or_file = userdata_path, pattern="*.csv", default=default_filename, key = None ) if not filename: return #abort delim = "," comment_prefix = "#" eol = "\n" with open(filename, 'w') as f: #write header f.write(comment_prefix) keys = self.app.temperature_samples.keys() f.write(delim.join(keys)) f.write(eol) vals = self.app.temperature_samples.values() D = np.vstack(vals).transpose() np.savetxt(f, D, fmt=DATA_FORMAT, delimiter=delim) def _update_temperature_plot(self): figure = self.temperature_figure_widget.get_figure() figure.clear() t = np.array(self.app.timestamps) t -= t[0] t /= 3600.0 Xs = [] Ys = [] for key,temp_list in self.app.temperature_samples.items(): Xs.append(t) Ys.append(temp_list) self.temperature_plot_template.plot(Xs, Ys, figure = figure ) self.temperature_figure_widget.update() # def wait_on_experiment(self): # if self.app.check_experiment_completed(): # self.app.shutdown_experiment() # self.win.after(WAIT_DELAY,self.wait_on_experiment_shutdown) # else: # self.win.after(WAIT_DELAY,self.wait_on_experiment) def print_to_text_display(self, text, eol='\n'): self.text_display.print_text(text, eol=eol) def _load_settings(self): if os.path.exists(SETTINGS_FILEPATH): self.app.print_comment("loading from settings file '%s'" % SETTINGS_FILEPATH) settings = shelve.open(SETTINGS_FILEPATH) self.settings_dialog.form['run_interval'] = settings.get('run_interval', DEFAULT_RUN_INTERVAL) settings.close() else: self.app.print_comment("failed to find settings file '%s'" % SETTINGS_FILEPATH) def _cache_settings(self): self.app.print_comment("caching to settings file '%s'" % SETTINGS_FILEPATH) settings = shelve.open(SETTINGS_FILEPATH) settings['run_interval'] = self.settings_dialog.form['run_interval'] settings.close() def _close(self): #cache the GUI settings FIXME - is this necessary? self._cache_settings() self.win.destroy()
def __init__(self, app): super(HashmalMain, self).__init__() self.app = app self.app.setStyleSheet(hashmal_style()) self.changes_saved = True # {Qt.DockWidgetArea: [dock0, dock1, ...], ...} self.dock_orders = defaultdict(list) self.setCorner(QtCore.Qt.BottomRightCorner, QtCore.Qt.RightDockWidgetArea) self.config = Config() self.init_logger() self.config.optionChanged.connect(self.on_option_changed) QtCore.QCoreApplication.setOrganizationName('mazaclub') QtCore.QCoreApplication.setApplicationName('hashmal') self.qt_settings = QtCore.QSettings() active_params = self.config.get_option('chainparams', 'Bitcoin') # True if chainparams needs to be set after plugins load. needs_params_change = False # An exception is thrown if the last-active chainparams preset # only exists due to a plugin that defines it. try: chainparams.set_to_preset(active_params) except KeyError: chainparams.set_to_preset('Bitcoin') needs_params_change = True self.download_controller = DownloadController() self.setDockNestingEnabled(True) # Plugin Handler loads plugins and handles their dock widgets. self.plugin_handler = PluginHandler(self) self.plugin_handler.load_plugins() self.plugin_handler.do_default_layout() # Attempt to load chainparams preset again if necessary. if needs_params_change: try: chainparams.set_to_preset(active_params) except KeyError: self.log_message('Core', 'Chainparams preset "%s" does not exist. Setting chainparams to Bitcoin.', logging.ERROR) self.config.set_option('chainparams', 'Bitcoin') # Filename of script being edited. self.filename = '' # The last text that we saved. self.last_saved = '' self.create_script_editor() # Set up script editor font. script_font = self.qt_settings.value('editor/font', defaultValue=QtCore.QVariant('default')).toString() if script_font == 'default': font = monospace_font else: font = QFont() font.fromString(script_font) self.script_editor.setFont(font) self.settings_dialog = SettingsDialog(self) self.create_menubar() self.create_toolbar() self.create_actions() self.new_script() self.statusBar().setVisible(True) self.statusBar().messageChanged.connect(self.change_status_bar) self.restoreState(self.qt_settings.value('toolLayout/default/state').toByteArray()) self.restoreGeometry(self.qt_settings.value('toolLayout/default/geometry').toByteArray()) self.script_editor.setFocus() if self.qt_settings.value('quickTipsOnStart', defaultValue=QtCore.QVariant(True)).toBool(): QtCore.QTimer.singleShot(500, self.do_quick_tips)
def settings(self): """Launch the preferences settings dialog """ self.set_dialog = SettingsDialog(self.prefs)