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()
Example #2
0
 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)
Example #3
0
 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
Example #4
0
    def action_settings(self):
        sett_dialog = SettingsDialog()
        sett_dialog.show()
        sett_dialog.exec_()

        self.reinit_tree()
Example #5
0
 def create_settings_dialog(self):
     self.settings_dialog     = SettingsDialog(controller=self)
Example #6
0
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()
Example #8
0
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'))
Example #9
0
    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)
Example #10
0
 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()
Example #11
0
 def do_change_settings(self):
     dlg_settings = SettingsDialog()
     dlg_settings.show()
     dlg_settings.projectsDatabaseHasChanged.connect(
         self.do_load_projects_database)
     result = dlg_settings.exec_()
Example #12
0
    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()
Example #13
0
    def action_settings(self):
        sett_dialog = SettingsDialog()
        sett_dialog.show()
        sett_dialog.exec_()

        self.reinit_tree()
Example #14
0
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)
Example #16
0
 def show_settings_dialog(self):
     settings_dlg = SettingsDialog()
     settings_dlg.exec_()
     # apply settings
     # self.remove_menu_buttons()
     self.build_menu_tree()
Example #17
0
 def open_settings(self, _):
     settings_dialog = SettingsDialog(self.settings, self)
     settings_dialog.exec()
Example #18
0
 def settings(self):
     sett_dialog = SettingsDialog()
     sett_dialog.show()
     result = sett_dialog.exec_()
Example #19
0
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'))
Example #20
0
 def show_settings_dialog(self, widget):
     settings_dialog = SettingsDialog()
     settings_dialog.run()
     settings_dialog.destroy()
Example #21
0
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)
Example #22
0
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()
Example #23
0
    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)
Example #24
0
    def settings(self):
        """Launch the preferences settings dialog
        """

        self.set_dialog = SettingsDialog(self.prefs)