class ViewExpensesScreen(QWidget, ListenerNode):
    def __init__(self, listeners_pool, *args, **kwargs):
        super(ViewExpensesScreen, self).__init__(*args, **kwargs)

        self.listeners_pool = listeners_pool
        ListenerNode.__init__(self, 'view-expenses-screen', self.listeners_pool)

        self.classified_expenses_table = None

        self.layout = QVBoxLayout()
        self.setLayout(self.layout)

        self.filter_widget = FilterWidget('classified', listeners_pool)
        self.layout.addWidget(self.filter_widget)

        self.add_table('expenses_raw')
        self.send_event('sum-text', 'show_records_no')

    def add_table(self, table_type):
        if self.classified_expenses_table != None:
            self.layout.removeWidget(self.classified_expenses_table)

        self.classified_expenses_table = ClassifiedExpensesTable(self.listeners_pool, table_type)
        self.classified_expenses_table.refresh_rows()
        self.layout.addWidget(self.classified_expenses_table)
Exemple #2
0
class DownloadPage(QWidget):
    def __init__(self, parent):
        super(DownloadPage, self).__init__()
        self.setMinimumSize(500, 300)
        self.parent = parent
        self.nbDownload = 0
        self.layoutMain = QVBoxLayout(self)
        self.scroll = QScrollArea(self)
        self.scroll.setWidgetResizable(True)
        self.title = QLabel("Téléchargements")
        self.title.setAlignment(Qt.AlignHCenter)
        self.layoutMain.addWidget(self.title)
        self.layoutMain.addWidget(self.scroll)

        self.container = QWidget()
        self.scroll.setWidget(self.container)
        self.layout = QVBoxLayout(self.container)
        self.label = QLabel("Pas de téléchargement")
        self.label.setAlignment(Qt.AlignHCenter)
        self.layout.addWidget(self.label)

    def downloadrequested(self, download):
        if download:
            if download.state() == QWebEngineDownloadItem.DownloadRequested:
                path = QFileDialog.getSaveFileName(self, "Sauver comme",
                                                   download.path())
                if path == "":
                    return
                else:
                    download.setPath(path[0])
                    download.accept()
                    self.add(
                        DownloadWidget(
                            download,
                            self.parent.parent.browserWidget.url().toString(),
                            self.parent.parent))

                    self.show()
            else:
                QMessageBox.warning(self, "ERREUR",
                                    "Le téléchargement n'a pas été demandé.")
        else:
            QMessageBox.warning(self, "ERREUR", "Le téléchargement est nul.")

    def add(self, downloadwidget):
        downloadwidget.downloadSignal.removeClicked.connect(self.remove)
        self.layout.addWidget(downloadwidget)
        self.layout.setAlignment(downloadwidget, Qt.AlignTop)
        self.nbDownload += 1
        if self.nbDownload >= 0:
            self.label.hide()

    def remove(self):
        downloadwidget = self.sender().parent
        self.layout.removeWidget(downloadwidget)
        downloadwidget.deleteLater()
        self.nbDownload -= 1
        if self.nbDownload <= 0:
            self.label.show()
Exemple #3
0
class ArrayRequirementEditor:
    def __init__(self, parent: QWidget, parent_layout: QVBoxLayout,
                 resource_database: ResourceDatabase,
                 requirement: Union[RequirementOr, RequirementAnd]):
        self._editors = []
        self.resource_database = resource_database
        self._array_type = type(requirement)

        self.group_box = QGroupBox(parent)
        self.group_box.setStyleSheet("QGroupBox { margin-top: 2px; }")
        parent_layout.addWidget(self.group_box)
        self.item_layout = QVBoxLayout(self.group_box)
        self.item_layout.setContentsMargins(8, 2, 2, 6)
        self.item_layout.setAlignment(Qt.AlignTop)

        self.new_item_button = QPushButton(self.group_box)
        self.new_item_button.setMaximumWidth(75)
        self.new_item_button.setText("New Row")
        self.new_item_button.clicked.connect(self.new_item)

        for item in requirement.items:
            self._create_item(item)

        self.item_layout.addWidget(self.new_item_button)

    def _create_item(self, item: Requirement):
        def on_remove():
            self._editors.remove(nested_editor)
            nested_editor.deleteLater()

        nested_editor = RequirementEditor(self.group_box,
                                          self.item_layout,
                                          self.resource_database,
                                          on_remove=on_remove)
        nested_editor.create_specialized_editor(item)
        self._editors.append(nested_editor)

    def new_item(self):
        self._create_item(
            _create_default_resource_requirement(self.resource_database))

        self.item_layout.removeWidget(self.new_item_button)
        self.item_layout.addWidget(self.new_item_button)

    def deleteLater(self):
        self.group_box.deleteLater()
        for editor in self._editors:
            editor.deleteLater()
        self.new_item_button.deleteLater()

    @property
    def current_requirement(self) -> Union[RequirementOr, RequirementAnd]:
        return self._array_type(
            [editor.current_requirement for editor in self._editors])
Exemple #4
0
class plotMainWidget(QWidget):
    def __init__(self, controller):
        super(plotMainWidget, self).__init__()
        print("plotMainWidget")
        self.dc = controller
        self.plot = None
        self.filter_groupBox = QGroupBox("Filters")
        self.filter_msg_comboBox = QComboBox()
        self.filter_msg_label = QLabel("Message:")
        self.filter_msg_label.setBuddy(self.filter_msg_comboBox)
        self.filter_msg_comboBox.addItems(plot_msg)
        self.filter_msg_button = QPushButton("Show")
        self.filter_msg_button.clicked.connect(self.filterButtonClicked)

        layout = QGridLayout()
        # layout.setColumnMinimumWidth(9,100)
        # layout.setColumnMinimumWidth(1,30)
        layout.addWidget(self.filter_msg_label, 0, 0)
        layout.addWidget(self.filter_msg_comboBox, 0, 2, 0, 8)
        layout.addWidget(self.filter_msg_button, 0, 10)
        self.filter_groupBox.setLayout(layout)

        self.plot_groupBox = QGroupBox("Chart")

        mainLayout = QGridLayout()
        mainLayout.addWidget(self.filter_groupBox, 0, 0)
        mainLayout.addWidget(self.plot_groupBox, 1, 0, 9, 0)
        self.setLayout(mainLayout)

    def filterButtonClicked(self):
        msg = self.filter_msg_comboBox.currentText()
        data_set = self.dc.getDataSet(msg)
        time_axis = []
        val_axis = []
        for i in data_set:
            time_axis.append(i[3])
            val_axis.append(i[4])

        self.plot = MyMplCanvas(time_axis, val_axis)
        self.curr_plot_layout = QVBoxLayout()
        self.curr_plot_layout.addWidget(self.plot)
        self.plot_groupBox.setLayout(self.curr_plot_layout)

    def cleanPlot(self):
        if (self.plot):
            print("clean")
            self.curr_plot_layout.removeWidget(self.plot)
Exemple #5
0
class _NotificationWidget(QWidget):
    def __init__(self, parent: QWidget = None):
        time = datetime.now()
        currentTime = str(time.hour) + ":" + str(time.minute) + "_"
        self.LOG_TAG = currentTime + self.__class__.__name__ + ": "
        super().__init__(parent)

        self.setWindowFlags(Qt.FramelessWindowHint | Qt.Tool)
        self.nMessages = 0
        self.mainLayout = QVBoxLayout(self)

    def updatePosition(self) -> None:
        parentOrigin = self.parentWidget().pos()
        parentSize = self.parentWidget().size()
        # Move in bottom right corner
        self.move(parentOrigin.x() + parentSize.width() - self.width(),
                  parentOrigin.y() + parentSize.height() - self.height())

    def setNotify(self, title, message, icon):
        m = _Message(title, message, icon, self)
        self.mainLayout.addWidget(m)
        m.buttonClose.clicked.connect(self.onClicked)
        self.nMessages += 1
        if not self.isVisible():
            self.show()
        m.show()
        self.adjustSize()
        self.updatePosition()

    def showEvent(self, event: QtGui.QShowEvent) -> None:
        if self.nMessages > 0:
            super().showEvent(event)

    @Slot()
    def onClicked(self):
        self.mainLayout.removeWidget(self.sender().parent())
        self.sender().parent().deleteLater()
        self.nMessages -= 1
        self.adjustSize()
        self.updatePosition()
        if self.nMessages == 0:
            self.hide()
Exemple #6
0
    def testDeleteMultipleInheritance(self):
        app = QApplication(sys.argv)

        class DerivedLabel(QLabel, QObject):
            def __del__(self):
                global is_alive
                is_alive = False

        global is_alive
        child = DerivedLabel('Hello')
        is_alive = True
        parent = QVBoxLayout()
        parent.addWidget(child)
        parent.removeWidget(child)
        child.deleteLater()
        self.assertTrue(is_alive)
        del child
        self.assertTrue(is_alive)
        QTimer.singleShot(100, app.quit)
        app.exec_()
        self.assertFalse(is_alive)
Exemple #7
0
class HackerNewsWidget(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.widgets = []

        self.layout = QVBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        self.setLayout(self.layout)

        OverviewSignal.changed.connect(self.render)
        self.render()

    def render(self, url=''):
        spider = HackerNewsSpider()
        spider.crawl(url)
        for widget in self.widgets:
            self.layout.removeWidget(widget)
            widget.setParent(None)
        for item in spider.contents:
            child_widget = HackerNewsItemWidget(self, item)
            self.widgets.append(child_widget)
            self.layout.addWidget(child_widget)

    def set_active_item(self, id):
        for child in self.widgets:
            if child.item['id'] == id:
                child.setStyleSheet("""
                    HackerNewsItemWidget {
                        border-left: 3px solid #ff6600;
                    }
                    HackerNewsItemWidget #title {
                        color: #fff;
                    }
                    """)
            else:
                child.setStyleSheet('')
Exemple #8
0
class SubtableWidget(QWidget):
    def __init__(self, subtable, parent=None):
        super().__init__(parent)
        self.subtable = subtable
        self.subtable.setSelectionMode(QAbstractItemView.SingleSelection)
        self.subtable.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.subtable.clicked.connect(self.row_selected)
        self.selected_row = 0

        self.package = QVBoxLayout()

        self.toolBar = QToolBar()
        self.toolBar.setMovable(True)

        sub_up = QAction(
            QIcon("view/images/toolbar/baseline_expand_less_black_48dp.png"),
            "Up", self.subtable)
        sub_up.setStatusTip("Move one up")
        sub_up.triggered.connect(self.sub_up)

        sub_down = QAction(
            QIcon("view/images/toolbar/baseline_expand_more_black_48dp.png"),
            "Down", self.subtable)
        sub_down.setStatusTip("Move one down")
        sub_down.triggered.connect(self.sub_down)

        sub_first = QAction(
            QIcon("view/images/toolbar/baseline_first_page_black_48dp.png"),
            "Jump to first", self.subtable)
        sub_first.setStatusTip("Jump to first")
        sub_first.triggered.connect(self.sub_first)

        sub_last = QAction(
            QIcon("view/images/toolbar/baseline_last_page_black_48dp.png"),
            "Jump to last", self.subtable)
        sub_last.setStatusTip("Jump to last")
        sub_last.triggered.connect(self.sub_last)

        self.toolBar.addAction(QIcon("view/images/toolbar/list_48px.png"),
                               "Manage Data")
        self.toolBar.addAction(QIcon("view/images/toolbar/add_new_40px.png"),
                               "Add Data")
        self.toolBar.addAction(sub_first)
        self.toolBar.addAction(sub_up)
        self.toolBar.addAction(sub_down)
        self.toolBar.addAction(sub_last)
        self.toolBar.addAction(
            QIcon("view/images/toolbar/close_window_26px.png"), "Close")

        self.manageData2 = ManageData(self.subtable)

        self.addData2 = AddData(self.subtable)
        self.label = QLabel()
        self.label.setText("Work with data, choose state.")

        self.stacked_layout_2 = QVBoxLayout()
        self.stacked_layout_2.addStretch(0)

        self.toolBar.actionTriggered.connect(self.sub_toolbar_actions)

        self.package.addWidget(self.toolBar)
        self.package.addLayout(self.stacked_layout_2)
        self.package.addWidget(self.subtable)

        self.setLayout(self.package)

    def sub_toolbar_actions(self, action):
        if action.iconText() == "Manage Data":
            if self.stacked_layout_2.indexOf(
                    self.addData2) == -1 and self.stacked_layout_2.indexOf(
                        self.manageData2
                    ) == -1 and self.stacked_layout_2.indexOf(
                        self.label) == -1:
                self.stacked_layout_2.addWidget(self.manageData2)
                self.manageData2.setVisible(True)
                return
            if self.stacked_layout_2.indexOf(self.addData2) != -1:
                self.stacked_layout_2.removeWidget(self.addData2)
                self.addData2.setVisible(False)
                self.stacked_layout_2.addWidget(self.manageData2)
                self.manageData2.setVisible(True)
                return
            if self.stacked_layout_2.indexOf(self.label) != -1:
                self.stacked_layout_2.removeWidget(self.label)
                self.label.setVisible(False)
                self.stacked_layout_2.addWidget(self.manageData2)
                self.manageData2.setVisible(True)
                return
            return

        elif action.iconText() == "Add Data":
            if self.stacked_layout_2.indexOf(
                    self.addData2) == -1 and self.stacked_layout_2.indexOf(
                        self.manageData2
                    ) == -1 and self.stacked_layout_2.indexOf(
                        self.label) == -1:
                self.stacked_layout_2.addWidget(self.addData2)
                self.addData2.setVisible(True)
                return
            if self.stacked_layout_2.indexOf(self.manageData2) != -1:
                self.stacked_layout_2.removeWidget(self.manageData2)
                self.manageData2.setVisible(False)
                self.stacked_layout_2.addWidget(self.addData2)
                self.addData2.setVisible(True)
                return
            if self.stacked_layout_2.indexOf(self.label) != -1:
                self.stacked_layout_2.removeWidget(self.label)
                self.label.setVisible(False)
                self.stacked_layout_2.addWidget(self.addData2)
                self.addData2.setVisible(True)
                return
            return

        elif action.iconText() == "Close":
            if self.stacked_layout_2.indexOf(
                    self.addData2) == -1 and self.stacked_layout_2.indexOf(
                        self.manageData2
                    ) == -1 and self.stacked_layout_2.indexOf(
                        self.label) == -1:
                self.stacked_layout_2.addWidget(self.label)
                self.label.setVisible(True)
                return
            if self.stacked_layout_2.indexOf(self.addData2) != -1:
                self.stacked_layout_2.removeWidget(self.addData2)
                self.addData2.setVisible(False)
                self.stacked_layout_2.addWidget(self.label)
                self.label.setVisible(True)
                return
            if self.stacked_layout_2.indexOf(self.manageData2) != -1:
                self.stacked_layout_2.removeWidget(self.manageData2)
                self.manageData2.setVisible(False)
                self.stacked_layout_2.addWidget(self.label)
                self.label.setVisible(True)
                return
            return

    def row_selected(self, index):
        self.selected_row = index.row()

    def sub_up(self):
        if self.selected_row != 0:
            self.selected_row -= 1
            self.subtable.selectRow(self.selected_row)

    def sub_down(self):
        if self.selected_row < len(self.subtable.model().displayed_d) - 1:
            self.selected_row += 1
            self.subtable.selectRow(self.selected_row)

    def sub_first(self):
        self.selected_row = 0
        self.subtable.selectRow(self.selected_row)

    def sub_last(self):
        self.selected_row = len(self.subtable.model().displayed_d) - 1
        self.subtable.selectRow(self.selected_row)
Exemple #9
0
class ProcessListWidget(QScrollArea):
    action_requested = Signal(str, str)
    process_state_changed = Signal(str, str)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.process_data = set()
        self.process_widget_map = {}  # type: Dict[str, ProcessWidget]

        self.main_widget = QWidget()
        self.process_layout = QVBoxLayout()
        self.process_layout.setContentsMargins(2, 2, 2, 2)
        self.main_widget.setLayout(self.process_layout)

        self.lbl_default = QLabel(text="No processes found")
        self.process_layout.addWidget(self.lbl_default)
        self.process_layout.addStretch()

        # Configure ScrollArea
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.setWidgetResizable(True)
        self.setWidget(self.main_widget)
        self.setSizePolicy(QSizePolicy.MinimumExpanding,
                           QSizePolicy.MinimumExpanding)

    def on_action_completed(self, response: ActionResponse):
        logger.info("Action completed: %s", response)
        self.process_widget_map[response.uid].on_action_completed(
            response.action)

    def update_single_process_state(self, event: StateChangedEvent):
        self.process_widget_map[event.uid].update_state(
            event.state, event.exit_code)

    def update_process_data(self, updated_process_data: Set[ProcessData]):
        potentially_updated = set()
        for process_data in updated_process_data:
            if process_data in self.process_data:
                potentially_updated.add(process_data)

        new_processes = updated_process_data - self.process_data
        unknown_processes = self.process_data - updated_process_data
        print(potentially_updated, new_processes, unknown_processes)
        # TODO(mark): update process data sets with new data
        for known_process in potentially_updated:
            widget = self.process_widget_map[known_process.uid]
            widget.on_update_process_data(known_process)

        for new_process in new_processes:
            widget = ProcessWidget(new_process)
            self.process_widget_map[new_process.uid] = widget
            widget.actionRequested.connect(self.action_requested)
            widget.process_state_changed.connect(self.process_state_changed)
            self.process_layout.insertWidget(0, widget)

        # TODO(mark): unknown processes
        for process in unknown_processes:
            widget = self.process_widget_map[process.uid]
            logger.info("Removing widget: %s", process.uid)
            self.process_layout.removeWidget(widget)
            del self.process_widget_map[process.uid]
            widget.deleteLater()

        self.process_data = new_processes | potentially_updated
        self.lbl_default.setVisible(len(self.process_data) == 0)

        return new_processes, unknown_processes
Exemple #10
0
class MainPage(QMainWindow):

    activePackageWidgets = None

    def __init__(self):
        QMainWindow.__init__(self, MaxPlus.GetQMaxMainWindow())
        self.resize(800, 600)
        self.setWindowTitle("Max Tools Updater")
        self.mainWidget = QWidget(self)
        self.central_layout = QVBoxLayout()
        menu_bar = QMenuBar()
        settingAct = QAction("&Settings", self)
        settingAct.setStatusTip("Open setting window")
        settingAct.connect(SIGNAL("triggered()"), self, SLOT("open()"))
        menu_bar.addAction(settingAct)
        self.mainWidget.setLayout(self.central_layout)
        self.central_layout.addWidget(menu_bar)
        self.tabs = QTabWidget()
        self.setCentralWidget(self.mainWidget)
        self.activePackageWidgets = list()

    def show(self, bringOnTop=None):
        self.loadPackagesTab()
        if bringOnTop:
            self.bringPackageOnTop(bringOnTop)
        QMainWindow.show(self)

    def closeEvent(self, event):
        for packageWidget in self.activePackageWidgets:
            packageWidget.closeQWebEngine()

    def open(self):
        self.settings_window = SettingsPage()
        self.settings_window.show()

    def loadPackagesTab(self):
        for i in range(self.tabs.count()):
            self.tabs.widget(i)
            self.tabs.removeTab(i)

        packagesConfigurationList = configuration.PackageConfiguration.readUserPackages(
        )
        if not packagesConfigurationList:
            self.togglePackagesFoundDialog(True)
        else:
            self.togglePackagesFoundDialog(False)
            self.central_layout.addWidget(self.tabs)
            for i in range(len(packagesConfigurationList)):
                packageConfig = packagesConfigurationList[i]
                package_page = ptw.PackageTabView(packageConfig)
                self.activePackageWidgets.append(package_page)
                if package_page.isValid:
                    self.tabs.addTab(package_page, packageConfig.package_name)
                else:
                    logging.info("package" + packageConfig.package_name +
                                 "is not valid")

    def bringPackageOnTop(self, packageConfig):
        for i in range(self.tabs.count()):
            tab = self.tabs.widget(i)
            if tab.packageConfig.package_name == packageConfig.package_name:
                self.tabs.setCurrentWidget(tab)

    def togglePackagesFoundDialog(self, enabled):
        if enabled:
            no_packages_lbl = QLabel(
                "Ops...No packages found, please add a package from Settings Menu",
                self)
            no_packages_lbl.setAlignment(Qt.AlignHCenter)
            self.central_layout.addWidget(no_packages_lbl)
            no_packages_lbl.setObjectName("No_Package")
        else:
            no_packages_lbl = self.central_layout.findChild(
                QLabel, "No_Package")
            self.central_layout.removeWidget(no_packages_lbl)
Exemple #11
0
class ViewWidget(QWidget):
    exercise_name_label = None
    exercise_name_line = None

    scroll_area = None
    base_widget = None
    exercises_widget = None

    return_button = None

    add_button = None

    def __init__(self):
        QWidget.__init__(self)

        self.file = ""
        self.setup_widget()

    def setup_widget(self):
        self.exercise_name_label = QLabel("Exercise name:", self)
        self.exercise_name_label.move(5, 5)
        self.exercise_name_label.resize(125, 25)

        self.add_button = QPushButton("Add", self)
        self.add_button.resize(75, 25)
        self.add_button.clicked.connect(self.add_line)

        self.exercise_name_line = QLineEdit(self)
        self.exercise_name_line.move(135, 5)
        self.exercise_name_line.resize(125, 25)

        self.scroll_area = QScrollArea(self)
        self.base_widget = QWidget(self)
        self.scroll_area.setWidget(self.base_widget)

        self.exercises_widget = QVBoxLayout()
        self.exercises_widget.setAlignment(Qt.AlignTop)

        self.base_widget.setLayout(self.exercises_widget)

        self.return_button = QPushButton("Return wo save", self)

    def resizeEvent(self, event):
        self.scroll_area.move(5, 35)
        self.scroll_area.resize(self.width() - 165, self.height() - 40)
        self.add_button.move(self.width() - 160 - 75, 5)
        self.return_button.move(self.width() - 155, 5)
        self.return_button.resize(150, 40)

        self.base_widget.resize(self.scroll_area.width() - 25,
                                self.exercises_widget.count() * 25)

    def clear_widget(self):
        while self.exercises_widget.count() > 0:
            self.exercises_widget.takeAt(0)

    def open_exercise_file(self, file: str):
        self.file = file

        with open(self.file, "r") as json_file:
            json_data = json.load(json_file)

            name = json_data['name']

            for data in json_data['exercise']:
                movement = data['name']
                description = data['description']
                time = data['time']

                widget = PanelWidget()
                widget.set_data(movement, description, time)
                widget.remove_signal.connect(self.remove_panel_item)
                widget.move_down_signal.connect(self.move_widget_down)
                widget.move_up_signal.connect(self.move_widget_up)

                self.exercises_widget.addWidget(widget)

            json_file.close()

        self.base_widget.resize(self.scroll_area.width() - 25,
                                self.exercises_widget.count() * 25)

        self.exercise_name_line.setText(name)

    @Slot()
    def add_line(self):
        widget = PanelWidget()
        self.exercises_widget.addWidget(widget)
        self.base_widget.resize(self.scroll_area.width() - 25,
                                self.exercises_widget.count() * 25)

    @Slot(QWidget)
    def move_widget_down(self, widget: QWidget):
        ind = self.exercises_widget.indexOf(widget)
        self.exercises_widget.removeWidget(widget)
        self.exercises_widget.insertWidget((ind + 1), widget)

    @Slot(QWidget)
    def move_widget_up(self, widget: QWidget):
        ind = self.exercises_widget.indexOf(widget)
        self.exercises_widget.removeWidget(widget)
        self.exercises_widget.insertWidget((ind - 1), widget)

    @Slot(QWidget)
    def remove_panel_item(self, widget: QWidget):
        self.exercises_widget.removeWidget(widget)
        self.base_widget.resize(self.scroll_area.width() - 25,
                                self.exercises_widget.count() * 25)
class FilelistWidget(QWidget):
    def __init__(self, parent=None):
        super(FilelistWidget, self).__init__(parent)
        self.setup_settings()
        self.setup_ui()

    def setup_settings(self):
        """Initialize widgets params.
        """
        self.target_dir = './'
        self.re_pattern = '/*\.(jpg|jpeg|png|gif|bmp)'
        self.target_files_path = []
        self.selected_idx = 0

    def setup_ui(self):
        """Initialize widgets.
        """
        # self.select_button = QPushButton("Open dir")
        # self.select_button.clicked.connect(self.select_dir)

        self.list_w = self.setup_list_ui()
        self.filelabel_list = []
        self.filelist_layout = QVBoxLayout()
        # self.filelist_layout.addWidget(self.select_button)
        self.filelist_layout.addWidget(self.list_w)

        self.setLayout(self.filelist_layout)

    def setup_list_ui(self):
        self.filelabel_list = []
        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        list_w = QWidget()
        vbox = QVBoxLayout()
        if self.target_files_path:
            for i, p in enumerate(self.target_files_path):
                label = FileLabelWidget(p, i)
                vbox.addWidget(label)
                self.filelabel_list.append(label)
        else:
            label = QLabel('Please select Directory!')
            vbox.addWidget(label)
        vbox.setAlignment(QtCore.Qt.AlignTop)
        list_w.setLayout(vbox)
        scroll.setWidget(list_w)
        return scroll

    def select_dir(self):
        dir_path = QFileDialog.getExistingDirectory(
            self, 'Select Directory', os.path.expanduser(self.target_dir))
        if dir_path:
            self.target_dir = dir_path
            self.load_files()
            self.init_selected_idx()

    def load_files(self):
        self.target_files_path = path_list(self.target_dir,
                                           path_key='f',
                                           use_re=True,
                                           re_pattern=self.re_pattern)
        self.filelist_layout.removeWidget(self.list_w)
        self.list_w.deleteLater()
        self.list_w = self.setup_list_ui()
        self.filelist_layout.addWidget(self.list_w)

    def get_filepath(self, id):
        if self.target_files_path:
            return self.target_files_path[id]
        else:
            return None

    def get_selected_path(self):
        return self.get_filepath(self.selected_idx)

    def init_selected_idx(self):
        self.selected_idx = 0

    def select_filepath(self, idx=None):
        if idx is None:
            if self.selected_idx != len(self.target_files_path) - 1:
                self.selected_idx += 1
                return self.get_selected_path()
            else:
                return self.get_selected_path()
        else:
            self.selected_idx = idx
            return self.get_selected_path()

    def select_filepath_back(self, idx=None):
        if idx is None:
            if self.selected_idx != 0:
                self.selected_idx -= 1
                return self.get_selected_path()
            else:
                return self.get_selected_path()
        else:
            self.selected_idx = idx
            return self.get_selected_path()
class NotificationsList(QWidget):
    READ_BACKGROUND_COLOR = "white"
    UNREAD_BACKGROUND_COLOR = "#eeeeee"
    WIDGET_BACKGROUND_COLOR = "darkGray"

    def __init__(self, dp, *args, **kwargs):
        QWidget.__init__(self, *args, **kwargs)

        self._dp = dp
        self._items = []
        self._main_layout = QVBoxLayout(self)
        self._main_layout.setSpacing(2)
        self._main_layout.setContentsMargins(0, 0, 0, 0)
        self._main_layout.addStretch()
        self.setStyleSheet('background-color: {};'.format(
            self.READ_BACKGROUND_COLOR))

    def show_notifications(self, notifications):
        items_count = len(self._items)
        for i, notification in enumerate(notifications):
            if i < items_count:
                self._update_n_list_item_widget(notification, self._items[i])
            else:
                self._create_n_list_item_widget(notification)

        for i in range(items_count - 1, len(notifications) - 1, -1):
            self._main_layout.removeWidget(self._items[i])
            self._items.pop()
        self.setStyleSheet('background-color: {};'.format(
            self.WIDGET_BACKGROUND_COLOR))

    def loading_needed(self, limit):
        items_len = len(self._items)
        if items_len < limit:
            return True

        for widget in self._items[-limit:]:
            if not widget.visibleRegion().isEmpty():
                return True

        return False

    def _create_n_list_item_widget(self, notification):
        widget = QWidget(parent=self)
        # widget.setFixedWidth(self.width())
        widget.notification = notification

        main_layout = QVBoxLayout(widget)
        main_layout.setSpacing(2)

        text_label = QLabel(widget)
        widget.text_label = text_label
        text_label.setWordWrap(True)
        text_label.setFont(QFont('Noto Sans', 10 * self._dp))
        text_label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
        text_label.setText(notification.get_text())
        main_layout.addWidget(text_label)

        time_label = QLabel(widget)
        widget.time_label = time_label
        time_label.setFont(QFont('Noto Sans', 8 * self._dp))
        time_label.setAlignment(Qt.AlignTop | Qt.AlignRight)
        time_label.setText(notification.get_datetime())
        main_layout.addWidget(time_label)

        self._set_background_color(widget, notification)

        def clicked(_):
            widget.notification.read()
            self._set_background_color(widget, widget.notification)

        widget.mouseReleaseEvent = clicked
        widget.text_label.mouseReleaseEvent = clicked
        widget.time_label.mouseReleaseEvent = clicked
        self._main_layout.insertWidget(len(self._items), widget)
        self._items.append(widget)

    def _update_n_list_item_widget(self, notification, widget):
        widget.notification = notification
        widget.text_label.setText(notification.get_text())
        widget.time_label.setText(notification.get_datetime())
        self._set_background_color(widget, notification)

    def _set_background_color(self, widget, notification):
        background_color = self.READ_BACKGROUND_COLOR \
            if notification.is_read \
            else self.UNREAD_BACKGROUND_COLOR
        widget.setStyleSheet('background-color: {};'.format(background_color))
Exemple #14
0
class DBWorkspace(QWidget):
    def __init__(self, db, table, parent=None):
        super().__init__(parent)

        self.main_layout = QVBoxLayout()
        self.tab_widget = None
        self.handler = None
        self.db = db
        self.table = table
        self.table_model = None
        self.create_tab_widget()

        self.main_table = DBTableView(self.tab_widget)
        self.main_table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.main_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.init_table()
        self.main_table.clicked.connect(self.row_selected)

        self.package = QVBoxLayout()
        self.package.addStretch(1)

        self.toolBar = QToolBar()
        self.toolBar.setMovable(True)

        self.up = QAction(
            QIcon("view/images/toolbar/baseline_expand_less_black_48dp.png"),
            "Up", self.main_table)
        self.up.setStatusTip("Move one up")
        self.up.triggered.connect(self.jump_up)

        self.down = QAction(
            QIcon("view/images/toolbar/baseline_expand_more_black_48dp.png"),
            "Down", self.main_table)
        self.down.setStatusTip("Move one down")
        self.down.triggered.connect(self.jump_down)

        self.first = QAction(
            QIcon("view/images/toolbar/baseline_first_page_black_48dp.png"),
            "Jump to first", self.main_table)
        self.first.setStatusTip("Jump to first")
        self.first.triggered.connect(self.jump_to_first)

        self.last = QAction(
            QIcon("view/images/toolbar/baseline_last_page_black_48dp.png"),
            "Jump to last", self.main_table)
        self.last.setStatusTip("Jump to last")
        self.last.triggered.connect(self.jump_to_last)

        self.toolBar.addAction(QIcon("view/images/toolbar/list_48px.png"),
                               "Manage Data")
        self.toolBar.addAction(QIcon("view/images/toolbar/add_new_40px.png"),
                               "Add Data")
        self.toolBar.addAction(self.first)
        self.toolBar.addAction(self.up)
        self.toolBar.addAction(self.down)
        self.toolBar.addAction(self.last)
        self.toolBar.addAction(
            QIcon("view/images/toolbar/close_window_26px.png"), "Close")

        self.manageData = DBManageData(self.main_table)
        self.addData = DBAddData(self.main_table)

        self.stacked_layout = QVBoxLayout()
        self.label = QLabel()
        self.label.setText("Work with data, choose state.")

        self.toolBar.actionTriggered.connect(self.toolbar_actions)

        self.package.addWidget(self.toolBar)
        self.package.addLayout(self.stacked_layout)
        self.package.addWidget(self.main_table)

        self.main_layout.addLayout(self.package)

        self.selected_row = 0

        self.main_layout.addStretch(2)
        self.setLayout(self.main_layout)

    def toolbar_actions(self, action):
        if action.iconText() == "Manage Data":
            if self.stacked_layout.indexOf(
                    self.addData) == -1 and self.stacked_layout.indexOf(
                        self.manageData) == -1 and self.stacked_layout.indexOf(
                            self.label) == -1:
                self.stacked_layout.addWidget(self.manageData)
                self.manageData.setVisible(True)
                return
            if self.stacked_layout.indexOf(self.addData) != -1:
                self.stacked_layout.removeWidget(self.addData)
                self.addData.setVisible(False)
                self.stacked_layout.addWidget(self.manageData)
                self.manageData.setVisible(True)
                return
            if self.stacked_layout.indexOf(self.label) != -1:
                self.stacked_layout.removeWidget(self.label)
                self.label.setVisible(False)
                self.stacked_layout.addWidget(self.manageData)
                self.manageData.setVisible(True)
                return
            return

        elif action.iconText() == "Add Data":
            if self.stacked_layout.indexOf(
                    self.addData) == -1 and self.stacked_layout.indexOf(
                        self.manageData) == -1 and self.stacked_layout.indexOf(
                            self.label) == -1:
                self.stacked_layout.addWidget(self.addData)
                self.addData.setVisible(True)
                return
            if self.stacked_layout.indexOf(self.manageData) != -1:
                self.stacked_layout.removeWidget(self.manageData)
                self.manageData.setVisible(False)
                self.stacked_layout.addWidget(self.addData)
                self.addData.setVisible(True)
                return
            if self.stacked_layout.indexOf(self.label) != -1:
                self.stacked_layout.removeWidget(self.label)
                self.label.setVisible(False)
                self.stacked_layout.addWidget(self.addData)
                self.addData.setVisible(True)
                return
            return

        elif action.iconText() == "Close":
            if self.stacked_layout.indexOf(
                    self.addData) == -1 and self.stacked_layout.indexOf(
                        self.manageData) == -1 and self.stacked_layout.indexOf(
                            self.label) == -1:
                self.stacked_layout.addWidget(self.label)
                self.label.setVisible(True)
                return
            if self.stacked_layout.indexOf(self.addData) != -1:
                self.stacked_layout.removeWidget(self.addData)
                self.addData.setVisible(False)
                self.stacked_layout.addWidget(self.label)
                self.label.setVisible(True)
                return
            if self.stacked_layout.indexOf(self.manageData) != -1:
                self.stacked_layout.removeWidget(self.manageData)
                self.manageData.setVisible(False)
                self.stacked_layout.addWidget(self.label)
                self.label.setVisible(True)
                return
            return

    def row_selected(self, index):
        if index.column() == len(self.main_table.model().columns):

            model = self.main_table.model()
            selected_data = model.get_element(index)

            self.selected_row = index.row()

    def create_tab_widget(self):
        self.tab_widget = QTabWidget()
        self.tab_widget.setTabsClosable(True)
        self.tab_widget.tabCloseRequested.connect(self.delete_tab)

    def delete_tab(self, index):
        self.tab_widget.removeTab(index)

    def init_table(self):
        self.handler = DBHandler(self.db, self.table, self)
        self.table_model = DBTableModel(self.handler)
        self.main_table.setModel(self.table_model)

    """
    Table navigation jumps
    """

    def jump_up(self):
        if self.selected_row != 0:
            self.selected_row -= 1
            self.main_table.selectRow(self.selected_row)

    def jump_down(self):
        if self.selected_row < len(self.main_table.model().displayed_d) - 1:
            self.selected_row += 1
            self.main_table.selectRow(self.selected_row)

    def jump_to_first(self):
        self.selected_row = 0
        self.main_table.selectRow(self.selected_row)

    def jump_to_last(self):
        self.selected_row = len(self.main_table.model().displayed_d) - 1
        self.main_table.selectRow(self.selected_row)

    def sub_up(self):
        if self.selected_row != 0:
            self.selected_row -= 1
            self.subtable.selectRow(self.selected_row)

    def sub_down(self):
        if self.selected_row < len(self.subtable.model().displayed_d) - 1:
            self.selected_row += 1
            self.subtable.selectRow(self.selected_row)

    def sub_first(self):
        self.selected_row = 0
        self.subtable.selectRow(self.selected_row)

    def sub_last(self):
        self.selected_row = len(self.subtable.model().displayed_d) - 1
        self.subtable.selectRow(self.selected_row)
Exemple #15
0
class DebugModulesWidget(QWidget, DockContextHandler):
    def __init__(self, parent, name, data):
        if not type(data) == binaryninja.binaryview.BinaryView:
            raise Exception('expected widget data to be a BinaryView')

        self.bv = data

        QWidget.__init__(self, parent)
        DockContextHandler.__init__(self, self, name)
        self.actionHandler = UIActionHandler()
        self.actionHandler.setupActionHandler(self)

        self.table = QTableView(self)
        self.model = DebugModulesListModel(self.table, data)
        self.table.setModel(self.model)

        self.item_delegate = DebugModulesItemDelegate(self)
        self.table.setItemDelegate(self.item_delegate)

        # self.table.setSortingEnabled(True)
        self.table.setSelectionBehavior(
            QAbstractItemView.SelectionBehavior.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.ExtendedSelection)

        self.table.verticalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)
        self.table.verticalHeader().setVisible(False)

        self.table.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
        self.table.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)

        self.table.resizeColumnsToContents()
        self.table.resizeRowsToContents()

        for i in range(len(self.model.columns)):
            self.table.setColumnWidth(
                i,
                self.item_delegate.sizeHint(
                    self.table.viewOptions(),
                    self.model.index(-1, i, QModelIndex())).width())

        update_layout = QHBoxLayout()
        update_layout.setContentsMargins(0, 0, 0, 0)

        update_label = QLabel("Data is Stale")
        update_button = QPushButton("Refresh")
        update_button.clicked.connect(lambda: self.refresh())

        update_layout.addWidget(update_label)
        update_layout.addStretch(1)
        update_layout.addWidget(update_button)

        self.update_box = QWidget()
        self.update_box.setLayout(update_layout)

        self.layout = QVBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        self.layout.addWidget(self.table)
        self.setLayout(self.layout)

    def notifyOffsetChanged(self, offset):
        pass

    def refresh(self):
        debug_state = binjaplug.get_state(self.bv)
        debug_state.ui.update_modules()

    def notifyModulesChanged(self, new_modules):
        self.model.update_rows(new_modules)
        self.table.resizeColumnsToContents()
        self.layout.removeWidget(self.update_box)
        self.update_box.setVisible(False)

    def mark_dirty(self):
        self.layout.addWidget(self.update_box)
        self.update_box.setVisible(True)

    def contextMenuEvent(self, event):
        self.m_contextMenuManager.show(self.m_menu, self.actionHandler)

    def shouldBeVisible(self, view_frame):
        if view_frame is None:
            return False
        else:
            return True
Exemple #16
0
class SemiAutoSignal():
    def __init__(self, widget, main_widget, config, delete_backtest_tree_item,
                 add_option_underlying, add_option_group, add_option_contract,
                 no_support):
        self.parent = main_widget

        self.config = config
        self.mdi_area = self.parent.mdi_area
        self.root = self.parent.root
        self.group_box_widgets = []
        backtest = widget
        self.backtest = backtest

        self.add_option_underlying = add_option_underlying
        self.add_option_group = add_option_group
        self.add_option_contract = add_option_contract
        self.no_support = no_support
        self.delete_backtest_tree_item = delete_backtest_tree_item

        self.group_box = backtest.findChild(QGroupBox, "backtest_box")
        self.group_box_layout = QVBoxLayout()
        self.group_box.setLayout(self.group_box_layout)
        self.backtest_tree = backtest.findChild(QTreeWidget, "backtest_tree")
        self.backtest_tree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.backtest_tree.topLevelItem(0).setExpanded(True)

        add_option_underlying.triggered.connect(self.onAddOptionUnderlying)
        add_option_group.triggered.connect(self.onAddOptionGroup)
        add_option_contract.triggered.connect(self.onAddOptionContract)
        self.backtest_tree.itemDoubleClicked.connect(
            self.onBackTestTreeDoubleClicked)
        self.backtest_tree.customContextMenuRequested.connect(
            lambda event: self.onBackTestTreeRightClicked())

        delete_backtest_tree_item.triggered.connect(
            self.onDeleteBackTestTreeItem)

        self.loadBacktestTree()

    def loadBacktestTree(self):
        options = self.config.get("options", {})
        underlyings = options.get("underlyings", [])

        for i in range(1):
            item = self.backtest_tree.topLevelItem(i)
            item.setExpanded(True)
            for j in range(item.childCount()):
                child_item = item.child(j)
                child_item.setExpanded(True)
                whatsthis = child_item.whatsThis(0)
                if whatsthis == "option":
                    for underlying in underlyings:
                        current_item = child_item
                        node = QTreeWidgetItem(current_item)
                        node.setText(0, underlying["name"])
                        node.setCheckState(0, Qt.Unchecked)
                        node.setWhatsThis(0, "option_underlying")
                        node.setExpanded(True)

                        data = underlying.get("id",
                                              {}).get("data", pd.DataFrame())
                        if not data.empty:
                            id_dict = underlying.get("id", {})
                            name = id_dict["list"][id_dict["value"]]
                            childSubWindow = {
                                "title": "%s的当日合约",
                                "type": "option_contract_table",
                                "table_name": "%date%",
                                "where": "",
                                "select": id,
                                "hidden_columns": [],
                                "index_column": [],
                                "childSubWindow": {},
                            }
                            hidden_columns = [
                                'total_turnover', 'limit_up', 'limit_down',
                                'settlement', 'prev_settlement',
                                'discount_rate', 'acc_net_value',
                                'unit_net_value', 'date', 'open_interest',
                                'iopv', 'num_trades'
                            ]

                            GridView(self.parent,
                                     name,
                                     data,
                                     id=name,
                                     hidden_columns=hidden_columns,
                                     index_column='date',
                                     childSubWindow=childSubWindow,
                                     type="option_underlying")
                        current_item = node

                        groups = underlying.get("groups", [])
                        for group in groups:
                            node = QTreeWidgetItem(current_item)
                            node.setText(0, group["name"])
                            node.setCheckState(0, Qt.Unchecked)
                            node.setIcon(0, QtGui.QIcon("../icon/group.png"))
                            node.setWhatsThis(0, "option_group")
                            node.setExpanded(True)
                            current_item = node
                            contracts = group.get("contracts")
                            for contract in contracts:
                                node = QTreeWidgetItem(current_item)
                                node.setText(0, contract["name"])
                                node.setCheckState(0, Qt.Unchecked)
                                node.setWhatsThis(0, "option_contract")
                                node.setExpanded(True)
                                current_item = node

    def onBackTestTreeDoubleClicked(self, item, column):
        self.setting_show(item, column)

    def onBackTestTreeRightClicked(self):
        menu = QMenu(self.backtest_tree)
        if self.backtest_tree.currentItem().whatsThis(0) == "option":
            #
            menu.addAction(self.add_option_underlying)
        else:
            whats_this = self.backtest_tree.currentItem().whatsThis(0)
            if whats_this == "option_underlying":
                menu.addAction(self.add_option_group)
                # menu.addAction(self.add_option_contract)
                menu.addAction(self.delete_backtest_tree_item)
            elif whats_this == "option_group":
                menu.addAction(self.add_option_contract)
                menu.addAction(self.delete_backtest_tree_item)
            elif whats_this == "option_contract":
                menu.addAction(self.delete_backtest_tree_item)
            else:
                menu.addAction(self.no_support)
        menu.popup(QtGui.QCursor.pos())

    def onDeleteBackTestTreeItem(self):
        current_item = self.backtest_tree.currentItem()
        parent_item = current_item.parent()
        grand_parent_item = parent_item.parent()
        whats_this = current_item.whatsThis(0)
        parent_whats_this = parent_item.whatsThis(0)
        parent_item_text = parent_item.text(0)
        current_item_text = current_item.text(0)

        index = parent_item.indexOfChild(current_item)
        if whats_this == "option_group":
            for underlying in self.config["options"]["underlyings"]:
                if underlying.get("name") == parent_item_text:
                    groups = underlying.get("groups")
                    for group in groups:
                        if group.get("name") == current_item_text:
                            groups.remove(group)
        elif whats_this == "option_contract":
            #两种情况需要处理
            if parent_whats_this == "option_underlying":
                for underlying in self.config["options"]["underlyings"]:
                    if underlying.get("name") == parent_item_text:
                        contracts = underlying.get("contracts")
                        for contract in contracts:
                            if contract.get("name") == current_item_text:
                                contracts.remove(contract)
            elif parent_whats_this == "option_group":
                for underlying in self.config["options"]["underlyings"]:
                    if underlying.get("name") == grand_parent_item.text(0):
                        groups = underlying.get("groups")
                        for group in groups:
                            if group.get("name") == parent_item_text:
                                contracts = group.get("contracts")
                                for contract in contracts:
                                    if contract.get(
                                            "name") == current_item_text:
                                        contracts.remove(contract)
        elif whats_this == "option_underlying":
            underlyings = self.config["options"]["underlyings"]
            for underlying in underlyings:
                if underlying.get("name") == current_item_text:
                    underlyings.remove(underlying)
        parent_item.takeChild(index)
        return

    def setting_show(self, item, column):

        while self.group_box_widgets:
            for i in self.group_box_widgets:
                i.hide()
                self.group_box_layout.removeWidget(i)
                self.group_box_widgets.remove(i)

        self.current_node = {}
        text = item.text(column)
        whats_this = item.whatsThis(column)
        if whats_this == "option":
            bt_type = "backtest_option"
            title = "期权设置"
            load_file = "backtest_option.ui"
            current_node = self.config["options"]
            self.current_node = current_node
        elif whats_this == "option_underlying":
            title = "标的 %s 的设置" % text
            load_file = "backtest_option_underlying.ui"
            bt_type = "backtest_option_underlying"
            current_node = [
                i for i in self.config["options"]["underlyings"]
                if i["name"] == text
            ][0]
            self.current_node = current_node
        elif whats_this == "option_group":
            title = "期权组 %s 的设置" % text
            load_file = "backtest_option_group.ui"
            bt_type = "backtest_option_group"
            parent_item = item.parent()
            parent_item_text = parent_item.text(0)
            underlying_node = [
                i for i in self.config["options"]["underlyings"]
                if i["name"] == parent_item_text
            ][0]
            current_node = [
                i for i in underlying_node["groups"] if i["name"] == text
            ][0]
            self.current_node = current_node
        elif whats_this == "option_contract":
            title = "期权合约 %s 的设置" % text
            load_file = "backtest_option_contract.ui"
            bt_type = "backtest_option_contract"
            parent_item = item.parent()
            parent_item_text = parent_item.text(0)
            parent_item_whats_this = parent_item.whatsThis(column)
            if parent_item_whats_this == "option_group":
                grand_parent_item = parent_item.parent()
                grand_parent_item_text = grand_parent_item.text(0)
                underlying_node = \
                [i for i in self.config["options"]["underlyings"] if i["name"] == grand_parent_item_text][0]
                group_node = [
                    i for i in underlying_node["groups"]
                    if i["name"] == parent_item_text
                ][0]
                current_node = [
                    i for i in group_node["contracts"] if i["name"] == text
                ][0]
                self.current_node = current_node
            elif parent_item_whats_this == "option_underlying":
                underlying_node = [
                    i for i in self.config["options"]["underlyings"]
                    if i["name"] == parent_item_text
                ][0]
                current_node = [
                    i for i in underlying_node["contracts"]
                    if i["name"] == text
                ][0]
                self.current_node = current_node
        # elif whats_this == "strategy":
        #     title = "策略基本设置"
        #     load_file = "strategy.ui"
        #     bt_type = "backtest_strategy"
        else:
            return

        loader = QUiLoader()
        setting_widget = loader.load(load_file)

        self.group_box.setTitle(title)
        self.group_box_layout.addWidget(setting_widget)
        self.group_box_widgets.append(setting_widget)

        # 连接各组件信号和展示数据
        if whats_this == "option":
            ratio = setting_widget.findChild(QSpinBox, "ratio")
            ratio.setValue(self.current_node["ratio"]["value"])
            ratio.valueChanged.connect(
                lambda event: self.onRatioChanged(event))
        elif whats_this == "option_underlying":
            ratio = setting_widget.findChild(QSpinBox, "ratio")
            ratio.setValue(self.current_node["ratio"]["value"])
            setting_widget.findChild(QSpinBox, "ratio").valueChanged.connect(
                lambda event: self.onRatioChanged(event))

            underlying_list = setting_widget.findChild(QComboBox,
                                                       "underlying_list")
            underlying_list.addItems(self.current_node["id"]["list"])
            underlying_list.currentIndexChanged.connect(
                lambda event: self.onUnderlyingListChanged(event))
            # underlying_list.setCurrentIndex(0)
            signal_list = setting_widget.findChild(QComboBox, "signal_list")
            # signal_list.setCurrentIndex(current_node["signal"]["value"])
            ids = self.current_node["id"]["list"]
            if ids == []:
                self.parent.messageBox("没有数据")
                return
            _sub_window = self.parent.getSubWindowByAttribute("btId", ids[0])
            if _sub_window is None:
                self.parent.messageBox("没有找到标的")
                return

            underlying_list.setCurrentIndex(self.current_node["id"]["value"])

            columns = _sub_window.btData.columns
            signal_column = [i for i in columns if i.startswith("signal")]
            self.current_node["signal"]["list"] = signal_column
            signal_list.addItems(signal_column)
            signal_list.setCurrentIndex(self.current_node["signal"]["value"])
            signal_list.currentIndexChanged.connect(
                lambda event: self.onSignalChanged(event))

            side = setting_widget.findChild(QComboBox, "side")
            side.setCurrentIndex(self.current_node["option_side"]["value"])
            side.currentIndexChanged.connect(
                lambda event: self.onOptionSideChanged(event))

            volume = setting_widget.findChild(QSpinBox, "volume")
            volume.setValue(self.current_node["volume"]["value"])
            volume.valueChanged.connect(
                lambda event: self.onVolumeChanged(event))

        elif whats_this == "option_group":

            ratio = setting_widget.findChild(QSpinBox, "ratio")
            ratio.setValue(self.current_node["ratio"]["value"])
            setting_widget.findChild(QSpinBox, "ratio").valueChanged.connect(
                lambda event: self.onRatioChanged(event))

        elif whats_this == "option_contract":
            contract_type = setting_widget.findChild(QComboBox,
                                                     "contract_type")
            contract_type.setCurrentIndex(
                self.current_node["option_type"]["value"])
            contract_type.currentIndexChanged.connect(
                lambda event: self.onOptionContractTypeChanged(event))

            option_side = setting_widget.findChild(QComboBox, "option_side")
            option_side.setCurrentIndex(
                self.current_node["option_side"]["value"])
            option_side.currentIndexChanged.connect(
                lambda event: self.onOptionSideChanged(event))

            close_strategy = setting_widget.findChild(QComboBox,
                                                      "close_strategy")
            close_strategy.setCurrentIndex(
                self.current_node["close_method"]["value"])
            close_strategy.currentIndexChanged.connect(
                lambda event: self.onCloseMethodChanged(event))

            change_feq = setting_widget.findChild(QComboBox, "change_feq")
            change_feq.setCurrentIndex(
                self.current_node["change_feq"]["value"])
            change_feq.currentIndexChanged.connect(
                lambda event: self.onChangeFeqChanged(event))

            move_condition = setting_widget.findChild(QComboBox,
                                                      "move_condition")
            move_condition.setCurrentIndex(
                self.current_node["change_condition"]["value"])
            move_condition.currentIndexChanged.connect(
                lambda event: self.onChangeConditionChanged(event))

            interval = setting_widget.findChild(QComboBox, "interval")
            interval.setCurrentIndex(
                self.current_node["month_interval"]["value"])
            interval.currentIndexChanged.connect(
                lambda event: self.onMonthIntervalChanged(event))

            strike_interval = setting_widget.findChild(QComboBox,
                                                       "strike_interval")
            strike_interval.setCurrentIndex(
                self.current_node["strike_interval"]["value"])
            strike_interval.currentIndexChanged.connect(
                lambda event: self.onStrikeIntervalChanged(event))

            smart_match = setting_widget.findChild(QComboBox, "smart_match")
            smart_match.setCurrentIndex(
                self.current_node["smart_selection"]["value"])
            smart_match.currentIndexChanged.connect(
                lambda event: self.onSmartSelectionChanged(event))

            volume = setting_widget.findChild(QSpinBox, "volume")
            volume.setValue(self.current_node["volume"]["value"])
            volume.valueChanged.connect(
                lambda event: self.onVolumeChanged(event))

            deposit_ratio = setting_widget.findChild(QDoubleSpinBox,
                                                     "deposit_ratio")
            deposit_ratio.setValue(
                self.current_node["deposit_coefficient"]["value"])
            deposit_ratio.valueChanged.connect(
                lambda event: self.onDepositCoefficient(event))

            delta = setting_widget.findChild(QDoubleSpinBox, "delta")
            delta.setValue(self.current_node["delta"]["value"])
            delta.valueChanged.connect(
                lambda event: self.onDeltaChanged(event))

            gamma = setting_widget.findChild(QDoubleSpinBox, "gamma")
            gamma.setValue(self.current_node["gamma"]["value"])
            gamma.valueChanged.connect(
                lambda event: self.onGammaChanged(event))

            theta = setting_widget.findChild(QDoubleSpinBox, "theta")
            theta.setValue(self.current_node["theta"]["value"])
            theta.valueChanged.connect(
                lambda event: self.onThetaChanged(event))

            vega = setting_widget.findChild(QDoubleSpinBox, "vega")
            vega.setValue(self.current_node["vega"]["value"])
            vega.valueChanged.connect(lambda event: self.onVegaChanged(event))

            rho = setting_widget.findChild(QDoubleSpinBox, "rho")
            rho.setValue(self.current_node["rho"]["value"])
            rho.valueChanged.connect(lambda event: self.onRhoChanged(event))

            ivix = setting_widget.findChild(QDoubleSpinBox, "ivix")
            ivix.setValue(self.current_node["ivix"]["value"])
            ivix.valueChanged.connect(lambda event: self.onIvixChanged(event))

        # elif whats_this == "strategy":
        #     account_folder = os.path.normpath(os.path.join(ROOT, "accounts"))
        #     account_files = [os.path.splitext(i)[0] for i in os.listdir(account_folder) if
        #                      os.path.splitext(i)[-1] == ".bt"]
        #     account_list = sub_window_widget.findChild(QComboBox, "account")
        #     account_list.addItems(account_files)
        #     account_list.currentTextChanged.connect(lambda event:self.onBackTestRunAccountChanged(event))
        #
        #     open_type_list = sub_window_widget.findChild(QComboBox, "open_type")
        #     open_type_list.currentIndexChanged.connect(lambda event: self.onBackTestOpenTypeChanged(event))
        #
        #     table_view = sub_window_widget.findChild(QTableWidget)
        #     self.initBacktestAccountTable(table_view, account_files[0])

    def onOptionContractTypeChanged(self, index):
        current_node = self.current_node
        current_node["option_type"]["value"] = index

    def onOptionSideChanged(self, index):
        current_node = self.current_node
        current_node["option_side"]["value"] = index

    def onCloseMethodChanged(self, index):
        current_node = self.current_node
        current_node["close_method"]["value"] = index

    def onChangeFeqChanged(self, index):
        current_node = self.current_node
        current_node["change_feq"]["value"] = index

    def onChangeConditionChanged(self, index):
        current_node = self.current_node
        current_node["change_condition"]["value"] = index

    def onMonthIntervalChanged(self, index):
        current_node = self.current_node
        current_node["month_interval"]["value"] = index

    def onStrikeIntervalChanged(self, index):
        current_node = self.current_node
        current_node["strike_interval"]["value"] = index

    def onSmartSelectionChanged(self, index):
        current_node = self.current_node
        current_node["smart_selection"]["value"] = index

    def onDepositCoefficient(self, value):
        current_node = self.current_node
        current_node["deposit_coefficient"]["value"] = value

    def onDeltaChanged(self, value):
        current_node = self.current_node
        current_node["delta"]["value"] = value

    def onGammaChanged(self, value):
        current_node = self.current_node
        current_node["gamma"]["value"] = value

    def onThetaChanged(self, value):
        current_node = self.current_node
        current_node["theta"]["value"] = value

    def onVegaChanged(self, value):
        current_node = self.current_node
        current_node["vega"]["value"] = value

    def onRhoChanged(self, value):
        current_node = self.current_node
        current_node["rho"]["value"] = value

    def onIvixChanged(self, value):
        current_node = self.current_node
        current_node["ivix"]["value"] = value

    def onRatioChanged(self, value):
        current_node = self.current_node
        current_node["ratio"]["value"] = value

    def onUnderlyingListChanged(self, index):
        current_node = self.current_node
        current_node["id"]["value"] = index
        text = current_node["id"]["list"][index]
        signal_list = self.mdi_area.currentSubWindow().findChild(
            QComboBox, "signal_list")
        signal_list.clear()
        sub_window = self.parent.getSubWindowByAttribute("btId", text)
        data = sub_window.btData
        signal_list.addItems(
            [i for i in data.columns if i.startswith("signal")])

    def onVolumeChanged(self, value):
        current_node = self.current_node
        current_node["volume"]["value"] = value

    def onSignalChanged(self, index):
        current_node = self.current_node
        current_node["signal"]["value"] = index

    def onAddOptionUnderlying(self):

        text, ok = QInputDialog.getText(self.backtest, "请输入期权标的名称", "名称",
                                        QLineEdit.Normal)
        if ok and text:
            node = QTreeWidgetItem(self.backtest_tree.currentItem())
            node.setText(0, text)
            node.setCheckState(0, Qt.Unchecked)
            node.setWhatsThis(0, "option_underlying")
            self.backtest_tree.expandItem(self.backtest_tree.currentItem())
            ids = [
                i.btId for i in self.mdi_area.subWindowList()
                if hasattr(i, "btType")
                and i.btType in ["option_underlying", "excel", "csv"]
            ]
            group_dict = {
                "name": text,
                "enable": 0,
                "ratio": {
                    "type": "int",
                    "value": 0,
                },
                "id": {
                    "type":
                    "list",
                    "value":
                    0,
                    "list":
                    ids,
                    "data":
                    getattr(
                        self.parent.getSubWindowByAttribute("btId", ids[0]),
                        "btData")
                },
                "signal": {
                    "type": "list",
                    "value": 0,
                    "list": []
                },
                "option_side": {
                    "type": "list",
                    "value": 0,
                    "list": [u"买入"]
                },
                "volume": {
                    "type": "int",
                    "value": 0,
                },
                "groups": [],
                "contracts": [],
            }
            self.config["options"]["underlyings"].append(group_dict)

    def onAddOptionGroup(self):
        text, ok = QInputDialog.getText(self.backtest, "请输入期权组名称", "名称",
                                        QLineEdit.Normal)
        current_item = self.backtest_tree.currentItem()
        # parent_item = current_item.parent()
        current_item_text = current_item.text(0)
        # parent_item_text = parent_item.text(0)
        if ok and text:
            node = QTreeWidgetItem(current_item)
            node.setText(0, text)
            node.setCheckState(0, Qt.Unchecked)
            node.setWhatsThis(0, "option_group")
            node.setIcon(0, QtGui.QIcon("../icon/group.png"))
            self.backtest_tree.expandItem(self.backtest_tree.currentItem())
            group_dict = {
                "name": text,
                "enable": 1,
                "contracts": [],
                "signal": {
                    "type": "list",
                    "value": 0,
                    "list": []
                },
                "ratio": {
                    "type": "float",
                    "value": 0,
                },
            }
            for underlying in self.config["options"]["underlyings"]:
                if underlying.get("name") == current_item_text:
                    underlying["groups"].append(group_dict)

    def onAddOptionContract(self):
        text, ok = QInputDialog.getText(self.backtest, "请输入期权合约名称", "名称",
                                        QLineEdit.Normal)
        current_item = self.backtest_tree.currentItem()
        current_item_whats_this = current_item.whatsThis(0)
        current_item_text = current_item.text(0)
        parent_item = current_item.parent()
        parent_whats_this = parent_item.whatsThis(0)
        parent_item_text = parent_item.text(0)
        if ok and text:
            node = QTreeWidgetItem(current_item)
            node.setText(0, text)
            node.setCheckState(0, Qt.Unchecked)
            node.setWhatsThis(0, "option_contract")
            node.setIcon(0, QtGui.QIcon("../icon/contract.png"))
            self.backtest_tree.expandItem(self.backtest_tree.currentItem())
            filter_dict = {
                "name": text,
                "enable": 1,
                "open_status": False,
                "ids": [],
                "option_type": {
                    "type": "list",
                    "value": 0,
                    "list": setting.OPTION_TYPE,
                },
                "option_side": {
                    "type": "list",
                    "value": 0,
                    "list": setting.OPTION_SIDE,
                },
                "close_method": {
                    "type": "list",
                    "value": 0,
                    "list": setting.OPTION_CLOSE_METHOD,
                },
                "change_feq": {
                    "type": "list",
                    "value": 0,
                    "list": setting.OPTION_CHANGE_FEQ,
                },
                "change_condition": {
                    "type": "list",
                    "value": 0,
                    "list": setting.OPTION_CHANGE_CONDITION,
                },
                "month_interval": {
                    "type":
                    "list",
                    "value":
                    0,
                    "list": [
                        setting.OPTION_INTERVAL[i]
                        for i in range(len(setting.OPTION_INTERVAL)) if i != 2
                    ],
                },
                "strike_interval": {
                    "type": "list",
                    "value": 0,
                    "list": setting.OPTION_STRIKE_INTERVAL,
                },
                "smart_selection": {
                    "type": "list",
                    "value": 1,
                    "list": setting.OPTION_SMART_SELECTION,
                },
                "type": "option",
                "volume": {
                    "type": "int",
                    "value": 0
                },
                "deposit_coefficient": {
                    "type": "int",
                    "value": 1,
                },
                "delta": {
                    "type": "int",
                    "value": 0,
                },
                "gamma": {
                    "type": "int",
                    "value": 0,
                },
                "theta": {
                    "type": "int",
                    "value": 0,
                },
                "vega": {
                    "type": "int",
                    "value": 0,
                },
                "rho": {
                    "type": "int",
                    "value": 0,
                },
                "ivix": {
                    "type": "float",
                    "value": 0
                }
            }
            for underlying in self.config["options"]["underlyings"]:
                underlying_name = underlying.get("name")
                if current_item_whats_this == "option_group":
                    if underlying_name == parent_item_text:
                        groups = underlying.get("groups")
                        for group in groups:
                            if group.get("name") == current_item_text:
                                group["contracts"].append(filter_dict)
                elif current_item_whats_this == "option_underlying":
                    if underlying_name == current_item_text:
                        underlying.get("contracts").append(filter_dict)
Exemple #17
0
class Window(QWidget):
    def __init__(self):
        # call the constructor of the parent (QWidget)
        super().__init__()

        # check if it the first time for user to plot
        self.firstTime = False

        # set title  and geometry for the window
        self.setWindowTitle("Function Plotter")
        self.setGeometry(500, 400, 400, 200)

        # give orange background to the window
        palette = self.palette()
        palette.setColor(QPalette.Window, QColor(150, 150, 150))
        self.setPalette(palette)
        self.setAutoFillBackground(True)

        # set minimum width and height for the window
        self.setMinimumHeight(200)
        self.setMinimumWidth(400)
        self.setMaximumHeight(200)
        self.setMaximumWidth(400)

        # set icon for the application at run time and center the application window with the primary screen
        self.setIcon()
        self.center()

        # setup the grid layout design and components
        self.createGridLayout()
        self.vbox = QVBoxLayout()
        self.vbox.addWidget(self.groupBox)
        self.vbox.setAlignment(Qt.AlignCenter | Qt.AlignTop)
        self.setLayout(self.vbox)

    # set icon for the application
    def setIcon(self):
        appIcon = QIcon("icon.png")
        self.setWindowIcon(appIcon)

    # reading the data from text input and apply check tests
    def readData(self):
        # read the equation and check if there is an actual input
        equation = self.equationInput.text()
        if equation == '':
            self.aboutBox("Empty section", "Please enter an equation")
            return
        # remove spaces from the equation and check if the equation has valid variable name
        equation = removeSpaces(equation)
        varName, _ = getVariableName(equation)
        check, error = checkVarName(equation, varName)
        if not check:
            self.aboutBox("Wrong equation", error)
            return

        # check min and max value if it's a real number and the text input isn't empty
        maxValue = self.maxInput.text()
        if maxValue == '':
            self.aboutBox("Empty section", "Please enter maximum value")
            return
        try:
            maxValue = float(maxValue)
        except ValueError:
            self.aboutBox(
                "Wrong range",
                "Invalid value for maximum, please enter float or integer value"
            )
            return
        minValue = self.minInput.text()
        if minValue == '':
            self.aboutBox("Empty section", "Please enter minimum value")
            return
        try:
            minValue = float(minValue)
        except ValueError:
            self.aboutBox(
                "Wrong range",
                "Invalid value for minimum, please enter float or integer value"
            )
            return

        # the max value should be greater than min value
        if minValue >= maxValue:
            self.aboutBox("Wrong range",
                          "Your maximum value should be greater than minimum")
            return

        # process the equation by trying to solve it with max value and check if there is error with operatos, operands or parentheses
        ops = trimTerms(equation, varName)
        temp_ops = replaceVar(ops, varName, str(maxValue))
        testVal, error = functionCalculator(temp_ops)

        if error != None:
            self.aboutBox("Evaluation error", error)
            return

        # function to evaluate f(x) array and return f(x) and x lists to be plotted
        fx, x = self.evaluateFunction(ops, maxValue, minValue, varName)

        # plot the graph
        self.plotGraph(fx, x, varName)

    def plotGraph(self, fx, x, varName):
        # remove the old figure if user request another equation
        if self.firstTime:
            self.fig.clear()
            self.vbox.removeWidget(self.toolbar)
            self.vbox.removeWidget(self.canvas)

        # set first time to be True, to remove the old figures
        self.firstTime = True

        # set the figure and toolbar and add it to the window
        self.fig = Figure(figsize=(7, 5),
                          dpi=65,
                          facecolor=(1, 1, 1),
                          edgecolor=(0, 0, 0))
        self.canvas = FigureCanvas(self.fig)
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.vbox.addWidget(self.toolbar)
        self.vbox.addWidget(self.canvas)

        # set new geometry to the window to fit the graph
        self.resize(400, 500)
        self.setMinimumHeight(500)
        self.setMaximumHeight(500)

        # plot the graph and set the labels
        self.ax = self.fig.add_subplot(111)
        self.ax.plot(x, fx)
        if varName == '':
            varName = 'x'
        self.ax.set_xlabel(varName)
        self.ax.set_ylabel('f(' + varName + ')')

    # QMessageBox which shows any error for the user
    def aboutBox(self, title, error):
        QMessageBox.about(self, title, error)

    def evaluateFunction(self, ops, maxVal, minVal, varName):
        # make array with start = minVal, end, maxVal and step for 0.25 for some accuracy
        x = np.arange(minVal, maxVal, 0.25)
        fx = []
        # loop over each number(i) and evaluate f(i) then add it to f(x) list
        for number in x:
            temp_ops = replaceVar(ops, varName, number)
            val, _ = functionCalculator(temp_ops)
            fx.append(val)

        return fx, x

    # to center the application window at the beginning
    def center(self):
        qRect = self.frameGeometry()
        centerPoint = QtGui.QGuiApplication.primaryScreen().availableGeometry(
        ).center()
        qRect.moveCenter(centerPoint)
        self.move(qRect.topLeft())

    def createGridLayout(self):
        # make group box with headline then add the gridlayout to it
        self.groupBox = QGroupBox("Please fill next sections")
        self.groupBox.setFont(QFont("Helvetica", 12))
        self.groupBox.setMaximumWidth(400)
        self.groupBox.setMaximumHeight(200)
        # create gridlayout with spacing between columns and rows
        gridLayout = QGridLayout()
        gridLayout.setSpacing(10)

        # set equation text input
        self.equationInput = QLineEdit()
        self.equationInput.setMaximumHeight(30)
        #self.equationInput.setMaximumWidth(175)
        self.equationInput.setPlaceholderText("Enter your equation")
        gridLayout.addWidget(self.equationInput, 0, 0, 1, 0)

        # set max value text input
        self.maxInput = QLineEdit()
        self.maxInput.setMaximumHeight(30)
        self.maxInput.setMaximumWidth(175)
        self.maxInput.setPlaceholderText("Enter maximum value")
        gridLayout.addWidget(self.maxInput, 1, 0)

        # set min value text input
        self.minInput = QLineEdit()
        self.minInput.setMaximumHeight(30)
        self.minInput.setMaximumWidth(175)
        self.minInput.setPlaceholderText("Enter minimum value")
        gridLayout.addWidget(self.minInput, 1, 1)

        # set Plot push button with green color and an icon
        plotButton = QPushButton("Plot")
        plotButton.setStyleSheet("background-color: green")
        plotButton.setIcon(QIcon("curve.png"))
        plotButton.setMaximumHeight(30)
        plotButton.setMaximumWidth(75)
        # when button is clicked, call readData and then will plot the function
        plotButton.clicked.connect(self.readData)
        gridLayout.addWidget(plotButton, 2, 0)

        # add gridlayout to the group box
        self.setLayout(gridLayout)
        self.groupBox.setLayout(gridLayout)
class MainWidget(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.lyt = QVBoxLayout()
        self.setLayout(self.lyt)

        #list of host & services
        self.table_main = QWidget()
        self.table_main_lyt = QVBoxLayout(self.table_main)
        self.info_table = QWidget()
        self.table_main_lyt.addWidget(self.info_table)
        self.lyt.addWidget(self.table_main)

        self.init_refresh()

        self.refresh()

    def init_refresh(self):
        self.refrsh_opt = QWidget()
        self.refrsh_opt_lyt = QHBoxLayout()
        self.refrsh_opt.setLayout(self.refrsh_opt_lyt)

        self.refrsh_btn = QPushButton()
        self.refrsh_btn.setIcon(self.style().standardIcon(
            QStyle.SP_BrowserReload))
        self.refrsh_btn.clicked.connect(self.refresh)

        self.test1_btn = QPushButton()
        self.test1_btn.setIcon(self.style().standardIcon(
            QStyle.SP_BrowserReload))
        self.test1_btn.clicked.connect(self.test1)

        self.refrsh_opt_lyt.addWidget(self.refrsh_btn)
        self.refrsh_opt_lyt.addWidget(self.test1_btn)

        self.lyt.addWidget(self.refrsh_opt)

    def test1(self):
        print("test")

    def refresh(self):
        print("Signal: refresh")
        self.netinfo = get_host_summary()

        self.table_main_lyt.removeWidget(self.info_table)
        self.info_table = QWidget()
        self.info_table_lyt = QGridLayout(self.info_table)
        self.table_main_lyt.addWidget(self.info_table)

        row = 0
        col = 0
        for iHeadline in ("Interface", "Mac", "Ip", "Hostname"):
            self.info_table_lyt.addWidget(QLabel("<b>" + iHeadline + "</b>"),
                                          row, col)
            col += 1
        for iServiceName, iService in SERVICES.items():
            self.info_table_lyt.addWidget(
                QLabel("<b>" + iServiceName + "</b>"), row, col)
            col += 1

        row += 1
        col = 0
        for iHost in self.netinfo:
            self.info_table_lyt.addWidget(QLabel(str(iHost["dev"])), row, col)
            col += 1
            self.info_table_lyt.addWidget(QLabel(str(iHost["mac"])), row, col)
            col += 1
            self.info_table_lyt.addWidget(QLabel(str(iHost["ip"])), row, col)
            col += 1

            if "hostname" in iHost:
                self.info_table_lyt.addWidget(QLabel(str(iHost["hostname"])),
                                              row, col)
            else:
                self.info_table_lyt.addWidget(QLabel(""), row, col)

            for iServiceName, iService in SERVICES.items():
                col += 1
                service_info = iHost["services"][iServiceName]
                if len(service_info) < 1:
                    self.info_table_lyt.addWidget(QLabel("x"), row, col)
                    continue
                widget = iService["display"].display(service_info)
                self.info_table_lyt.addWidget(widget, row, col)

            row += 1
            col = 0
Exemple #19
0
class FileSystemWidget(QWidget, DirectoryObserver):
    """
    Widget for listing directory contents and download files from the RDP client.
    """

    # fileDownloadRequested(file, targetPath, dialog)
    fileDownloadRequested = Signal(File, str, FileDownloadDialog)

    def __init__(self, root: Directory, parent: QObject = None):
        """
        :param root: root of all directories. Directories in root will be displayed with drive icons.
        :param parent: parent object.
        """

        super().__init__(parent)
        self.root = root
        self.breadcrumbLabel = QLabel()

        self.titleLabel = QLabel()
        self.titleLabel.setStyleSheet("font-weight: bold")

        self.titleSeparator: QFrame = QFrame()
        self.titleSeparator.setFrameShape(QFrame.HLine)

        self.listWidget = QListWidget()
        self.listWidget.setSortingEnabled(True)
        self.listWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.listWidget.customContextMenuRequested.connect(self.onCustomContextMenu)

        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.addWidget(self.breadcrumbLabel)
        self.verticalLayout.addWidget(self.listWidget)

        self.setLayout(self.verticalLayout)
        self.listWidget.itemDoubleClicked.connect(self.onItemDoubleClicked)

        self.currentPath: Path = Path("/")
        self.currentDirectory: Directory = root
        self.listCurrentDirectory()

        self.currentDirectory.addObserver(self)

    def setWindowTitle(self, title: str):
        """
        Set the window title. When the title is not blank, a title label and a separator is displayed.
        :param title: the new title.
        """

        previousTitle = self.windowTitle()

        super().setWindowTitle(title)

        self.titleLabel.setText(title)

        if previousTitle == "" and title != "":
            self.verticalLayout.insertWidget(0, self.titleLabel)
            self.verticalLayout.insertWidget(1, self.titleSeparator)
        elif title == "" and previousTitle != "":
            self.verticalLayout.removeWidget(self.titleLabel)
            self.verticalLayout.removeWidget(self.titleSeparator)

            # noinspection PyTypeChecker
            self.titleLabel.setParent(None)

            # noinspection PyTypeChecker
            self.titleSeparator.setParent(None)

    def onItemDoubleClicked(self, item: FileSystemItem):
        """
        Handle double-clicks on items in the list. When the item is a directory, the current path changes and the
        contents of the directory are listed. Files are ignored.
        :param item: the item that was clicked.
        """

        if not item.isDirectory() and not item.isDrive():
            return

        if item.text() == "..":
            self.currentPath = self.currentPath.parent
        else:
            self.currentPath = self.currentPath / item.text()

        self.listCurrentDirectory()

    def listCurrentDirectory(self):
        """
        Refresh the list widget with the current directory's contents.
        """

        node = self.root

        for part in self.currentPath.parts[1 :]:
            node = next(d for d in node.directories if d.name == part)

        self.listWidget.clear()
        self.breadcrumbLabel.setText(f"Location: {str(self.currentPath)}")

        if node != self.root:
            self.listWidget.addItem(FileSystemItem("..", FileSystemItemType.Directory))

        for directory in node.directories:
            self.listWidget.addItem(FileSystemItem(directory.name, directory.type))

        for file in node.files:
            self.listWidget.addItem(FileSystemItem(file.name, file.type))

        if node is not self.currentDirectory:
            self.currentDirectory.removeObserver(self)
            node.addObserver(self)
            self.currentDirectory = node
            node.list()

    def onDirectoryChanged(self):
        """
        Refresh the directory view when the directory has changed.
        """

        self.listCurrentDirectory()

    def currentItemText(self) -> str:
        try:
            return self.listWidget.selectedItems()[0].text()
        except IndexError:
            return ""

    def selectedFile(self) -> Optional[File]:
        text = self.currentItemText()

        if text == "":
            return None

        if text == "..":
            return self.currentDirectory.parent

        for sequence in [self.currentDirectory.files, self.currentDirectory.directories]:
            for file in sequence:
                if text == file.name:
                    return file

        return None

    def canDownloadSelectedItem(self) -> bool:
        return self.selectedFile().type == FileSystemItemType.File

    def onCustomContextMenu(self, localPosition: QPoint):
        """
        Show a custom context menu with a "Download file" action when a file is right-clicked.
        :param localPosition: position where the user clicked.
        """
        selectedFile = self.selectedFile()

        if selectedFile is None:
            return

        globalPosition = self.listWidget.mapToGlobal(localPosition)

        downloadAction = QAction("Download file")
        downloadAction.setEnabled(selectedFile.type in [FileSystemItemType.File])
        downloadAction.triggered.connect(self.downloadFile)

        itemMenu = QMenu()
        itemMenu.addAction(downloadAction)

        itemMenu.exec_(globalPosition)

    def downloadFile(self):
        file = self.selectedFile()

        if file.type != FileSystemItemType.File:
            return

        filePath = file.getFullPath()
        targetPath, _ = QFileDialog.getSaveFileName(self, f"Download file {filePath}", file.name)

        if targetPath != "":
            dialog = FileDownloadDialog(filePath, targetPath, self)
            dialog.show()

            self.fileDownloadRequested.emit(file, targetPath, dialog)
Exemple #20
0
class DataDisplay(QWidget):
    def __init__(self, state, transactionList, monthCode, prevCode=None):
        QWidget.__init__(self)
        self.allTransactions = []
        self.state = state
        self.addListeners()
        self.loadNewMonth(transactionList, monthCode, prevCode)

    def addListeners(self):
        self.state.addSubscriber(Events.transaction_drop_event, self.dropEvent)
        self.state.addSubscriber(Events.remove_category, self.removeCategory)
        self.state.addSubscriber(Events.update_category_total,
                                 self.updateConfigCategoryTotal)
        self.state.addSubscriber(Events.update_category_title,
                                 self.updateConfigCategoryName)
        self.state.addSubscriber(Events.add_category, self.addCategory)
        self.state.addSubscriber(Events.remove_all_categories,
                                 self.removeAllCategories)

    def onDestroy(self):
        self.state.removeSubscriber(Events.transaction_drop_event,
                                    self.dropEvent)
        self.state.removeSubscriber(Events.remove_category,
                                    self.removeCategory)
        self.state.removeSubscriber(Events.update_category_total,
                                    self.updateConfigCategoryTotal)
        self.state.removeSubscriber(Events.update_category_title,
                                    self.updateConfigCategoryName)
        self.state.removeSubscriber(Events.add_category, self.addCategory)
        self.state.removeSubscriber(Events.remove_all_categories,
                                    self.removeAllCategories)

    def addCategory(self, data):
        cfg = self.state.getConfig()
        if not data['title'] in cfg['months'][self.month]:
            amt = int(data['amt'])
            cfg['months'][self.month][data['title']] = {
                'transactionList': [],
                'total': amt
            }
            self.state.setConfig(cfg)

            idx = -1
            if data['title'] == 'Income':
                idx = 0
            else:
                for i, section in enumerate(self.sectionState):
                    if int(section['total']) < amt:
                        idx = i
                        break

            self.sectionState.insert(idx, {
                'name': data['title'],
                'total': amt
            })
            self.contentWrapperLayout.insertWidget(
                idx, Category(data['title'], amt, [], self.state))
            self.updateTotalAmt()

    def loadNewMonth(self,
                     transactionList,
                     monthCode,
                     prevCode=None,
                     disableCredit=False):
        self.allTransactions = transactionList
        self.month = monthCode
        self.constructCategories(transactionList, monthCode, prevCode)
        self.updateTotalAmt()

    def constructCategories(self, transactionList, monthCode, prevCode):
        config = self.state.getConfig()
        if monthCode not in config['months']:
            if not config['months']:
                config['months'][monthCode] = {}
            else:
                prevCode = prevCode if prevCode else max(
                    list(config['months'].keys()))
                # config option?
                config['months'][monthCode] = deepcopy(
                    config['months'][prevCode])

        formattedSections = {
            'uncategorized': {
                'tList': [],
                'total': 0
            },
            'income': {
                'tList': [],
                'total': 0
            }
        }

        for transaction in transactionList:
            foundCategory = False
            if transaction.isCredit:
                formattedSections['income']['tList'].append(transaction)
                formattedSections['income']['total'] += transaction.amt
            else:
                for category in list(config['months'][monthCode].keys()):
                    transactionList = config['months'][monthCode][category][
                        'transactionList']
                    if not category in formattedSections.keys():
                        formattedSections[category] = {'tList': [], 'total': 0}
                    if transaction.name in transactionList:
                        foundCategory = True
                        formattedSections[category]['tList'].append(
                            transaction)
                        formattedSections[category]['total'] += transaction.amt
                if not foundCategory:
                    formattedSections['uncategorized']['tList'].append(
                        transaction)
                    formattedSections['uncategorized'][
                        'total'] += transaction.amt

        def sortSection(x, y):
            if x == 'Income':
                return 1
            if x == 'uncategorized':
                return -1
            if formattedSections[x]['total'] < formattedSections[y]['total']:
                return -1
            return 1

        categoryKeys = sorted(list(formattedSections.keys()),
                              key=cmp_to_key(sortSection),
                              reverse=True)
        sectionsUI = []
        self.sectionState = []
        incomeCategory = None
        for category in categoryKeys:
            if category == 'income':
                if formattedSections['income']['total'] > 0:
                    self.sectionState.append({
                        'name':
                        'Income',
                        'total':
                        formattedSections['income']['total']
                    })
                    incomeCategory = {
                        'title': 'Income',
                        'amt': formattedSections['income']['total']
                    }
            elif category == 'uncategorized':
                self.sectionState.append({
                    'name': 'Uncategorized',
                    'total': '0'
                })
                sectionsUI.append(
                    Category('Uncategorized', 0,
                             formattedSections['uncategorized']['tList'],
                             self.state))
            else:
                catTotal = config['months'][monthCode][category]['total']
                self.sectionState.append({'name': category, 'total': catTotal})
                sectionsUI.append(
                    Category(category, catTotal,
                             formattedSections[category]['tList'], self.state))

        self.contentWrapperLayout = QVBoxLayout()
        for sectionLayout in sectionsUI:
            self.contentWrapperLayout.addWidget(sectionLayout)
        self.setLayout(self.contentWrapperLayout)
        self.state.setConfig(config)
        if incomeCategory:
            self.addCategory(incomeCategory)
            incomeCategoryWidget = self.getCategoryWidget('Income')
            incomeCategoryWidget.addTransactions(
                formattedSections['income']['tList'])

    def updateConfigCategoryTotal(self, name, amt):
        cfg = self.state.getConfig()
        cfg['months'][self.month][name]['total'] = amt
        self.state.setConfig(cfg)
        self.updateTotalAmt()

    def updateConfigCategoryName(self, name, newTitle):
        cfg = self.state.getConfig()
        cfg['months'][self.month][newTitle] = cfg['months'][self.month].pop(
            name)
        self.state.setConfig(cfg)

    def dropEvent(self, transactionTitle, destCategoryTitle):
        cfg = self.state.getConfig()
        sourceCat = self.getCategoryFromTransaction(cfg, transactionTitle)
        if not len(sourceCat) or sourceCat[0] != destCategoryTitle:
            transactionsToAdd = []
            if len(sourceCat):
                oldList = cfg['months'][self.month][
                    sourceCat[0]]['transactionList']
                newList = list(filter((transactionTitle).__ne__, oldList))
                cfg['months'][self.month][
                    sourceCat[0]]['transactionList'] = newList
                transactionsToAdd += self.removeTransactionsFromCategory(
                    transactionTitle, sourceCat[0])
            else:
                transactionsToAdd += self.removeTransactionsFromCategory(
                    transactionTitle, 'Uncategorized')

            if destCategoryTitle != 'Uncategorized':
                cfg['months'][self.month][destCategoryTitle][
                    'transactionList'].append(transactionTitle)

            self.state.setConfig(cfg)
            categoryToAddTo = self.getCategoryWidget(destCategoryTitle)
            categoryToAddTo.addTransactions(transactionsToAdd)

    def removeTransactionsFromCategory(self, transactionTitle, title):
        i = 0
        transactionsRemoved = []
        curWidget = self.getCategoryWidget(title)
        j = 0
        while j < len(curWidget.transactions):
            widgetTransaction = curWidget.transactions[j]
            if widgetTransaction.name == transactionTitle:
                transactionsRemoved.append(widgetTransaction)
                curWidget.removeTransaction(widgetTransaction)
            else:
                j += 1

        return transactionsRemoved

    def getCategoryWidget(self, categoryName):
        i = 0
        curWidget = self.contentWrapperLayout.itemAt(i)
        while (curWidget):
            if curWidget.widget().name == categoryName:
                return curWidget.widget()
            i += 1
            curWidget = self.contentWrapperLayout.itemAt(i)

    def getCategoryFromTransaction(self, cfg, title):
        category = list(
            filter(
                lambda x: title in cfg['months'][self.month][x][
                    'transactionList'], cfg['months'][self.month].keys()))
        return category

    def removeCategory(self, title, transactionList):
        cfg = self.state.getConfig()

        amt = cfg['months'][self.month][title]['total']
        del cfg['months'][self.month][title]

        self.state.setConfig(cfg)
        i = 0
        curWidget = self.contentWrapperLayout.itemAt(i)
        while (curWidget):
            if curWidget.widget().name == title:
                curWidget.widget().deleteLater()
                self.contentWrapperLayout.removeWidget(curWidget.widget())
                self.sectionState.remove({'name': title, 'total': amt})
            elif curWidget.widget().name == 'Uncategorized':
                curWidget.widget().addTransactions(transactionList)
                i += 1
            else:
                i += 1
            curWidget = self.contentWrapperLayout.itemAt(i)
        self.updateTotalAmt()

    def removeAllCategories(self):
        cfg = self.state.getConfig()
        allCategories = cfg['months'][self.month].keys()
        for category in allCategories:
            categoryTransactions = self.getCategoryWidget(
                category).getTransactions()
            self.removeCategory(category, categoryTransactions)

    def getTotalAmt(self):
        totalAmt = 0
        for transaction in self.allTransactions:
            # totalAmt += (-1 * transaction.amt) if transaction.isCredit else transaction.amt
            totalAmt += 0 if transaction.isCredit else transaction.amt
        return round(totalAmt, 2)

    def sumCategories(self):
        cfg = self.state.getConfig()
        sum = 0
        categories = list(cfg['months'][self.month].keys())
        for category in categories:
            categoryTotal = cfg['months'][self.month][category]['total']
            # sum += categoryTotal if category != 'Income' else -categoryTotal
            sum += categoryTotal if category != 'Income' else 0
        return sum

    def updateTotalAmt(self):
        categorySum = self.sumCategories()
        transactionSum = self.getTotalAmt()
        self.state.next(Events.update_total, transactionSum, categorySum)
Exemple #21
0
class ImageToPdfWidget(QWidget):
    def __init__(self, status_link):
        super(ImageToPdfWidget, self).__init__()
        LABEL_WIDTH = 80
        self.last_selected_items = []
        self.options_mode = 0
        self.update_status_combobox = False
        layout = QHBoxLayout()
        self.status_bar = status_link
        self.list_view = QListWidget()
        self.list_view.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.list_view.setAlternatingRowColors(True)
        self.list_view.itemClicked.connect(self.click_item_signal)
        self.list_view.itemEntered.connect(self.click_item_signal)
        self.list_view.itemSelectionChanged.connect(
            self.change_selection_signal)

        controls_layout = QVBoxLayout()
        controls_layout.setAlignment(Qt.AlignTop)

        select_zone = SelectWidget(self.click_move_up, self.click_move_down,
                                   self.click_invert, self.click_delete)

        # options zone -------------------------------------
        options_zone = QGroupBox("Options")
        self.options_zone_layout = QVBoxLayout()

        self.options_mode_combobox = QComboBox()
        self._add_items_to_mode_combobox(self.options_mode_combobox)
        options_mode_label = QLabel("Mode")
        options_mode_label.setMaximumWidth(LABEL_WIDTH)
        options_mode_layout = QHBoxLayout()
        options_mode_layout.addWidget(options_mode_label)
        options_mode_layout.addWidget(self.options_mode_combobox)
        self.options_zone_layout.addLayout(options_mode_layout)
        self.option_source_widget = OptionsFromSourceWidget(
            label_width=LABEL_WIDTH, status_bar=self.status_bar)
        self.options_a_widget = OptionsAWidget(label_width=LABEL_WIDTH,
                                               status_bar=self.status_bar)
        self.options_mode_combobox.currentIndexChanged.connect(
            self.change_options_mode_signal)
        self.change_options_mode_signal(self.options_mode)

        options_zone.setLayout(self.options_zone_layout)

        # Add files button and final structures ---------------------------
        add_file_button = QPushButton("Add Files")
        add_file_button.clicked.connect(self.click_add_files)
        controls_layout.addWidget(select_zone)
        controls_layout.addWidget(options_zone)
        controls_layout.addWidget(add_file_button)

        # image preview ---------------------------------------------------
        image_prev_layout = QVBoxLayout()
        image_prev_layout.setContentsMargins(0, 0, 4, 0)
        self.IMG_PREVIEW_WIDTH = 256
        self.img_label = QLabel()
        self.img_label.setAlignment(Qt.AlignCenter)
        self.select_text = "Click item to preview"
        self.last_created_pix_path = ""
        self.img_label.setText(self.select_text)
        image_prev_layout.addWidget(self.img_label)
        # slider for the preview scale
        self.img_scale_slider = QSlider()
        self.img_scale_slider.setMinimum(6)
        self.img_scale_slider.setMaximum(2048)
        self.img_scale_slider.setValue(self.IMG_PREVIEW_WIDTH)
        self.img_scale_slider.setOrientation(Qt.Horizontal)
        self.img_scale_slider.valueChanged.connect(
            self.change_scale_slider_signal)
        image_prev_layout.addWidget(self.img_scale_slider)
        self._update_preview()

        layout.addLayout(image_prev_layout)
        layout.addWidget(self.list_view)
        layout.addLayout(controls_layout)
        self.setLayout(layout)
        self.update_status_combobox = True

    def _pillow_to_pixmap(self, img):
        if img.mode == "RGB":
            r, g, b = img.split()
            img = Image.merge("RGB", (b, g, r))
        elif img.mode == "RGBA":
            r, g, b, a = img.split()
            img = Image.merge("RGBA", (b, g, r, a))
        elif img.mode == "L":
            img = img.convert("RGBA")
        img2 = img.convert("RGBA")
        data = img2.tobytes("raw", "RGBA")
        qim = QImage(data, img.size[0], img.size[1], QImage.Format_ARGB32)
        pixmap = QPixmap.fromImage(qim)
        return pixmap

    def _update_preview(self):
        self.img_label.setMinimumWidth(self.IMG_PREVIEW_WIDTH)
        self.img_label.setMaximumWidth(
            max(self.IMG_PREVIEW_WIDTH, self.img_scale_slider.width()))
        if len(self.last_created_pix_path) > 0:
            img = Image.open(self.last_created_pix_path)
            img_pix = self._pillow_to_pixmap(img)
            img_pix = img_pix.scaled(
                QSize(self.IMG_PREVIEW_WIDTH, self.IMG_PREVIEW_WIDTH),
                Qt.KeepAspectRatio)
            self.img_label.setPixmap(img_pix)

    def _set_preview(self, img_path):
        if img_path is None:
            self.last_created_pix_path = ""
            self.img_label.setText(self.select_text)
        else:
            if img_path != self.last_created_pix_path:
                self.last_created_pix_path = img_path
                self._update_preview()

    def _add_items_to_mode_combobox(self, combobox):
        combobox.addItem("From Source")
        combobox.addItem("A4")
        # combobox.addItem("A5")
        # combobox.addItem("A6")
        # combobox.addItem("Letter")

    def _get_filtered_string(self, string):
        to_return_array = []
        for s in string:
            if s.isdigit():
                to_return_array.append(s)
        return "".join(to_return_array)

    def get_images_to_save(self):
        path_array = []
        for i in range(self.list_view.count()):
            path_array.append(self.list_view.item(i).get_data())
        return path_array

    def get_image_parameters(self):  # return as dictionary
        if self.options_mode == 0:
            return {
                "mode": 0,
                "pixels": self.option_source_widget.get_pixel_value(),
                "margin": self.option_source_widget.get_margin_value(),
                "background": self.option_source_widget.get_background_value()
            }
        else:
            return {
                "mode": self.options_mode,
                "align": self.options_a_widget.get_align_value(),
                "margin": self.options_a_widget.get_margin_value(),
                "background": self.options_a_widget.get_background_value()
            }

    def add_items(self, array):
        added_names = []
        for a in array:
            new_name = os.path.basename(a)
            new_item = ImageListItem(new_name, a)
            added_names.append(new_name)
            self.list_view.addItem(new_item)
        self.status_bar.showMessage("Add items: " + ", ".join(added_names))

    def change_scale_slider_signal(self, value):
        self.IMG_PREVIEW_WIDTH = value
        self._update_preview()
        self.status_bar.showMessage("Set preview scale to " + str(value))

    def click_item_signal(self, item):
        pass
        # self._set_preview(item.get_data())
        # self.status_bar.showMessage("Select " + str(item.text()))

    def _get_first_new_index(self, current, last):
        for v in current:
            if v not in last:
                return v
        return current[0]

    def change_selection_signal(self):
        if len(self.list_view.selectedItems()) == 0:
            self._set_preview(None)  # nothing selected
        else:
            selected_indexes = [
                self.list_view.indexFromItem(sel).row()
                for sel in self.list_view.selectedItems()
            ]
            item = self.list_view.item(
                self._get_first_new_index(selected_indexes,
                                          self.last_selected_items))
            self._set_preview(item.get_data())
            self.status_bar.showMessage("Select " + str(item.text()))
            self.last_selected_items = selected_indexes

    def change_options_mode_signal(self, index):
        self.options_mode = index
        if self.options_mode == 0:
            self.options_zone_layout.removeWidget(self.options_a_widget)
            self.options_a_widget.setParent(None)
            self.options_zone_layout.addWidget(self.option_source_widget)
        else:
            self.options_zone_layout.removeWidget(self.option_source_widget)
            self.option_source_widget.setParent(None)
            self.options_zone_layout.addWidget(self.options_a_widget)
        if self.update_status_combobox:
            self.status_bar.showMessage(
                "Set combine mode to \"" +
                self.options_mode_combobox.itemText(index) + "\"")

    def resizeEvent(self, size):
        # self._update_preview()
        pass

    def click_move_up(self):
        selected = self.list_view.selectedItems()
        selected_indexes = [
            self.list_view.indexFromItem(sel).row() for sel in selected
        ]
        selected_indexes.sort()
        if len(selected_indexes) > 0 and selected_indexes[0] > 0:
            for index in selected_indexes:
                prev_item = self.list_view.takeItem(index - 1)
                self.list_view.insertItem(index, prev_item)
            self.status_bar.showMessage("Move " + str(len(selected_indexes)) +
                                        " items")
        else:
            self.status_bar.showMessage("Nothing to move")

    def click_move_down(self):
        selected = self.list_view.selectedItems()
        selected_indexes = [
            self.list_view.indexFromItem(sel).row() for sel in selected
        ]
        selected_indexes.sort()
        sel_count = len(selected_indexes)
        if len(selected_indexes) > 0 and selected_indexes[
                sel_count - 1] < self.list_view.count() - 1:
            for i_index in range(sel_count):
                next_item = self.list_view.takeItem(
                    selected_indexes[sel_count - i_index - 1] + 1)
                self.list_view.insertItem(
                    selected_indexes[sel_count - i_index - 1], next_item)
            self.status_bar.showMessage("Move " + str(len(selected_indexes)) +
                                        " items")
        else:
            self.status_bar.showMessage("Nothing to move")

    def click_invert(self):
        selected = self.list_view.selectedItems()
        selected_indexes = []
        for sel in selected:
            selected_indexes.append(self.list_view.indexFromItem(sel).row())
        total_indexes = [i for i in range(self.list_view.count())]
        new_indexes = []
        for i in total_indexes:
            if i not in selected_indexes:
                new_indexes.append(i)
        self.list_view.clearSelection()
        for i in new_indexes:
            self.list_view.item(i).setSelected(True)
        self.status_bar.showMessage("Invert selection: " + str(new_indexes))

    def click_delete(self):
        selected = self.list_view.selectedItems()
        delete_names = []
        for s in selected:
            s_index = self.list_view.indexFromItem(s).row()
            del_item = self.list_view.takeItem(s_index)
            delete_names.append(del_item.text())
        if len(delete_names) == 0:
            self.status_bar.showMessage("Nothing to delete")
        else:
            self.status_bar.showMessage("Delete items: " +
                                        ", ".join(delete_names))

    def click_add_files(self):
        files_dialog = QFileDialog()
        files_dialog.setNameFilter("Images (*.jpg *.jpeg *.bmp *.png *.tiff)")
        files_dialog.setFileMode(QFileDialog.ExistingFiles)
        if files_dialog.exec_():
            files = files_dialog.selectedFiles()
            self.add_items(files)
Exemple #22
0
class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self, parent=None)
        self.settings = QSettings(ORGANIZATION_STR)
        self.toolbar = self.createToolBar()

        self.widget = QWidget(self)
        self.layout = QVBoxLayout(self.widget)
        self.layout.setContentsMargins(1, 1, 1, 1)
        self.currentWidget = None

        self.editor = QTextEdit()
        self.editor.setAcceptRichText(False)

        font = QFontDatabase.systemFont(QFontDatabase.FixedFont)
        fs = int(self.settings.value("fontSize", 13))
        font.setPointSize(fs)

        self.editor.setFont(font)
        self.preview = MarkdownRenderer()

        self.layout.addWidget(self.toolbar)
        self.widget.setLayout(self.layout)

        self.showWidget(self.editor)

        self.addToolBar(self.toolbar)
        self.setCentralWidget(self.widget)

        self.setWindowTitle(BASIC_TITLE)

        self.nbManager = NotebookManager()

        self.currentNotebook = None
        self.currentNote = None
        self.dirty = False

        self.editor.document().modificationChanged.connect(self.editorModified)

        self.updateUI()

        if len(self.nbManager.notebooks()) > 0:
            self.switchNotebook(self.nbManager.notebooks()[0].name)

        self.createTrayIcon()

        self.readConfig()

    def closeEvent(self, event):
        self.nbManager.writeConfig()
        self.writeConfig()

        QMainWindow.closeEvent(self, event)

    def showWidget(self, w):
        if self.currentWidget is not None:
            self.currentWidget.hide()
            self.layout.removeWidget(self.currentWidget)

        self.layout.addWidget(w)
        #self.layout.update()
        self.currentWidget = w
        self.currentWidget.show()

    def createToolBar(self):
        toolbar = QToolBar()

        act = toolbar.addAction(QIcon.fromTheme("document-new"),
                                "Create a new note", self.newNote)
        act.setShortcut(QKeySequence.New)
        toolbar.addAction(QIcon.fromTheme("folder-new"),
                          "Create a new notebook", self.newNotebook)
        toolbar.addSeparator()

        act = toolbar.addAction(QIcon.fromTheme("document-save"),
                                "Save changes to current note", self.saveNote)
        act.setShortcut(QKeySequence.Save)
        toolbar.addAction(QIcon.fromTheme("document-send"),
                          "Export current note")
        toolbar.addSeparator()

        toolbar.addAction(QIcon.fromTheme("format-text-bold"), "Bold")
        toolbar.addAction(QIcon.fromTheme("format-text-italic"), "Italic")
        toolbar.addAction(QIcon.fromTheme("format-text-underline"),
                          "Underline")

        self.headingsCombo = QComboBox()
        self.headingsCombo.addItem("H1")
        self.headingsCombo.addItem("H2")
        self.headingsCombo.addItem("H3")
        self.headingsCombo.addItem("H4")
        self.headingsCombo.addItem("H5")
        self.headingsCombo.addItem("H6")

        toolbar.addWidget(self.headingsCombo)
        toolbar.addSeparator()

        toolbar.addAction(QIcon.fromTheme("format-list-unordered"),
                          "Insert bulleted list")
        toolbar.addAction(QIcon.fromTheme("format-list-ordered"),
                          "Insert numbered list")
        toolbar.addAction(QIcon.fromTheme("insert-link"), "Inserts a link")
        toolbar.addSeparator()

        self.editableAction = toolbar.addAction(
            QIcon.fromTheme("edit"), "Toggle edit or markdown visualizer")
        self.editableAction.setCheckable(True)
        self.editableAction.setChecked(True)
        self.editableAction.setShortcut(QKeySequence("Ctrl+E"))
        QObject.connect(self.editableAction, SIGNAL('triggered(bool)'),
                        self.editTriggered)

        toolbar.addAction(QIcon.fromTheme("system-search"), "Search")

        self.notebooksCombo = QComboBox()
        self.notebooksCombo.setSizePolicy(QSizePolicy.Expanding,
                                          QSizePolicy.Preferred)
        self.notebooksCombo.addItem(QIcon.fromTheme("folder"),
                                    "Create new notebook")

        self.notesCombo = QComboBox()
        self.notesCombo.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Preferred)

        QObject.connect(self.notebooksCombo, SIGNAL("activated(QString)"),
                        self.switchNotebook)
        QObject.connect(self.notesCombo, SIGNAL("activated(QString)"),
                        self.switchNote)

        self.spacer = QWidget()
        self.spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)

        toolbar.addWidget(self.spacer)
        toolbar.addWidget(self.notebooksCombo)
        toolbar.addWidget(self.notesCombo)

        return toolbar

    def createTrayIcon(self):
        path = os.path.join(
            pathlib.Path(__file__).parent.absolute(), "icons/notes.svg")
        icon = QIcon(QPixmap(path))

        self.trayIcon = QSystemTrayIcon(icon, self)
        self.trayMenu = None

        QObject.connect(self.trayIcon,
                        SIGNAL("activated(QSystemTrayIcon::ActivationReason)"),
                        self.trayIconActivated)

        self.populateTrayMenu()
        self.trayIcon.show()

    def trayIconActivated(self, reason):
        if reason != QSystemTrayIcon.Trigger:
            return

        if self.isVisible():
            self.savedGeometry = self.saveGeometry()
            self.hide()
        else:
            self.show()
            self.activateWindow()
            self.restoreGeometry(self.savedGeometry)

    def populateTrayMenu(self):
        del self.trayMenu
        self.trayMenu = QMenu()

        self.trayMenu.addAction(QIcon.fromTheme("folder-new"),
                                "Create a new notebook", self.newNotebook)
        self.trayMenu.addSeparator()

        for notebook in self.nbManager.notebooks():
            nbMenu = self.trayMenu.addMenu(QIcon.fromTheme("folder"),
                                           notebook.name)

            nbMenu.addAction(QIcon.fromTheme("document-new"),
                             "Create a new note", self.newNote)
            nbMenu.addSeparator()

            for note in notebook.notes():
                nbMenu.addAction(QIcon.fromTheme("text-x-generic"), note.name)

        self.trayMenu.addSeparator()
        self.trayMenu.addAction(QIcon.fromTheme("application-exit"), "&Quit",
                                QApplication.instance().quit)

        self.trayIcon.setContextMenu(self.trayMenu)

    def editTriggered(self, checked):
        if checked:
            self.showWidget(self.editor)
        else:
            self.preview.displayMarkdown(self.editor.toPlainText())
            self.showWidget(self.preview)

    def readConfig(self):
        if self.settings.contains("geometry"):
            geometry = self.settings.value("geometry")
            self.restoreGeometry(geometry)

    def writeConfig(self):
        geometry = self.saveGeometry()

        self.settings.setValue("geometry", geometry)

    def updateUI(self):
        self.notebooksCombo.clear()

        for notebook in self.nbManager.notebooks():
            self.notebooksCombo.addItem(QIcon.fromTheme("folder"),
                                        notebook.name)

        if self.currentNotebook is not None:
            self.notesCombo.clear()

            for note in self.currentNotebook.notes():
                self.notesCombo.addItem(QIcon.fromTheme("text-x-generic"),
                                        note.name)

        if self.currentNotebook is not None and self.currentNote is not None:
            title = BASIC_TITLE + " - {}/{}".format(self.currentNotebook.name,
                                                    self.currentNote.name)

            if self.dirty:
                title += " (Modified)"
        else:
            title = BASIC_TITLE

        self.setWindowTitle(title)

    def switchNotebook(self, notebookName):
        self.currentNotebook = self.nbManager.notebook(notebookName)
        self.updateUI()

        # If notebook not empty, switch to first note.
        if len(self.currentNotebook.notes()) > 0:
            self.switchNote(self.currentNotebook.notes()[0].name)
        # If not, request creation of a new note
        else:
            self.newNote()

        self.notebooksCombo.setCurrentText(notebookName)

    def switchNote(self, noteName):
        self.currentNote = self.currentNotebook.note(noteName)
        self.editor.setPlainText(self.currentNote.contents)
        self.preview.displayMarkdown(self.currentNote.contents)

        self.updateUI()

        self.notesCombo.setCurrentText(noteName)

    def newNotebook(self):
        name, ok = QInputDialog.getText(
            self, "Notebook name",
            "How would you like your notebook to be named?")

        if ok:
            storagePath = QDir.homePath() + "/.config/wikinotebook/" + name

            nb = self.nbManager.createNewNotebook(name, storagePath)
            self.switchNotebook(nb.name)

    def newNote(self):
        if self.currentNotebook is None:
            return

        name, ok = QInputDialog.getText(
            self, "Note name", "How would you like your note to be named?")

        if ok:
            note = self.currentNotebook.createNewNote(name)
            self.switchNote(note.name)

    def saveNote(self):
        self.currentNote.contents = self.editor.toPlainText()
        self.currentNote.save()

        self.dirty = False
        self.editor.document().setModified(False)
        self.updateUI()

    def editorModified(self, changed):
        self.dirty = changed
        self.updateUI()