Esempio n. 1
0
class Ui_GHydraulicsResultDialog(object):
    def setupUi(self, GHydraulicsResultDialog):
        GHydraulicsResultDialog.setObjectName(_fromUtf8("GHydraulicsResultDialog"))
        GHydraulicsResultDialog.resize(640, 480)
        self.buttonBox = QDialogButtonBox(GHydraulicsResultDialog)
        self.buttonBox.setGeometry(QtCore.QRect(10, 440, 620, 32))
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)
        self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
        self.tabWidget = QTabWidget(GHydraulicsResultDialog)
        self.tabWidget.setGeometry(QtCore.QRect(10, 10, 620, 390))
        self.tabWidget.setObjectName(_fromUtf8("tabWidget"))
        self.tabOutput = QWidget()
        self.tabOutput.setObjectName(_fromUtf8("tabOutput"))
        self.textOutput = QTextBrowser(self.tabOutput)
        self.textOutput.setGeometry(QtCore.QRect(10, 10, 600, 340))
        sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.textOutput.sizePolicy().hasHeightForWidth())
        self.textOutput.setSizePolicy(sizePolicy)
        self.textOutput.setObjectName(_fromUtf8("textOutput"))
        self.tabWidget.addTab(self.tabOutput, _fromUtf8(""))
        self.tabReport = QWidget()
        self.tabReport.setObjectName(_fromUtf8("tabReport"))
        self.textReport = QTextBrowser(self.tabReport)
        self.textReport.setGeometry(QtCore.QRect(10, 10, 600, 340))
        sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.textReport.sizePolicy().hasHeightForWidth())
        self.textReport.setSizePolicy(sizePolicy)
        self.textReport.setObjectName(_fromUtf8("textReport"))
        self.tabWidget.addTab(self.tabReport, _fromUtf8(""))
        self.comboStep = QComboBox(GHydraulicsResultDialog)
        self.comboStep.setGeometry(QtCore.QRect(150, 410, 80, 27))
        self.comboStep.setObjectName(_fromUtf8("comboStep"))
        self.labelStep = QLabel(GHydraulicsResultDialog)
        self.labelStep.setGeometry(QtCore.QRect(10, 415, 120, 17))
        self.labelStep.setObjectName(_fromUtf8("labelStep"))

        self.retranslateUi(GHydraulicsResultDialog)
        self.tabWidget.setCurrentIndex(0)
        
        #QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), GHydraulicsResultDialog.accept)
        self.buttonBox.accepted.connect(GHydraulicsResultDialog.accept)
        #QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), GHydraulicsResultDialog.reject)
        self.buttonBox.rejected.connect(GHydraulicsResultDialog.reject)
        QtCore.QMetaObject.connectSlotsByName(GHydraulicsResultDialog)

    def retranslateUi(self, GHydraulicsResultDialog):
        GHydraulicsResultDialog.setWindowTitle(_translate("GHydraulicsResultDialog", "EPANET Results", None))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabOutput), _translate("GHydraulicsResultDialog", "EPANET Output", None))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabReport), _translate("GHydraulicsResultDialog", "Report", None))
        self.labelStep.setText(_translate("GHydraulicsResultDialog", "Load time step", None))
Esempio n. 2
0
class SupportingDocuments(ComponentUtility):
    onUploadDocument = pyqtSignal(list)

    def __init__(self,
                 box,
                 combobox,
                 add_documents_btn,
                 notification_bar,
                 parent=None):
        """
        Handles the supporting documents component loading.
        :param box: The layout holding the container widget.
        :type box: QVBoxLayout
        :param combobox: The combobox loading supporting document types.
        :type combobox: QComboBox
        :param add_documents_btn: The add supporting document button
        :type add_documents_btn: QPushButton
        :param notification_bar: The NotificationBar object that displays
        notification.
        :type notification_bar: Object
        :param parent: The container of the widget
        :type parent: QDialog or None
        """
        ComponentUtility.__init__(self)
        self._parent = parent
        self.container_box = box
        self.doc_type_cbo = combobox
        self.notification_bar = notification_bar
        self.str_number = 1
        self.add_documents_btn = add_documents_btn
        self.str_numbers = [1]
        self.current_party_count = None
        self.init_documents()

    def init_documents(self):
        """
        Initializes the document type combobox by
        populating data.
        """
        self.supporting_doc_manager = SourceDocumentManager(
            self.social_tenure.supporting_doc, self.str_doc_model,
            self._parent)

        self.create_doc_tab_populate_combobox()

        self.doc_type_cbo.currentIndexChanged.connect(
            self.match_doc_combo_to_tab)
        self.docs_tab.currentChanged.connect(self.match_doc_tab_to_combo)

    def party_count(self, count):
        """
        A setter for current_party_count that is used to determined
        the number of copies for each supporting document.
        :param count: The number of currently added party records.
        :type count: Integer
        """
        self.current_party_count = count

    def create_doc_tab_populate_combobox(self):
        """
        Creates the supporting document component widget.
        """
        self.doc_tab_data()
        self.docs_tab = QTabWidget()
        self.docs_tab_index = OrderedDict()
        for i, (id, doc) in enumerate(self.doc_types.items()):
            self.docs_tab_index[doc] = i
            # the tab widget containing the document widget layout
            # and the child of the tab.
            tab_widget = QWidget()
            tab_widget.setObjectName(doc)
            # The layout of the tab widget
            cont_layout = QVBoxLayout(tab_widget)
            cont_layout.setObjectName('widget_layout_{}'.format(doc))
            # the scroll area widget inside the tab widget.
            scroll_area = QScrollArea(tab_widget)
            scroll_area.setFrameShape(QFrame.NoFrame)
            scroll_area.setObjectName('tab_scroll_area_{}'.format(doc))

            layout_widget = QWidget()
            # the widget the is under the scroll area content and
            # the widget containing the document widget layout
            # This widget is hidden and shown based on the STR number
            layout_widget.setObjectName('widget_{}'.format(doc))

            doc_widget_layout = QVBoxLayout(layout_widget)
            doc_widget_layout.setObjectName('doc_widget_layout_{}'.format(doc))
            doc_widget = QWidget()
            doc_widget.setObjectName('doc_widget_{}_{}'.format(
                doc, self.str_number))

            doc_widget_layout.addWidget(doc_widget)

            # the layout containing document widget.
            ### This is the layout that is registered to add uploaded
            # supporting documents widgets into.
            tab_layout = QVBoxLayout(doc_widget)
            tab_layout.setObjectName('layout_{}_{}'.format(
                doc, self.str_number))

            scroll_area.setWidgetResizable(True)
            scroll_area.setWidget(layout_widget)

            cont_layout.addWidget(scroll_area)
            # Add the tab widget with the document
            # type name to create a tab.
            self.docs_tab.addTab(tab_widget, doc)

            self.container_box.addWidget(self.docs_tab, 1)
            if len(self.str_numbers) == 1:
                self.doc_type_cbo.addItem(doc, id)

    def doc_tab_data(self):
        """
        Sets the document types in the social tenure entity.
        """
        doc_entity = self.social_tenure. \
            supporting_doc.document_type_entity
        doc_type_model = entity_model(doc_entity)
        docs = doc_type_model()
        doc_type_list = docs.queryObject().all()
        self.doc_types = [(doc.id, doc.value) for doc in doc_type_list]
        self.doc_types = OrderedDict(self.doc_types)

    def match_doc_combo_to_tab(self):
        """
        Changes the active tab based on the
        selected value of document type combobox.
        """
        combo_text = self.doc_type_cbo.currentText()
        if combo_text is not None and len(combo_text) > 0:
            index = self.docs_tab_index[combo_text]
            self.docs_tab.setCurrentIndex(index)

    def match_doc_tab_to_combo(self):
        """
        Changes the document type combobox value based on the
        selected tab.
        """
        doc_tab_index = self.docs_tab.currentIndex()
        self.doc_type_cbo.setCurrentIndex(doc_tab_index)

    @staticmethod
    def hide_doc_widgets(widget, visibility):
        """
        Hides or shows the visibility of the supporting document
        container widgets.
        :param widget: The widget to which the visibility is set.
        :type widget: QWidget
        :param visibility: A boolean to show or hide visibility.
        True hides widget and False shows it.
        :type visibility: Boolean
        """
        widget.setHidden(visibility)

    def update_container(self, str_number):
        """
        Update the current supporting document widget container to be used.
        :param str_number: The STR node number
        :type str_number: Integer
        """
        doc_text = self.doc_type_cbo.currentText()
        cbo_index = self.doc_type_cbo.currentIndex()
        doc_id = self.doc_type_cbo.itemData(cbo_index)
        scroll_area = self.docs_tab.findChild(
            QScrollArea, 'tab_scroll_area_{}'.format(doc_text, str_number))
        doc_widget = scroll_area.findChild(
            QWidget, 'doc_widget_{}_{}'.format(doc_text, str_number))
        # If the doc widget doesn't exist create it for new STR instance
        if doc_widget is None:
            # find the doc_widget layout that contains
            # all STR doc widget layouts. Single
            # doc_widget_layout is created for each document type.
            # But all doc_widgets for each STR instance and
            # document types will be added here.
            doc_widget_layout = scroll_area.findChild(
                QVBoxLayout, 'doc_widget_layout_{}'.format(doc_text))

            doc_widget = QWidget()
            doc_widget.setObjectName('doc_widget_{}_{}'.format(
                doc_text, str_number))
            self.hide_all_other_widget(doc_text, str_number)
            doc_widget_layout.addWidget(doc_widget)
            # Create the layout so that layouts are registered in
            # which uploaded document widgets are added.
            layout = QVBoxLayout(doc_widget)
            layout.setObjectName('layout_{}_{}'.format(doc_text, str_number))
        # If the doc widget exists, get the lowest
        # layout so that it is registered.
        else:
            # hide all other widgets
            self.hide_all_other_widget(doc_text, str_number)
            # show the current doc widget to display
            # the document widgets for the current tab.
            self.hide_doc_widgets(doc_widget, False)
            layout = doc_widget.findChild(
                QVBoxLayout, 'layout_{}_{}'.format(doc_text, str_number))
        # register layout
        self.supporting_doc_manager.registerContainer(layout, doc_id)

    def hide_all_other_widget(self, doc_text, str_number):
        """
        Hides all other supporting document widget except the current
        STR node widget.
        :param doc_text: The current document type selected.
        :type doc_text: String
        :param str_number: The STR node number
        :type str_number: Integer
        """
        expression = QRegExp('doc_widget*')
        # hide all existing widgets in all layouts
        for widget in self.docs_tab.findChildren(QWidget, expression):
            if widget.objectName() != 'doc_widget_{}_{}'.format(
                    doc_text, str_number):
                self.hide_doc_widgets(widget, True)

    def on_upload_document(self):
        '''
        Slot raised when the user clicks
        to upload a supporting document.
        '''
        document_str = QApplication.translate(
            "SupportingDocuments", "Specify the Document File Location")
        documents = self.select_file_dialog(document_str)

        cbo_index = self.doc_type_cbo.currentIndex()
        doc_id = self.doc_type_cbo.itemData(cbo_index)

        for doc in documents:
            self.supporting_doc_manager.insertDocumentFromFile(
                doc, doc_id, self.social_tenure, self.current_party_count)

        # Set last path
        if len(documents) > 0:
            doc = documents[0]
            fi = QFileInfo(doc)
            dir_path = fi.absolutePath()
            set_last_document_path(dir_path)

            model_objs = self.supporting_doc_manager.model_objects()
            self.onUploadDocument.emit(model_objs)

    def select_file_dialog(self, title):
        """
        Displays a file dialog for a user to specify a source document
        :param title: The title of the file dialog
        :type title: String
        """
        # Get last path for supporting documents
        last_path = last_document_path()
        if last_path is None:
            last_path = '/home'

        files, _ = QFileDialog.getOpenFileNames(
            iface.mainWindow(), title, last_path,
            "Source Documents (*.jpg *.jpeg *.png *.bmp *.tiff *.svg)")
        return files
Esempio n. 3
0
class InspectionForm(FeatureForm):
    def __init__(self, *args, **kwargs):
        super(InspectionForm, self).__init__(*args, **kwargs)
        self.inspectionforms = []
        self.joinkey = 'insp_loc_id'
        self.mapkeycolumn = 'mapkey'
        self.inspectionformname = 'inspection_data'
        self.countcolum = 'number'

    def uisetup(self):
        """
        Called when the UI is fully constructed.  You should connect any signals here.
        """
        if self.formconfig['type'] == 'auto':
            self.AddInspectionButton = QPushButton()
            self.inspectiontabs = QTabWidget()
            self.layout().addRow(self.AddInspectionButton)
            self.layout().addRow(self.inspectiontabs)

        self.AddInspectionButton.pressed.connect(self.create_new_inspection)

    def load(self, feature, layers, values):
        """
        Called before the form is loaded. This method can be used to do pre checks and halt the loading of the form
        if needed.

        Calling self.cnacelload("Your message") will stop the opening of the form and show the message to the user.

            >>> self.cancelload("Sorry you can't load this form now")

        You may alter the values given in the values dict. It will be passed to the form after this method returns.
        """

        project = self.form.project
        self.inspectionform = project.form_by_name(self.inspectionformname)
        inspectionlayer = self.inspectionform.QGISLayer

        self.AddInspectionButton.setText("Add {}".format(
            self.inspectionform.label))
        self.AddInspectionButton.setIcon(QIcon(self.inspectionform.icon))
        if not self.is_capturing:
            inspections = self.find_inspections(self.feature)
            self.load_inspections(inspections, mapkeycolumn=self.mapkeycolumn)

    def find_inspections(self, feature):
        """
        Override to return the inspections for this form forms feature.
        :param feature:
        :return:
        """
        return []

    def load_inspections(self, inspections, mapkeycolumn):
        """
        Load the given inspections into the form
        :param inspections:
        :param mapkeycolumn:
        :return:
        """
        inspectionlayer = self.inspectionform.QGISLayer
        for inspection in inspections:
            mapkey = inspection['mapkey']
            inspectionfeature = feature_by_key(inspectionlayer, mapkey)
            self._add_inspectionform(inspectionfeature,
                                     editing=True,
                                     label=self.inspectionform.label)

    def create_new_inspection(self):
        """
        Create a new inspection feature and add it to the form
        :return:
        """
        feature = self.inspectionform.new_feature()
        # Give the new feature the key from the parent
        feature[self.joinkey] = self.bindingvalues[self.joinkey]
        self._add_inspectionform(feature,
                                 editing=False,
                                 label=self.inspectionform.label)

    def _add_inspectionform(self, feature, editing=False, label=''):
        """
        Add a new inspection form for the given feature.
        :param feature: The feature to bind to the form
        :param editing: True to set the form into edit mode.
                        False edit mode will add a new feature on save.
        """
        count = len(self.inspectionforms) + 1
        # Increase the inspection count for this feature
        feature[self.countcolum] = count

        # Create a new inspection form widget
        featureform = self.inspectionform.create_featureform(feature,
                                                             editmode=editing)
        featureform.helprequest.connect(self.helprequest.emit)

        # Extract the values from the feature
        values = self.inspectionform.values_from_feature(feature)
        # Bind the values to the feature form
        featureform.bindvalues(values)

        # Add the tab and set the icon
        icon = QIcon(self.inspectionform.icon)
        self._add_tab(featureform, "{label} {count}".format(label=label,
                                                            count=count), icon)

        # If the current count is over the max number of inspections then set the
        # button to disabled so we can't add anymore
        if count >= self.formconfig.get('maxinspections', 2):
            self.AddInspectionButton.setText("Max Inspections")
            self.AddInspectionButton.setEnabled(False)

    def _add_tab(self, widget, name, icon):
        """
        Adds a tab to the tab widget with the given widget, name, and icon.
        :param widget: The widget to add to the tab
        :param name: The name of the tab
        :param icon: The icon of the tab
        """
        index = self.inspectiontabs.addTab(widget, name)
        self.inspectionforms.append(widget)
        self.inspectiontabs.setCurrentIndex(index)
        self.inspectiontabs.setTabIcon(index, icon)

    def save(self):
        """
        Override of the save logic for the feature form

        We override the save logic because we are not saving to the property layer but to the
        InspectionLocation table
        """
        # Save all sub forms
        for subform in self.inspectionforms:
            subform.save()
Esempio n. 4
0
class SupportingDocumentsWidget(QWidget):
    """
    Widget for managing an entity's supporting documents. It enables listing
    of documents grouped by tabs depending on type.
    """
    def __init__(self,
                 entity_supporting_document,
                 supporting_doc_model_cls,
                 parent=None):
        """
        Class constructor.
        :param entity_supporting_document: Object containing information
        pertaining to document types, parent entity etc.
        :type entity_supporting_document: EntitySupportingDocument
        :param supporting_doc_model_cls: Class representing the data model
        corresponding to the entity supporting document object.
        :type supporting_doc_model_cls: object
        :param parent: Parent container widget.
        :type parent: QWidget
        """
        QWidget.__init__(self, parent)

        self._init_gui()

        self._entity_supporting_doc = entity_supporting_document

        # Container for document type widgets based on lookup id
        self._doc_type_widgets = {}

        # Init document manager
        self.source_document_manager = SourceDocumentManager(
            self._entity_supporting_doc, supporting_doc_model_cls, self)

        self._load_document_types()

        # Connect signals
        self._btn_add_document.clicked.connect(
            self._on_add_supporting_document)
        self._cbo_doc_type.currentIndexChanged.connect(
            self.on_doc_type_changed)
        self._doc_tab_container.currentChanged.connect(
            self.on_tab_doc_type_changed)

    def _init_gui(self):
        self._gl = QGridLayout(self)
        self._label = QLabel(self)
        self._label.setText(self.tr('Select document type'))
        self._gl.addWidget(self._label, 0, 0, 1, 1)
        self._cbo_doc_type = QComboBox(self)
        self._gl.addWidget(self._cbo_doc_type, 0, 1, 1, 1)
        self._btn_add_document = QPushButton(self)
        doc_ico = GuiUtils.get_icon('document.png')
        self._btn_add_document.setIcon(doc_ico)
        self._btn_add_document.setText(self.tr('Add document...'))
        self._btn_add_document.setMaximumWidth(200)
        self._gl.addWidget(self._btn_add_document, 0, 2, 1, 1)
        self._doc_tab_container = QTabWidget(self)
        self._gl.addWidget(self._doc_tab_container, 1, 0, 1, 3)

        self.setMinimumHeight(140)

    def on_doc_type_changed(self, idx):
        """
        Slot raised when the document types changes. The corresponding
        widget in the tab container is also selected.
        :param idx: Item index in the combobox.
        :type idx: int
        """
        if idx == -1:
            return

        self._doc_tab_container.setCurrentIndex(idx)

    def on_tab_doc_type_changed(self, idx):
        """
        Slot raised when the document types changes. The corresponding
        widget in the tab container is also selected.
        :param idx: Item index in the tab widget.
        :type idx: int
        """
        if idx == -1:
            return

        self._cbo_doc_type.setCurrentIndex(idx)

    def current_document_type(self):
        """
        :return: Returns the currently selected document type in the combobox.
        :rtype: str
        """
        return self._cbo_doc_type.currentText()

    def current_document_type_id(self):
        """
        :return: Returns the primary key/id of the currently selected
        document type in the combobox, else -1 if there is not current
        item in the combobox
        :rtype: int
        """
        if not self.current_document_type():
            return -1

        curr_idx = self._cbo_doc_type.currentIndex()

        return self._cbo_doc_type.itemData(curr_idx)

    def count(self):
        """
        :return: Returns the number of document types supported by this
        widget.
        :rtype: int
        """
        return self._cbo_doc_type.count()

    def document_type_containers(self):
        """
        :return: Returns a list of document container widgets for all
        registered document types.
        :rtype: list
        """
        return list(self.source_document_manager.containers.values())

    def document_type_widget(self, name):
        """
        Searches for the document type widget that corresponds to the given
        name.
        :param name: Name of the document type.
        :type name: str
        :return: Returns the document widget corresponding to the given type
        name.
        :rtype: QWidget
        """
        idx = self._cbo_doc_type.findText(name)

        if idx == -1:
            return None

        rec_id = self._cbo_doc_type.itemData(idx)

        return self._doc_type_widgets.get(rec_id, None)

    def _load_document_types(self):
        # Load document types in the combobox and tab widget
        vl_cls = entity_model(self._entity_supporting_doc.document_type_entity,
                              entity_only=True)

        vl_obj = vl_cls()
        res = vl_obj.queryObject().all()
        for r in res:
            # Add to combo
            self._cbo_doc_type.addItem(r.value, r.id)

            # Add to tab widget
            doc_type_widget = _DocumentTypeContainer(self)
            self._doc_tab_container.addTab(doc_type_widget, r.value)
            self._doc_type_widgets[r.id] = doc_type_widget

            # Register container
            self.source_document_manager.registerContainer(
                doc_type_widget.container, r.id)

    def _on_add_supporting_document(self):
        # Slot raised when the user select to add a supporting document
        if self.count == 0:
            return

        select = self.tr('Select')
        supporting_docs_str = 'Supporting Documents'
        title = '{0} {1} {2}'.format(select, self.current_document_type(),
                                     supporting_docs_str)

        filter_str = '{0} (*.jpg *.jpeg *.png *.bmp *.tiff *.svg *.pdf)'.format(
            supporting_docs_str)

        # Get last path for supporting documents
        last_path = last_document_path()
        if last_path is None:
            last_path = '/home'

        else:
            dir = QDir(last_path)
            if not dir.exists():
                last_path = '/home'

        source_docs, _ = QFileDialog.getOpenFileNames(self, title, last_path,
                                                      filter_str)

        doc_type_id = self._cbo_doc_type.itemData(
            self._cbo_doc_type.currentIndex())
        parent_entity = self._entity_supporting_doc.parent_entity

        for doc in source_docs:
            self.source_document_manager.insertDocumentFromFile(
                doc, doc_type_id, parent_entity)

        # Set last path
        if len(source_docs) > 0:
            doc = source_docs[0]
            fi = QFileInfo(doc)
            dir_path = fi.absolutePath()
            set_last_document_path(dir_path)
Esempio n. 5
0
class DebuggerWidget(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.setWindowTitle("First Aid - Debugger")

        self.text_edits = {}  # fully expanded path of the file -> associated SourceWidget
        self.toolbar = self.addToolBar("General")
        self.toolbar.setObjectName("ToolbarGeneral")

        self.tab_widget = QTabWidget()
        self.tab_widget.setTabsClosable(True)
        self.tab_widget.tabCloseRequested.connect(self.on_tab_close_requested)
        self.tab_widget.currentChanged.connect(self.on_pos_changed)

        self.setCentralWidget(self.tab_widget)

        _icon = lambda x: QIcon(os.path.join(os.path.dirname(__file__), "icons", x + ".svg"))

        self.action_load = self.toolbar.addAction(_icon("folder-outline"), "Load Python file (Ctrl+O)", self.on_load)
        self.action_load.setShortcut("Ctrl+O")
        self.action_run = self.toolbar.addAction(_icon("run"), "Run Python file (Ctrl+R)", self.on_run)
        self.action_run.setShortcut("Ctrl+R")
        self.action_bp = self.toolbar.addAction(_icon("record"), "Toggle breakpoint (F9)", self.on_toggle_breakpoint)
        self.action_bp.setShortcut("F9")
        self.toolbar.addSeparator()
        self.action_continue = self.toolbar.addAction(_icon("play"), "Continue (F5)", self.on_continue)
        self.action_continue.setShortcut("F5")
        self.action_step_into = self.toolbar.addAction(_icon("debug-step-into"), "Step into (F11)", self.on_step_into)
        self.action_step_into.setShortcut("F11")
        self.action_step_over = self.toolbar.addAction(_icon("debug-step-over"), "Step over (F10)", self.on_step_over)
        self.action_step_over.setShortcut("F10")
        self.action_step_out = self.toolbar.addAction(_icon("debug-step-out"), "Step out (Shift+F11)", self.on_step_out)
        self.action_step_out.setShortcut("Shift+F11")
        self.action_run_to_cursor = self.toolbar.addAction(_icon("cursor-default-outline"), "Run to cursor (Ctrl+F10)",
                                                           self.on_run_to_cursor)
        self.action_run_to_cursor.setShortcut("Ctrl+F10")

        self.vars_view = VariablesView()
        self.frames_view = FramesView()

        self.dock_frames = QDockWidget("Frames", self)
        self.dock_frames.setObjectName("DockFrames")
        self.dock_frames.setWidget(self.frames_view)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.dock_frames)

        self.dock_vars = QDockWidget("Variables", self)
        self.dock_vars.setObjectName("DockVariables")
        self.dock_vars.setWidget(self.vars_view)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.dock_vars)

        self.resize(800, 800)

        self.debugger = Debugger(self)

        self.update_buttons()

        settings = QSettings()
        self.restoreGeometry(settings.value("/plugins/firstaid/debugger-geometry", b''))
        self.restoreState(settings.value("/plugins/firstaid/debugger-windowstate", b''))

        filenames = settings.value("/plugins/firstaid/debugger-files", [])
        if filenames is None:
            filenames = []

        # load files from previous session
        for filename in filenames:
            self.load_file(filename)

        if self.tab_widget.count() > 1:
            self.tab_widget.setCurrentIndex(0)

        # start tracing
        self.start_tracing()

    def start_tracing(self):
        """ called from constructor or when the debugger window is opened again """
        sys.settrace(self.debugger.trace_function)

    def closeEvent(self, event):

        # disable tracing
        sys.settrace(None)

        settings = QSettings()
        settings.setValue("/plugins/firstaid/debugger-geometry", self.saveGeometry())
        settings.setValue("/plugins/firstaid/debugger-windowstate", self.saveState())

        filenames = list(self.text_edits.keys())
        settings.setValue("/plugins/firstaid/debugger-files", filenames)

        QMainWindow.closeEvent(self, event)

    def load_file(self, filename):
        filename = os.path.normpath(os.path.realpath(filename))

        if filename in self.text_edits:
            self.switch_to_file(filename)
            return  # already there...
        try:
            self.text_edits[filename] = SourceWidget(filename)
        except IOError:
            # TODO: display warning we failed to read the file
            return
        tab_text = os.path.basename(filename)
        self.tab_widget.addTab(self.text_edits[filename], tab_text)
        self.tab_widget.setTabToolTip(self.tab_widget.count() - 1, filename)
        self.tab_widget.setCurrentWidget(self.text_edits[filename])
        self.text_edits[filename].cursorPositionChanged.connect(self.on_pos_changed)
        self.on_pos_changed()

    def switch_to_file(self, filename):
        if filename in self.text_edits:
            self.tab_widget.setCurrentWidget(self.text_edits[filename])

    def unload_file(self, filename):
        for index in range(self.tab_widget.count()):
            if self.text_edits[filename] == self.tab_widget.widget(index):
                self.tab_widget.removeTab(index)
                del self.text_edits[filename]
                break

    def get_file_name(self, args):
        if isinstance(args, tuple):
            return args[0]
        elif isinstance(args, str):
            return args

        return ""


    def on_load(self):

        settings = QSettings()
        folder = settings.value("firstaid/lastFolder", '')

        args = QFileDialog.getOpenFileName(self, "Load", folder, "Python files (*.py)")
        filename = self.get_file_name(args)
        if not filename: return 

        settings.setValue("firstaid/lastFolder", os.path.dirname(filename))
        self.load_file(filename)

    def on_tab_close_requested(self, index):
        self.unload_file(self.tab_widget.widget(index).filename)

    def on_pos_changed(self):
        if not self.current_text_edit():
            self.statusBar().showMessage("[no file]")
            return
        c = self.current_text_edit().textCursor()
        line = c.blockNumber() + 1
        col = c.positionInBlock() + 1
        self.statusBar().showMessage("%d:%d" % (line, col))

    def on_run(self):
        globals = None
        locals = None
        if globals is None:
            import __main__
            globals = __main__.__dict__
        if locals is None:
            locals = globals
        execfile(self.tab_widget.currentWidget().filename, globals, locals)

    def current_text_edit(self):
        return self.tab_widget.currentWidget()

    def on_toggle_breakpoint(self):
        if self.current_text_edit():
            self.current_text_edit().toggle_breakpoint()

    def update_buttons(self):
        active = self.debugger.stopped
        self.action_step_into.setEnabled(active)
        self.action_step_over.setEnabled(active)
        self.action_step_out.setEnabled(active)
        self.action_run_to_cursor.setEnabled(active)
        self.action_continue.setEnabled(active)

    def on_step_into(self):
        self.debugger.stepping = True
        self.debugger.next_step = None
        self.debugger.ev_loop.exit(0)

    def on_step_over(self):
        self.debugger.stepping = True
        self.debugger.next_step = (
        'over', self.debugger.current_frame.f_code.co_filename, self.debugger.current_frame.f_lineno)
        self.debugger.ev_loop.exit(0)

    def on_step_out(self):
        self.debugger.stepping = True
        self.debugger.next_step = ('out', frame_depth(self.debugger.current_frame))
        self.debugger.ev_loop.exit(0)

    def on_run_to_cursor(self):
        self.debugger.stepping = True
        filename = self.tab_widget.currentWidget().filename
        line_no = self.tab_widget.currentWidget().textCursor().blockNumber() + 1
        self.debugger.next_step = ('at', filename, line_no)
        self.debugger.ev_loop.exit(0)

    def on_continue(self):
        self.debugger.stepping = False
        self.current_text_edit().debug_line = -1
        self.current_text_edit().update_highlight()
        self.vars_view.setVariables({})
        self.frames_view.setTraceback(None)
        self.debugger.ev_loop.exit(0)