Пример #1
0
class AppDemo(QWidget):
    ppt = PPTController()

    def __init__(self):
        app = QApplication(sys.argv)
        # 화면 전환용 widget 설정
        self.widget = QStackedLayout()

        # 레이아웃 생성
        self.introLayout = IntroLayout()
        self.guideLayout = GuideLayout()
        self.fileUploadLayout = FileUploadLayout(self)
        self.webcamLayout = WebcamLayout()

        # widget 추가
        self.widget.addWidget(self.introLayout)
        self.widget.addWidget(self.guideLayout)
        self.widget.addWidget(self.fileUploadLayout)
        self.widget.addWidget(self.webcamLayout)

        self.introLayout.nextButton.clicked.connect(lambda: self.nextPage())

        self.guideLayout.nextButton.clicked.connect(lambda: self.nextPage())
        self.guideLayout.backButton.clicked.connect(lambda: self.backPage())

        self.fileUploadLayout.backButton.clicked.connect(
            lambda: self.backPage())
        self.fileUploadLayout.camTestButton.clicked.connect(
            lambda: self.nextPage())

        self.webcamLayout.backButton.clicked.connect(lambda: self.backPage())

        app.exec_()

    def start(self):
        self.webcamLayout.start()

    def nextPage(self):
        # max page : 4
        if self.widget.currentIndex() < 3:
            self.widget.setCurrentIndex(self.widget.currentIndex() + 1)

    def backPage(self):
        if self.widget.currentIndex() > 0:
            self.widget.setCurrentIndex(self.widget.currentIndex() - 1)
Пример #2
0
class Window(BaseWindow):
    def __init__(self):
        super(Window, self).__init__()

        self.last_index = 0

        self.setFixedSize(WINDOW_WIDTH, WINDOW_HEIGHT)
        # 要想使 move_center 起作用,必须设置 resize
        self.resize(WINDOW_WIDTH, WINDOW_HEIGHT)
        self.move_center()
        self.setWindowIcon(QIcon(abs_path('static/images/icon/logo.png')))
        self.setWindowTitle('江科大课表导出 v1.0')

        self.stack_layout = QStackedLayout()
        self.stack_layout.addWidget(StepHello(self.stack_layout))
        self.stack_layout.addWidget(StepAccount(self.stack_layout))
        self.stack_layout.addWidget(StepDate(self.stack_layout))
        self.stack_layout.addWidget(StepSuccess(self.stack_layout))
        self.stack_layout.addWidget(StepMistake(self.stack_layout))
        self.stack_layout.setCurrentIndex(self.last_index)
        self.stack_layout.currentChanged.connect(self.interface_changed)

        self.setLayout(self.stack_layout)
        self.show()

    def interface_changed(self):
        if self.last_index < self.stack_layout.currentIndex():
            self.last_index = self.stack_layout.currentIndex()
        elif self.last_index == 4 and self.stack_layout.currentIndex() == 0:
            for i in range(3)[::-1]:
                self.stack_layout.widget(i).step_ani(True)
            self.last_index = 0
        elif self.last_index in [3, 4
                                 ] and self.stack_layout.currentIndex() == 2:
            self.stack_layout.widget(2).step_ani(True)
            self.last_index = 2
        elif self.last_index == 2 and self.stack_layout.currentIndex() == 1:
            self.stack_layout.widget(1).step_ani(True)
            self.last_index = 1
        elif self.last_index == 1 and self.stack_layout.currentIndex() == 0:
            self.stack_layout.widget(0).step_ani(True)
            self.last_index = 0
class AbstractTemplateWidget(QFrame):
    """
    TemplateWidget is used in reports and options tab.
    So it needs several common methods and common layout.
    But behavior is different. it should be defined in children classes.
    """
    def __init__(self, main_window, items):
        super().__init__()

        self.items = items
        self.visible_items = []
        self.layout = QStackedLayout()
        self.menu_layout = QVBoxLayout()
        self.templates_layout = QStackedLayout()
        self.showEvent = self._get_show_event(main_window)
        self.menu_wrapper = QVBoxLayout()

        try:
            self.ACTION_BTN_ICON
        except AttributeError:
            self.ACTION_BTN_ICON = ''

        self.setLayout(self.layout)

        self.layout.addWidget(self._get_static_widgets())

    def _get_static_widgets(self):
        """
        Create layout that does not depend on content.
        """

        hbox = QHBoxLayout()
        self.menu_wrapper.addWidget(utils.get_scrollable(self.menu_layout))
        hbox.addLayout(self.menu_wrapper, stretch=30)
        hbox.addLayout(self.templates_layout, stretch=70)
        widget = QWidget()
        widget.setLayout(hbox)
        widget.setGraphicsEffect(utils.get_shadow())
        return widget

    def _iterate_items(self):
        """
        Filter items if they has no values.
        """
        pass

    def hideEvent(self, event):
        """
        Clear menu and templates.
        """

        utils.clear_layout(self.menu_layout)
        utils.clear_layout(self.templates_layout)

    def _get_show_event(self, main_window):
        """
        Update templates list and re-select them.
        """
        def show_event(event):
            utils.clear_layout(self.menu_layout)
            utils.clear_layout(self.templates_layout)

            self.visible_items = self._iterate_items()
            self._show_menu()
            self._show_templates()
            if not self.layout.currentIndex():
                main_window.communication.action_button_toggle.emit(
                    bool(self.visible_items), self.ACTION_BTN_ICON,
                    self.action_btn_function)

        return show_event

    def _show_menu(self):
        """
        Update menu on showEvent.
        """

        for i, item in enumerate(self.visible_items):
            b = QRadioButton(self._get_button_name(item))
            b.setChecked(i == 0)
            b.clicked.connect(
                functools.partial(self.templates_layout.setCurrentIndex, i))
            b.setObjectName('menu_button')
            self.menu_layout.addWidget(b)

        if not self.visible_items:
            self.menu_layout.addStretch()
            # l = QLabel('Чтобы создать отчет\nначните заполнять данные')
            l = QLabel(
                'Para criar um relatório,\ninicie os dados de preenchimento')
            l.setAlignment(Qt.AlignCenter)
            self.menu_layout.addWidget(l)

        self.menu_layout.addStretch()

    def _show_templates(self):
        """
        Update templates on shoeEvent.
        """

        cols = 3
        templates = template_module.Template.get_all()
        check_templates = []

        for j, item in enumerate(self.visible_items):
            if not templates[item.id]:
                # l = QLabel('Нет шаблонов для данного объекта\nУправлять шаблонами можно на вкладке настроек')
                l = QLabel(
                    'Não há modelos para este objeto\nOs modelos de gerenciamento podem estar na guia de configurações'
                )
                l.setAlignment(Qt.AlignCenter)
                self.templates_layout.addWidget(l)
                continue
            layouts = [QVBoxLayout() for _ in range(cols)]
            for i, each in enumerate(templates[item.id]):
                b = QRadioButton(each.name)
                b.setChecked(item.template == each)
                b.clicked.connect(
                    functools.partial(self._template_clicked, j, each))
                if len(templates[item.id]) == 1:
                    check_templates.append((b, j, each))
                b.mouseDoubleClickEvent = functools.partial(
                    self.open_template_edit_widget, j, each)
                layouts[i % cols].addWidget(b)

            wrapper = QHBoxLayout()
            for each in layouts:
                each.addStretch()
                wrapper.addLayout(each, stretch=int(100 / cols))
            self.templates_layout.addWidget(utils.get_scrollable(wrapper))
        for i, each in enumerate(check_templates):
            b, j, template = each
            self._template_clicked(j, template, i == 0)
            b.setChecked(True)

    def _template_selected(self, index, template):
        """
        Change menu item name.
        Add template for the item.
        """

        self.visible_items[index].template = template
        buttons = self.findChildren(QRadioButton, name='menu_button')
        buttons[index].setText(self._get_button_name(
            self.visible_items[index]))
        for i in range(len(self.visible_items)):
            ind = (i + index) % len(self.visible_items)
            if not self.visible_items[ind].template:
                self.templates_layout.setCurrentIndex(ind)
                buttons[ind].setChecked(True)
                buttons[index].setChecked(False)
                return

    def _get_button_name(self, item):
        pass

    def _double_click(self, index, template, event):
        pass

    def _template_clicked(self, index, template, show_next=False):
        pass

    def action_btn_function(self, event):
        pass

    def open_template_edit_widget(self, index, template, event):
        pass
Пример #4
0
class TimerWidget(QWidget, ClockAssets):
    # widget containing the timer and all methods associated with it

    def __init__(self):
        super().__init__()

        self.timer_duration = QTime(0, 5, 0)
        self.zero_time = QTime(0, 0, 0)
        self.timer_is_running = False

        self.timer = QTimer()
        self.timer.timeout.connect(self.update_timer)

        self.init_window()

    def init_window(self):

        self.stack = QStackedLayout()
        self.stack.addWidget(self.create_timer_window())
        self.stack.addWidget(self.create_change_time_window())

        self.setLayout(self.stack)

    def change_window(self, index):
        self.stack.setCurrentIndex(index)

        if self.stack.currentIndex() == 0:
            self.display_timer_time()
            self.change_timer_button_logo("play")
            self.toggle_timer_button.setDisabled(False)

        elif self.stack.currentIndex() == 1:
            # stops timer if user goes to change_time window
            self.stop_timer()

    # WINDOW
    def create_timer_window(self):
        # shows timer window

        self.timer_time = self.timer_duration

        self.timer_time_label = QLabel()
        self.timer_time_label.setAlignment(Qt.AlignCenter)
        self.timer_time_label.setFont(QFont("Arial", 20))

        self.display_timer_time()

        self.change_time_button = QPushButton("Change Time")
        self.change_time_button.setFixedWidth(200)
        self.change_time_button.clicked.connect(lambda: self.change_window(1))

        self.reset_timer_button = QPushButton()
        self.reset_timer_button.setIcon(QIcon(self.reset_icon))
        self.reset_timer_button.setFixedWidth(200)
        self.reset_timer_button.clicked.connect(self.reset_timer)

        self.toggle_timer_button = QPushButton()
        self.toggle_timer_button.setIcon(QIcon(self.play_icon))
        self.toggle_timer_button.setFixedWidth(200)
        self.toggle_timer_button.clicked.connect(self.toggle_timer)

        if self.timer_time == self.zero_time:
            self.toggle_timer_button.setDisabled(True)
        else:
            self.toggle_timer_button.setDisabled(False)

        self.vbox = QVBoxLayout()
        self.vbox.addWidget(self.timer_time_label)
        self.vbox.addWidget(self.change_time_button, alignment=Qt.AlignHCenter)
        self.vbox.addWidget(self.reset_timer_button,
                            alignment=Qt.AlignHCenter,
                            stretch=1)
        self.vbox.addWidget(self.toggle_timer_button,
                            alignment=Qt.AlignHCenter,
                            stretch=2)

        self.timer_widget = QWidget()
        self.timer_widget.setLayout(self.vbox)

        return self.timer_widget

    def display_timer_time(self):
        self.timer_time_label.setText(self.timer_time.toString("hh:mm:ss"))

    # EFFECT
    def change_timer_button_logo(self, action):

        if action == "play":
            self.toggle_timer_button.setIcon(QIcon(self.play_icon))
        elif action == "pause":
            self.toggle_timer_button.setIcon(QIcon(self.pause_icon))

    # EFFECT
    def play_alarm_sound_effect(self):
        # plays sound effect

        self.sound_effect = QSound(self.alarm_sound)
        self.sound_effect.play()

    def toggle_timer(self):
        # starts timer if it's not running or
        # stops timer if it is running

        if self.timer_is_running:
            self.timer_is_running = False
            self.change_timer_button_logo("play")
            self.stop_timer()
        else:
            # resume playing timer
            if self.timer_time != self.zero_time:
                self.timer_is_running = True
                self.change_timer_button_logo("pause")
                self.start_timer()

    def start_timer(self):
        # starts timer countdown

        self.timer.start(1000)

    def stop_timer(self):
        self.timer.stop()

    def update_timer(self):
        # updates timer's time every 1 second

        # decrements one second from time
        self.timer_time = self.timer_time.addSecs(-1)

        if self.timer_time == self.zero_time:
            self.stop_timer()
            self.timer_is_running = False
            self.change_timer_button_logo("play")
            self.toggle_timer_button.setDisabled(True)
            self.play_alarm_sound_effect()

        self.display_timer_time()

    def reset_timer(self):
        # changes timer countdown back to normal

        self.timer_time = self.timer_duration
        self.display_timer_time()

        if self.timer_time == self.zero_time:
            self.toggle_timer_button.setDisabled(True)
        else:
            self.toggle_timer_button.setDisabled(False)

    # WINDOW
    def create_change_time_window(self):
        # shows change time window

        self.stop_timer()

        self.hour_input = QLineEdit()
        self.hour_input.setAlignment(Qt.AlignHCenter)
        self.hour_input.setValidator(QIntValidator())
        self.hour_input.setText(self.timer_duration.toString("hh"))

        self.hour_label = QLabel("HH")

        self.minute_input = QLineEdit()
        self.minute_input.setAlignment(Qt.AlignHCenter)
        self.minute_input.setValidator(QIntValidator())
        self.minute_input.setText(self.timer_duration.toString("mm"))

        self.minute_label = QLabel("MM")

        self.second_input = QLineEdit()
        self.second_input.setAlignment(Qt.AlignHCenter)
        self.second_input.setValidator(QIntValidator())
        self.second_input.setText(self.timer_duration.toString("ss"))

        self.second_label = QLabel("SS")

        self.grid_layout = QGridLayout()
        self.grid_layout.addWidget(self.hour_input, 0, 0)
        self.grid_layout.addWidget(self.hour_label,
                                   1,
                                   0,
                                   alignment=Qt.AlignHCenter)

        self.grid_layout.addWidget(self.minute_input, 0, 1)
        self.grid_layout.addWidget(self.minute_label,
                                   1,
                                   1,
                                   alignment=Qt.AlignHCenter)

        self.grid_layout.addWidget(self.second_input, 0, 2)
        self.grid_layout.addWidget(self.second_label,
                                   1,
                                   2,
                                   alignment=Qt.AlignHCenter)

        self.set_time_button = QPushButton("Set Time")
        self.set_time_button.clicked.connect(self.check_time_input)

        self.vbox = QVBoxLayout()
        self.vbox.addStretch()
        self.vbox.addLayout(self.grid_layout)
        self.vbox.addStretch()
        self.vbox.addWidget(self.set_time_button)

        self.change_time_widget = QWidget()
        self.change_time_widget.setLayout(self.vbox)

        return self.change_time_widget

    def check_time_input(self):
        # checks if user's HH, MM, SS in Change Time Window
        # are valid inputs

        hours = self.hour_input.text()
        minutes = self.minute_input.text()
        seconds = self.second_input.text()

        if hours == "":
            hours = 0
        if minutes == "":
            minutes = 0
        if seconds == "":
            seconds = 0

        hours = int(hours)
        minutes = int(minutes)
        seconds = int(seconds)

        if hours >= 0 and minutes >= 0 and seconds >= 0:
            if hours < 24 and minutes < 60 and seconds < 60:

                if hours == 0 and minutes == 0 and seconds == 0:
                    self.show_button_effect()
                else:
                    self.timer_duration = QTime(hours, minutes, seconds)
                    self.change_window(0)

                    self.timer_time = self.timer_duration
                    self.display_timer_time()
            else:
                # button turns red to give user feedback
                self.show_button_effect()
        else:
            self.show_button_effect()

    # EFFECT
    def show_button_effect(self):
        # changes button's color to red and returns back to normal after half a second

        self.set_time_button.setStyleSheet("background-color: red")
        QTimer.singleShot(500, self.reset_button_color)

    # EFFECT
    def reset_button_color(self):
        # resets buttons color back to light grey

        self.set_time_button.setStyleSheet("background-color: light grey")
class ComboEditor(QDialog):

    closeSplit = pyqtSignal(QWidget)
    aboutToCloseComboEditor = pyqtSignal()
    allFilesClosed = pyqtSignal()
    splitEditor = pyqtSignal("QWidget*", "QWidget*", bool)
    recentTabsModified = pyqtSignal()

    class NAVIGATE:
        prev = 0
        next = 1

    Q_ENUMS(NAVIGATE)

    def __init__(self, original=False, Force_Free=False):
        super(ComboEditor, self).__init__(None)  #, Qt.WindowStaysOnTopHint)
        self.__original = original
        self.Force_Free = Force_Free
        self.__undocked = []
        self._single_undocked = []
        self._symbols_index = []
        self.__OFiles = []
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)

        self.bar = ActionBar(self, main_combo=original)
        vbox.addWidget(self.bar)

        self.stackedEditor = QStackedLayout()
        vbox.addLayout(self.stackedEditor)

        self._main_container = IDE.get_service('main_container')

        if not self.__original and not self.Force_Free:
            self._main_container.fileOpened.connect(self._file_opened_by_main)

        # QApplication.instance().focusChanged["QWidget*", "QWidget*"].connect(\
        #     lambda w1, w2: QTimer.singleShot(10, lambda w1=w1, w2=w2: print("\n\nQApplication::focusChanged::", w1, w2)))

        self.bar.combo.showComboSelector.connect(
            self._main_container.change_tab)
        self.bar.changeCurrent.connect(self._set_current)
        self.bar.editorSplited.connect(self.split_editor)
        self.bar.runFile[str].connect(self._run_file)
        self.bar.closeFile.connect(lambda: self.closeSplit.emit(self))
        self.bar.addToProject[str].connect(self._add_to_project)
        self.bar.showFileInExplorer.connect(self._show_file_in_explorer)
        self.bar.goToSymbol.connect(self._go_to_symbol)
        self.bar.undockEditor.connect(self.undock_editor)
        self.bar.undockThisEditor.connect(self.single_undock_editor)
        self.bar.reopenTab[str].connect(self._main_container.open_file)
        self.bar.recentTabsModified.connect(
            self._main_container.recent_files_changed)
        self.bar.code_navigator.btnPrevious.clicked['bool'].connect(
            lambda: self._navigate_code(self.NAVIGATE.prev))
        self.bar.code_navigator.btnNext.clicked['bool'].connect(
            lambda: self._navigate_code(self.NAVIGATE.prev))

        # QTimer.singleShot(39999, lambda : print("\n\ncombo:-:", self))

    # def closeEvent(self, event):
    #     for comboeditor in self._single_undocked:
    #         print("has undocked", comboeditor)
    #         comboeditor.reject()
    #         comboeditor.deleteLater()

    #     self.bar._close_all_files()
    #     super(ComboEditor, self).closeEvent(event)

    def _navigate_code(self, val):
        op = self.bar.code_navigator.operation
        self._main_container.navigate_code_history(val, op)

    def setFocus(self):
        super(ComboEditor, self).setFocus()
        w = self.stackedEditor.currentWidget()
        if w:
            w.setFocus()
        self._editor_with_focus()

    def _file_opened_by_main(self, path):
        index = self.stackedEditor.currentIndex()
        ninjaide = IDE.getInstance()
        editable = ninjaide.get_or_create_editable(path)
        print("_file_opened_by_main", editable)
        self.add_editor(editable)
        self.bar.set_current_by_index(index)
        if index == -1:
            self.bar.set_current_by_index(0)

    def add_editor(self, neditable, keep_index=False):
        """Add Editor Widget to the UI area."""
        if neditable.editor:
            if self.__original or self.Force_Free:
                editor = neditable.editor
                print("\n\nadd_editor() ignora por ahora!", editor)

                # disconnect old Signals
                try:
                    editor.cursorPositionChanged[int, int].disconnect()
                except TypeError:
                    pass
                try:
                    editor.editorFocusObtained.disconnect()
                except TypeError:
                    pass
                try:
                    editor.currentLineChanged.disconnect()
                except TypeError:
                    pass
                try:
                    editor.modificationChanged['bool'].disconnect()
                except TypeError:
                    pass
                try:
                    neditable.checkersUpdated.disconnect()
                except TypeError:
                    pass
                try:
                    neditable.fileSaved.disconnect()
                except TypeError:
                    pass

                # Disonnect file system signals only in the original
                try:
                    neditable.fileClosing.disconnect()
                except TypeError:
                    pass
                if self.__original:
                    try:
                        neditable.askForSaveFileClosing.disconnect()
                    except TypeError:
                        pass
                    try:
                        neditable.fileChanged.disconnect()
                    except TypeError:
                        pass

            else:
                editor = self._main_container.create_text_editor_from_editable(
                    neditable)

            index = self.stackedEditor.currentIndex()
            self.stackedEditor.addWidget(editor)
            self.bar.add_item(neditable.display_name, neditable)
            if keep_index:
                self.bar.set_current_by_index(index)

            # Editor Signals
            editor.cursorPositionChanged[int, int].connect(
                self._update_cursor_position)
            editor.editorFocusObtained.connect(self._editor_with_focus)
            editor.currentLineChanged.connect(self._set_current_symbol)
            editor.modificationChanged['bool'].connect(self._editor_modified)
            neditable.checkersUpdated.connect(self._show_notification_icon)
            neditable.fileSaved.connect(self._update_symbols)
            neditable.fileSaved.connect(self._update_combo_info)

            # Connect file system signals only in the original
            neditable.fileClosing.connect(self._close_file)
            if self.__original:
                neditable.askForSaveFileClosing.connect(self._ask_for_save)
                neditable.fileChanged.connect(self._file_has_been_modified)

            # Load Symbols
            self._load_symbols(neditable)

    def show_combo_file(self):
        print("show_combo_file")
        self.bar.combo.showPopup()

    def show_combo_symbol(self):
        self.bar.symbols_combo.showPopup()

    def getOpenedFiles(self):
        return self.__OFiles.copy()

    def addOpenedFiles(self, fil):
        self.__OFiles.append(fil)

    def unlink_editors(self):
        for index in range(self.stackedEditor.count()):
            widget = self.stackedEditor.widget(index)
            widget.setDocument(QsciDocument())

    def split_editor(self, orientationVertical):
        new_widget = ComboEditor()
        for neditable in self.bar.get_editables():
            print("\nsplit_editor", neditable, new_widget)
            new_widget.add_editor(neditable)
        self.splitEditor.emit(self, new_widget, orientationVertical)

    def undock_editor(self):
        new_combo = ComboEditor()
        new_combo.setWindowTitle("NINJA-IDE")
        self.add_Undocked(new_combo)
        for neditable in self.bar.get_editables():
            print("undock_editor", neditable)
            new_combo.add_editor(neditable)
        new_combo.resize(500, 500)
        new_combo.aboutToCloseComboEditor.connect(self._remove_undock)
        new_combo.show()

    def _remove_undock(self):
        print("_remove_undock", self.sender())
        widget = self.sender()
        self.sub_Undocked(widget)

    def add_Undocked(self, combedit):
        self.__undocked.append(combedit)

    def sub_Undocked(self, combedit):
        self.__undocked.remove(combedit)

    def add_SingleUndocked(self, combedit):
        self._single_undocked.append(combedit)

    def sub_SingleUndocked(self, combedit):
        self._single_undocked.remove(combedit)

    # aún no se ha puesto en funcionamiento!.
    def single_split_editor(self, orientationVertical):
        new_widget = ComboEditor()
        for neditable in self.bar.get_editables():
            print("\nsingle_split_editor", neditable, new_widget)
            new_widget.add_editor(neditable)
        self.splitEditor.emit(self, new_widget, orientationVertical)

    def single_undock_editor(self):
        new_combo = ComboEditor(Force_Free=True)
        new_combo.setWindowTitle("NINJA-IDE")
        self.add_SingleUndocked(new_combo)

        nEdit = self.stackedEditor.takeAt(
            self.stackedEditor.currentIndex()).widget()
        ide = IDE.getInstance()
        ide.unload_NEditable(nEdit)
        neditable = self.bar.take_editable()
        print("\n\nsingle_undock_editor:::", neditable, neditable.editor,
              nEdit, neditable.nfile)

        if self.stackedEditor.isEmpty():
            self.allFilesClosed.emit()

        new_combo.add_editor(neditable)
        new_combo.stackedEditor.setCurrentIndex(
            0)  # new_combo.stackedEditor.setCurrentWidget(nEdit)
        new_combo.resize(500, 500)
        new_combo.aboutToCloseComboEditor.connect(self.single__remove_undock)
        new_combo.show()

    def single__remove_undock(self):
        print("single__remove_undock", self.sender())
        widget = self.sender()
        self.sub_SingleUndocked(widget)
        ##widget.deleteLater()

    def bind_Editable(self, editable):
        self.bar.add_item(neditable.display_name, editable)

    def close_current_file(self):
        self.bar.about_to_close_file()

    def _close_file(self, neditable):
        print("\n\n_close_file", self.__original, self.Force_Free)
        index = self.bar.close_file(neditable)
        layoutItem = self.stackedEditor.takeAt(index)
        #neditable.editor.completer.cc.unload_module()
        self._add_to_last_opened(neditable.file_path)
        layoutItem.widget().deleteLater(
        )  # @@4 -> Comentando ésta linea desaparece el mensaje

        if self.stackedEditor.isEmpty():
            self.allFilesClosed.emit()

    def _add_to_last_opened(self, path):
        if path not in settings.LAST_OPENED_FILES:
            settings.LAST_OPENED_FILES.append(path)
            if len(settings.LAST_OPENED_FILES) > settings.MAX_REMEMBER_TABS:
                self.__lastOpened = self.__lastOpened[1:]
            self.recentTabsModified.emit()

    def _editor_with_focus(self):
        if self._main_container.current_comboEditor is not self:
            self._main_container.current_comboEditor = self
            editor = self.stackedEditor.currentWidget()
            self._main_container.current_editor_changed(
                editor.neditable.file_path)
            self._load_symbols(editor.neditable)
            editor.neditable.update_checkers_display()

    def _ask_for_save(self, neditable):
        val = QMessageBox.No
        fileName = neditable.nfile.file_name
        val = QMessageBox.question(
            self, (self.tr('The file %s was not saved') % fileName),
            self.tr("Do you want to save before closing?"),
            QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
        if val == QMessageBox.No:
            neditable.nfile.close(force_close=True)
        elif val == QMessageBox.Yes:
            neditable.ignore_checkers = True
            self._main_container.save_file(neditable.editor)
            neditable.nfile.close()

    def _file_has_been_modified(self, neditable):
        val = QMessageBox.No
        fileName = neditable.file_path
        val = QMessageBox.question(
            self, translations.TR_FILE_HAS_BEEN_MODIFIED,
            "%s%s" % (fileName, translations.TR_FILE_MODIFIED_OUTSIDE),
            QMessageBox.Yes | QMessageBox.No)
        if val == QMessageBox.Yes:
            neditable.reload_file()

    def _run_file(self, path):
        self._main_container.run_file(path)

    def _add_to_project(self, path):
        self._main_container._add_to_project(path)

    def _show_file_in_explorer(self, path):
        '''Connected to ActionBar's showFileInExplorer(QString)
        signal, forwards the file path on to the main container.'''
        self._main_container._show_file_in_explorer(path)

    def set_current(self, neditable):
        if neditable:
            self.bar.set_current_file(neditable)

    def _set_current(self, neditable, index):
        if neditable:
            self.stackedEditor.setCurrentIndex(index)
            editor = self.stackedEditor.currentWidget()
            self._update_cursor_position(ignore_sender=True)
            editor.setFocus()
            self._main_container.current_editor_changed(neditable.file_path)
            self._load_symbols(neditable)
            self._show_file_in_explorer(neditable.file_path)
            neditable.update_checkers_display()

    def widget(self, index):
        return self.stackedEditor.widget(index)

    def countEditors(self):
        """Return the number of editors opened."""
        return self.stackedEditor.count()

    def currentEditor(self):
        """ rtn -> Editor()# local QsciScintilla"""
        return self.stackedEditor.currentWidget()

    def _update_cursor_position(self, line=0, col=0, ignore_sender=False):
        obj = self.sender()
        editor = self.stackedEditor.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            line += 1
            self.bar.update_line_col(line, col)

    def _set_current_symbol(self, line, ignore_sender=False):
        obj = self.sender()
        editor = self.stackedEditor.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            index = bisect.bisect(self._symbols_index, line)
            if (index >= len(self._symbols_index)
                    or self._symbols_index[index] > (line + 1)):
                index -= 1
            self.bar.set_current_symbol(index)

    def _editor_modified(self, value):
        obj = self.sender()
        neditable = obj.neditable
        if value:
            text = "\u2022 %s" % neditable.display_name
            self.bar.update_item_text(neditable, text)
        else:
            self.bar.update_item_text(neditable, neditable.display_name)

    def _go_to_symbol(self, index):
        print("_go_to_symbol in index:", index)
        line = self._symbols_index[index]
        editor = self.stackedEditor.currentWidget()
        editor.go_to_line(line)

    def _update_symbols(self, neditable):
        editor = self.stackedEditor.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if editor == neditable.editor:
            self._load_symbols(neditable)

    def _update_combo_info(self, neditable):
        self.bar.update_item_text(neditable, neditable.display_name)
        self._main_container.current_editor_changed(neditable.file_path)

    def _load_symbols(self, neditable):
        symbols_handler = handlers.get_symbols_handler('py')
        source = neditable.editor.text()
        source = source.encode(neditable.editor.encoding)
        symbols, symbols_simplified = symbols_handler.obtain_symbols(
            source, simple=True)
        self._symbols_index = sorted(symbols_simplified.keys())
        symbols_simplified = sorted(list(symbols_simplified.items()),
                                    key=lambda x: x[0])
        self.bar.add_symbols(symbols_simplified)
        line, _ = neditable.editor.getCursorPosition()
        self._set_current_symbol(line, True)
        tree_symbols = IDE.get_service('symbols_explorer')
        tree_symbols.update_symbols_tree(symbols, neditable.file_path)

    def _show_notification_icon(self, neditable):
        checkers = neditable.sorted_checkers
        icon = QIcon()
        for items in checkers:
            checker, color, _ = items
            if checker.checks:
                if isinstance(checker.checker_icon, int):
                    icon = self.style().standardIcon(checker.checker_icon)
                elif isinstance(checker.checker_icon, str):
                    icon = QIcon(checker.checker_icon)
                break
        self.bar.update_item_icon(neditable, icon)

    def show_menu_navigation(self):
        self.bar.code_navigator.show_menu_navigation()

    def closeEvent(self, event):
        for comboeditor in self._single_undocked:
            print("has undocked", comboeditor)
            comboeditor.reject()
            comboeditor.deleteLater()

        # print("\n\ncloseEvent", self)
        if self.__original:
            self.bar._close_all_files()
        self.aboutToCloseComboEditor.emit()
        super(ComboEditor, self).closeEvent(event)

    def reject(self):
        if not self.__original:
            super(ComboEditor, self).reject()
Пример #6
0
class MyApplication(QMainWindow):
    def __init__(self, parent=None):
        super().__init__()

        self.serverpack = {"equation": 0, "coeffs": []}

        self.initWidgets()
        self.initUI()

    def initWidgets(self):

        self.greetingWidget()
        self.mainWidget()

        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)

        self.lay = QStackedLayout()
        self.lay.addWidget(self.greeting_widget)
        self.lay.addWidget(self.main_widget)

        self.core_lay = QVBoxLayout()
        self.core_lay.addLayout(self.lay)
        self.centralWidget.setLayout(self.core_lay)

    def greetingWidget(self):

        self.greeting_widget = QWidget()

        btn = QPushButton("Continue")
        btn.setStyleSheet(
            "color: #4d4d4f; border: 1px solid #4d4d4f; padding: 10px; border-radius: 5px; font-size: 20px; outline: none; background: none;"
        )
        btn.setCursor(Qt.OpenHandCursor)
        btn.clicked.connect(self.change)

        lbl = QLabel(
            "This is equation solver.\nChoose equation, input coefficients, get answer\nand have fun!",
            self)
        lbl.setAlignment(Qt.AlignHCenter)
        lbl.setStyleSheet(
            "font-size: 20px; margin-top: 30px; margin-bottom: 50px;")

        grid = QVBoxLayout()
        grid.setAlignment(Qt.AlignTop)
        grid.addWidget(lbl)
        grid.addWidget(btn)
        self.greeting_widget.setLayout(grid)

    def mainWidget(self):

        self.main_widget = QWidget()

        self.equation_lbl = QLabel('Equation type', self)
        equations = [
            'Ax + B = 0', 'Ax^2 + Bx + C = 0',
            'Ax + By + C = 0; Cx + Dy + E = 0',
            'Ax^2 + By^2 + C = 0; Cx^2 + Dy^2 + E = 0'
        ]
        self.equation = QComboBox(self)
        self.equation.setMaximumWidth(300)
        for eq in equations:
            self.equation.addItem(eq)

        self.coef_lbl = QLabel('Coefficients')
        self.coeffs = QLineEdit()
        style = self.stylify('input')
        self.coeffs.setStyleSheet(style)
        self.coeffs.setPlaceholderText('Example: A=1;B=-1;')
        self.coeffs.setMaximumWidth(300)

        answerBtn = QPushButton('Get Answer')
        style = self.stylify('btn--small')
        answerBtn.setStyleSheet(style)
        answerBtn.setCursor(Qt.OpenHandCursor)
        answerBtn.setMaximumWidth(300)
        answerBtn.clicked.connect(self.sendToServer)

        greetBtn = QPushButton('Go to start page')
        style = self.stylify('btn--large')
        greetBtn.setStyleSheet(style)
        greetBtn.setCursor(Qt.OpenHandCursor)
        greetBtn.clicked.connect(self.change)

        self.resultLabel = QLabel(self)
        self.resultLabel.setText("Here Will Be An Answer")
        self.resultLabel.setMinimumWidth(165)

        grid = QGridLayout()
        grid.addWidget(self.equation_lbl, 0, 0)
        grid.addWidget(self.equation, 0, 1)
        grid.addWidget(self.coef_lbl, 1, 0)
        grid.addWidget(self.coeffs, 1, 1)
        grid.addWidget(answerBtn, 2, 1)
        grid.addWidget(self.resultLabel, 2, 0)
        grid.addWidget(greetBtn, 3, 0, 1, 2)
        self.main_widget.setLayout(grid)

    def initUI(self):
        self.setGeometry(400, 50, 500, 400)
        self.setWindowTitle('MathSelf')
        self.show()

    # STYLES
    def stylify(self, target):
        if target == 'btn--large':
            return "color: #4d4d4f; border: 1px solid #4d4d4f; padding: 10px; border-radius: 5px; font-size: 20px; outline: none; background: none;"
        elif target == 'btn--small':
            return "color: #4d4d4f; border: 1px solid #4d4d4f; padding: 4px; border-radius: 5px; font-size: 14px; outline: none; background: none;"
        elif target == 'input':
            return "color: #4d4d4f; border: 1px solid #4d4d4f; padding: 4px; border-radius: 5px; font-size: 14px; outline: none; background: none;"

    # EVENTS HANDLER
    def change(self):

        if self.lay.currentIndex() == 0:
            self.lay.setCurrentWidget(self.main_widget)
        elif self.lay.currentIndex() == 1:
            self.lay.setCurrentWidget(self.greeting_widget)

            self.resultLabel.setText("Here Will Be Your Answer")
            self.equation.setCurrentIndex(0)
            self.coeffs.setText("")

    # COMMUNICATES WITH SERVER
    def initSocketConnection(self):
        self.clientSocket = socket.socket()
        self.clientSocket.connect(('localhost', 9090))
        self.serverpack = {"equation": 0, "coeffs": []}

    def sendToServer(self):

        success = self.parse()
        if not success:
            self.setErrorLabel()
            return
        else:
            self.initSocketConnection()

        self.serverpack["equation"] = self.equation.currentIndex()
        self.serverpack["coeffs"] = self.parsed_coeffs

        data = json.dumps(self.serverpack)
        self.clientSocket.send(data.encode())
        self.receiveData()

    def receiveData(self):
        serialized_result = self.clientSocket.recv(4048)
        self.clientSocket.close()

        result = json.loads(serialized_result.decode())
        print(result)
        if result != 'noresult':
            self.setResultLabel(result)
        else:
            self.setNoResultLabel()

    # DEAL WITH INFORMATION FOR/FROM SERVER
    def parse(self):

        self.parsed_coeffs = []

        # determine which regex we need to use for a particular equation
        current_eq = self.equation.currentIndex()
        if current_eq == 0:
            reg_ex = r'A=.?\d+;\s*B=.?\d+;'
            self.serverpack["equation"] = current_eq
        elif current_eq == 1:
            reg_ex = r'A=.?\d+;\s*B=.?\d+;\s*C=.?\d+;\s*'
            self.serverpack["equation"] = current_eq
        elif current_eq == 2:
            reg_ex = r'A=.?\d+;\s*B=.?\d+;\s*C=.?\d+;\s*D=.?\d+;\s*E=.?\d+;\s*'
            self.serverpack["equation"] = current_eq
        elif current_eq == 3:
            reg_ex = r'A=.?\d+;\s*B=.?\d+;\s*C=.?\d+;\s*D=.?\d+;\s*E=.?\d+;\s*'
            self.serverpack["equation"] = current_eq

        # check regex
        success_reg = re.findall(reg_ex, self.coeffs.text())
        if success_reg:
            for coef in re.findall(r'.?\d+', self.coeffs.text()):
                if coef[0] == '-':
                    self.parsed_coeffs.append(int(coef))
                else:
                    self.parsed_coeffs.append(int(coef[1:len(coef)]))
            return True
        else:
            return False

    def setErrorLabel(self):
        self.resultLabel.setText("Wrong coefficients input")

    def setResultLabel(self, result):
        self.resultLabel.setText("%s" % result)

    def setNoResultLabel(self):
        self.resultLabel.setText("No Real Result For This Coefficients")
class ProjectTreeColumn(QDialog):
    dockWidget = pyqtSignal("QObject*")
    undockWidget = pyqtSignal()
    changeTitle = pyqtSignal("QObject*", str)
    def __init__(self, parent=None):
        super(ProjectTreeColumn, self).__init__(parent,
                                                Qt.WindowStaysOnTopHint)
        vbox = QVBoxLayout(self)
        vbox.setSizeConstraint(QVBoxLayout.SetDefaultConstraint)
        vbox.setContentsMargins(0, 0, 0, 0)
        self._buttons = []

        self._combo_project = QComboBox()
        self._combo_project.setMinimumHeight(30)
        self._combo_project.setContextMenuPolicy(Qt.CustomContextMenu)
        vbox.addWidget(self._combo_project)

        self._projects_area = QStackedLayout()
        logger.debug("This is the projects area")
        logger.debug(self._projects_area)
        vbox.addLayout(self._projects_area)

        self.projects = []

        self._combo_project.currentIndexChanged[int].connect(self._change_current_project)
        self._combo_project.customContextMenuRequested['const QPoint &'].connect(self.context_menu_for_root)
        connections = (
            {'target': 'main_container',
             'signal_name': 'addToProject',#(QString)
             'slot': self._add_file_to_project},
            {'target': 'main_container',
             'signal_name': 'showFileInExplorer',#(QString)
             'slot': self._show_file_in_explorer},
        )
        IDE.register_service('projects_explorer', self)
        IDE.register_signals('projects_explorer', connections)
        ExplorerContainer.register_tab(translations.TR_TAB_PROJECTS, self)

        #FIXME: Should have a ninja settings object that stores tree state
        #FIXME: Or bettter, application data object
        #TODO: check this:
        #self.connect(ide, SIGNAL("goingDown()"),
            #self.tree_projects.shutdown)

        #def close_project_signal():
            #self.emit(SIGNAL("updateLocator()"))



    def install_tab(self):
        ide = IDE.getInstance()
        ui_tools.install_shortcuts(self, actions.PROJECTS_TREE_ACTIONS, ide)

        ide.goingDown.connect(self.close)

    def load_session_projects(self, projects):
        for project in projects:
            if os.path.exists(project):
                self._open_project_folder(project)

    def open_project_folder(self, folderName=None):
        print("open_project_folder", folderName)
        if settings.WORKSPACE:
            directory = settings.WORKSPACE
        else:
            directory = os.path.expanduser("~")

        if folderName is None:
            folderName = QFileDialog.getExistingDirectory(
                self, translations.TR_OPEN_PROJECT_DIRECTORY, directory)
            logger.debug("Choosing Foldername")
        if folderName:
            logger.debug("Opening %s" % folderName)
            self._open_project_folder(folderName)

    def _open_project_folder(self, folderName):
        ninjaide = IDE.get_service("ide")
        project = NProject(folderName)
        qfsm = ninjaide.filesystem.open_project(project)
        if qfsm:
            self.add_project(project)
            self.save_recent_projects(folderName)
            main_container = IDE.get_service('main_container')
            if main_container:
                main_container.show_editor_area()
            if len(self.projects) > 1:
                title = "%s (%s)" % (
                    translations.TR_TAB_PROJECTS, len(self.projects))
            else:
                title = translations.TR_TAB_PROJECTS
            self.changeTitle.emit(self, title)

    def _add_file_to_project(self, path):
        """Add the file for 'path' in the project the user choose here."""
        if self._projects_area.count() > 0:
            pathProject = [self.current_project]
            addToProject = add_to_project.AddToProject(pathProject, self)
            addToProject.exec_()
            if not addToProject.pathSelected:
                return
            main_container = IDE.get_service('main_container')
            if not main_container:
                return
            editorWidget = main_container.get_current_editor()
            if not editorWidget.file_path:
                name = QInputDialog.getText(None,
                                            translations.TR_ADD_FILE_TO_PROJECT,
                                            translations.TR_FILENAME + ": ")[0]
                if not name:
                    QMessageBox.information(
                        self,
                        translations.TR_INVALID_FILENAME,
                        translations.TR_INVALID_FILENAME_ENTER_A_FILENAME)
                    return
            else:
                name = file_manager.get_basename(editorWidget.file_path)
            new_path = file_manager.create_path(addToProject.pathSelected, name)
            ide_srv = IDE.get_service("ide")
            old_file = ide_srv.get_or_create_nfile(path)
            new_file = old_file.save(editorWidget.text(), new_path)
            #FIXME: Make this file replace the original in the open tab
        else:
            pass
            # Message about no project

    def _show_file_in_explorer(self, path):
        '''Iterate through the list of available projects and show
        the current file in the explorer view for the first
        project that contains it (i.e. if the same file is
        included in multiple open projects, the path will be
        expanded for the first project only).
        Note: This slot is connected to the main container's
        "showFileInExplorer(QString)" signal.'''
        central = IDE.get_service('central_container')
        if central and not central.is_lateral_panel_visible():
            return
        for project in self.projects:
            index = project.model().index(path)
            if index.isValid():
                # This highlights the index in the tree for us
                project.scrollTo(index, QAbstractItemView.EnsureVisible)
                project.setCurrentIndex(index)
                break

    def add_project(self, project):
        if project not in self.projects:
            self._combo_project.addItem(project.name)
            ptree = TreeProjectsWidget(project)
            self._projects_area.addWidget(ptree)
            ptree.closeProject.connect(self._close_project)
            print("project", project)#setRootPath
            pmodel = project.model
            ptree.setModel(pmodel)
            pindex = pmodel.index(pmodel.rootPath())
            ptree.setRootIndex(pindex)
            self.projects.append(ptree)
            current_index = self._projects_area.count()
            self._projects_area.setCurrentIndex(current_index - 1)
            self._combo_project.setCurrentIndex(current_index - 1)

    def _close_project(self, widget):
        """Close the project related to the tree widget."""
        index = self._projects_area.currentIndex()
        self.projects.remove(widget)
        self._projects_area.takeAt(index)
        self._combo_project.removeItem(index)
        index = self._combo_project.currentIndex()
        self._projects_area.setCurrentIndex(index)
        ninjaide = IDE.getInstance()
        ninjaide.filesystem.close_project(widget.project.path)
        widget.deleteLater()
        if len(self.projects) > 1:
            title = "%s (%s)" % (
                translations.TR_TAB_PROJECTS, len(self.projects))
        else:
            title = translations.TR_TAB_PROJECTS
        self.changeTitle.emit(self, title)

    def _change_current_project(self, index):
        self._projects_area.setCurrentIndex(index)

    def close_opened_projects(self):
        for project in reversed(self.projects):
            self._close_project(project)

    def save_project(self):
        """Save all the opened files that belongs to the actual project."""
        if self._projects_area.count() > 0:
            path = self.current_project.path
            main_container = IDE.get_service('main_container')
            if path and main_container:
                main_container.save_project(path)

    def create_new_project(self):
        wizard = new_project_manager.NewProjectManager(self)
        wizard.show()

    @property
    def current_project(self):
        if self._projects_area.count() > 0:
            return self._projects_area.currentWidget().project

    @property
    def current_tree(self):
        obj = self._projects_area.currentWidget()
        return obj

    def save_recent_projects(self, folder):
        settings = IDE.data_settings()
        recent_project_list = settings.value('recentProjects', {})
        #if already exist on the list update the date time
        projectProperties = json_manager.read_ninja_project(folder)
        name = projectProperties.get('name', '')
        description = projectProperties.get('description', '')

        if name == '':
            name = file_manager.get_basename(folder)

        if description == '':
            description = translations.TR_NO_DESCRIPTION

        if folder in recent_project_list:
            properties = recent_project_list[folder]
            properties["lastopen"] = QDateTime.currentDateTime()
            properties["name"] = name
            properties["description"] = description
            recent_project_list[folder] = properties
        else:
            recent_project_list[folder] = {
                "name": name,
                "description": description,
                "isFavorite": False, "lastopen": QDateTime.currentDateTime()}
            #if the length of the project list it's high that 10 then delete
            #the most old
            #TODO: add the length of available projects to setting
            if len(recent_project_list) > 10:
                del recent_project_list[self.find_most_old_open(
                    recent_project_list)]
        settings.setValue('recentProjects', recent_project_list)

    def find_most_old_open(self, recent_project_list):
        listFounder = []
        for recent_project_path, content in list(recent_project_list.items()):
            listFounder.append((recent_project_path, int(
                content["lastopen"].toString("yyyyMMddHHmmzzz"))))
        listFounder = sorted(listFounder, key=lambda date: listFounder[1],
                             reverse=True)   # sort by date last used
        return listFounder[0][0]

    def reject(self):
        if self.parent() is None:
            self.dockWidget.emit(self)

    def closeEvent(self, event):
        self.dockWidget.emit(self)
        event.ignore()

    def context_menu_for_root(self):
        if not self.current_tree:
            # en vez de un mensaje, colorear el area de projecto...
            # el area de projecto debería decir 'Sin Projectos'/'without Projects'
            # QMessageBox.information(self, translations.TR_INFO_TITLE_PROJECT_PROPERTIES,
            #     translations.TR_INFO_MESSAGE_PROJECT_PROPERTIES)
            return
        menu = QMenu(self)
        path = self.current_tree.project.path
        action_add_file = menu.addAction(QIcon(":img/new"),
                                         translations.TR_ADD_NEW_FILE)
        action_add_folder = menu.addAction(QIcon(
            ":img/openProj"), translations.TR_ADD_NEW_FOLDER)
        action_create_init = menu.addAction(translations.TR_CREATE_INIT)
        action_add_file.triggered['bool'].connect(lambda s,_path=path: self.current_tree._add_new_file(_path))
        action_add_folder.triggered['bool'].connect(lambda s,_path=path: self.current_tree._add_new_folder(_path))
        action_create_init.triggered['bool'].connect(lambda s,_path=path: self.current_tree._create_init(_path))
        menu.addSeparator()
        actionRunProject = menu.addAction(QIcon(
            ":img/play"), translations.TR_RUN_PROJECT)
        actionRunProject.triggered['bool'].connect(lambda s: self.current_tree._execute_project())
        if self.current_tree._added_to_console:
            actionRemoveFromConsole = menu.addAction(
                translations.TR_REMOVE_PROJECT_FROM_PYTHON_CONSOLE)
            actionRemoveFromConsole.triggered['bool'].connect(lambda s: self.current_tree._remove_project_from_console())
        else:
            actionAdd2Console = menu.addAction(
                translations.TR_ADD_PROJECT_TO_PYTHON_CONSOLE)
            actionAdd2Console.triggered['bool'].connect(lambda s: self.current_tree._add_project_to_console())
        actionShowFileSizeInfo = menu.addAction(translations.TR_SHOW_FILESIZE)
        actionShowFileSizeInfo.triggered['bool'].connect(lambda s: self.current_tree.show_filesize_info())
        actionProperties = menu.addAction(QIcon(":img/pref"),
                                          translations.TR_PROJECT_PROPERTIES)
        actionProperties.triggered['bool'].connect(lambda s: self.current_tree.open_project_properties())

        menu.addSeparator()
        action_close = menu.addAction(
            self.style().standardIcon(QStyle.SP_DialogCloseButton),
            translations.TR_CLOSE_PROJECT)
        action_close.triggered['bool'].connect(lambda s: self.current_tree._close_project())
        #menu for the project
        for m in self.current_tree.extra_menus_by_scope['project']:
            if isinstance(m, QMenu):
                menu.addSeparator()
                menu.addMenu(m)

        #show the menu!
        menu.exec_(QCursor.pos())

    def open_project_properties(self):
        print("open_project_properties-.-.-.-.-")
        _prj = self.current_project
        if _prj:
            proj = project_properties_widget.ProjectProperties(_prj, self)
            proj.show()
            return
        
        QMessageBox.information(self, translations.TR_INFO_TITLE_PROJECT_PROPERTIES,
                translations.TR_INFO_MESSAGE_PROJECT_PROPERTIES)
class OptionsWidget(QWidget):
    """
    Widget holds menu with all options.
    """
    def __init__(self, main_window, items):

        super().__init__()

        self.items = items

        self.layout = QStackedLayout()
        self._switch_user = self._get_switch_user_func(main_window)
        self.setLayout(self.layout)
        self._hide_action_button = lambda: main_window.communication.action_button_toggle.emit(
            False, '', None)

        self._create_layout(main_window)

    def set_current_index(self, index):
        self.layout.setCurrentIndex(index)
        if not index:
            self._hide_action_button()

    def showEvent(self, event):
        if not self.layout.currentIndex():
            self._hide_action_button()

    def _get_switch_user_func(self, main_window):
        def _switch_user():
            main_window.menu_btn_clicked(main_window.user_frame_index)
            self.layout.setCurrentIndex(0)

        return _switch_user

    def _get_template_import_func(self, main_window):
        func = self._wrap_template_func(template.Template.import_, main_window)

        def _alert_callback(path, value):
            if value:
                func(path[0])

        def _f():
            # path = QFileDialog.getOpenFileName(main_window, 'Выберите файл', options.DATABASE_DIR)
            path = QFileDialog.getOpenFileName(main_window,
                                               'Selecione o arquivo',
                                               options.DATABASE_DIR)
            if path:
                # main_window.create_alert('Шаблоны с одинаковыми именами будут перезаписаны.'
                #  '\nПродолжить?', functools.partial(_alert_callback, path))
                main_window.create_alert(
                    'Padrões com o mesmo nome serão sobrescritos.'
                    '\nContinua?', functools.partial(_alert_callback, path))

        return _f

    def _get_template_export_func(self, main_window):
        func = self._wrap_template_func(template.Template.export, main_window)

        def _f():
            # path = QFileDialog.getExistingDirectory(main_window, 'Выберите путь', options.DATABASE_DIR)
            path = QFileDialog.getExistingDirectory(main_window,
                                                    'Escolha um caminho',
                                                    options.DATABASE_DIR)
            if path:
                return func(path)

        return _f

    @staticmethod
    def _wrap_template_func(func, main_window):
        def _f(path):
            ok, result = func(path)
            if ok:
                # main_window.show_message('Готово')
                main_window.show_message('Feito')
            else:
                # main_window.create_alert('Произошла ошибка\n{}'.format(result.get('error')))
                main_window.create_alert('Ocorreu um erro\n{}'.format(
                    result.get('error')))
            return ok, result

        return _f

    def _create_layout(self, main_window):

        wrapper = QHBoxLayout()
        self.layout.addWidget(utils.get_scrollable(wrapper))
        rows = 8
        cols = 3
        vboxes = [QVBoxLayout() for _ in range(cols)]

        # widgets = ((TemplateWidgetInOptions(main_window, self.items, self), 'Шаблоны'),
        #            (UsersAndGroupsWidget(main_window, self), 'Пользователи и группы'),
        #            (self._switch_user, 'Сменить пользователя'),
        #            (self._get_template_export_func(main_window), 'Экспортировать шаблоны'),
        #            (self._get_template_import_func(main_window), 'Импортировать шаблоны'))
        widgets = ((TemplateWidgetInOptions(main_window, self.items, self),
                    'Templates'), (UsersAndGroupsWidget(main_window, self),
                                   'Usuários e Grupos'), (self._switch_user,
                                                          'Alterar usuário'),
                   (self._get_template_export_func(main_window),
                    'Modelos de exportação'),
                   (self._get_template_import_func(main_window),
                    'Importar modelos'))

        for i, widget in enumerate(widgets):
            b = QPushButton(widget[1])

            if callable(widget[0]):
                b.clicked.connect(widget[0])
            else:
                b.clicked.connect(
                    functools.partial(self.layout.setCurrentIndex, i + 1))
                self.layout.addWidget(widget[0])

            b.setGraphicsEffect(utils.get_shadow())
            vboxes[(i // rows) % cols].addWidget(b)

        for each in vboxes:
            each.addStretch()
            wrapper.addLayout(each, stretch=int(100 / cols))
Пример #9
0
class GUI(MainUi):
    def __init__(self):
        super(GUI, self).__init__()
        # 左边面板按钮触发函数,可以是import进来的,也可以是类内的
        self.left_button_1.clicked.connect(self.click_password_book)
        self.left_button_2.clicked.connect(self.click_PrivateFiles)
        self.left_button_3.clicked.connect(self.click_browser_history)
        self.left_button_4.clicked.connect(self.click_visual_crypt)
        self.left_button_5.clicked.connect(self.click_mar_word)
        self.left_button_8.clicked.connect(self.click_find_device_location)
        self.left_button_6.clicked.connect(self.click_face_collect)
        self.left_button_7.clicked.connect(self.click_build_model)
        self.left_button_9.clicked.connect(self.click_set_user_password)
        self.left_close.clicked.connect(self.close_and_enc)

        # 多个窗口切换
        self.stacked_layout = QStackedLayout(self.right_widget)

        self.main_frame1 = QWidget()
        self.right_layout = QtWidgets.QGridLayout()
        self.main_frame1.setLayout(self.right_layout)

        self.main_frame2 = QWidget()
        self.right_layout2 = QtWidgets.QGridLayout()
        self.main_frame2.setLayout(self.right_layout2)

        self.main_frame3 = QWidget()
        self.right_layout3 = QtWidgets.QGridLayout()
        self.main_frame3.setLayout(self.right_layout3)

        self.main_frame4 = QWidget()
        self.right_layout4 = QtWidgets.QGridLayout()
        self.main_frame4.setLayout(self.right_layout4)
        self.FileRecorder = []

        self.main_frame5 = QWidget()
        self.right_layout5 = QtWidgets.QGridLayout()
        self.main_frame5.setLayout(self.right_layout5)

        self.main_frame6 = QWidget()
        self.right_layout6 = QtWidgets.QGridLayout()
        self.main_frame6.setLayout(self.right_layout6)

        self.stacked_layout.addWidget(self.main_frame1)
        self.stacked_layout.addWidget(self.main_frame2)
        self.stacked_layout.addWidget(self.main_frame3)
        self.stacked_layout.addWidget(self.main_frame4)
        self.stacked_layout.addWidget(self.main_frame5)
        self.stacked_layout.addWidget(self.main_frame6)

    def click_find_device_location(self):  # 4. visual crypto
        try:
            from track import track_gui
            if self.stacked_layout.currentIndex() != 5:
                self.stacked_layout.setCurrentIndex(5)
            track_gui.find_device_location(self)
        except Exception as err:
            print(err)

    def click_visual_crypt(self):  # 4. visual crypto
        from vc import vc_gui
        if self.stacked_layout.currentIndex() != 1:
            self.stacked_layout.setCurrentIndex(1)
        vc_gui.show_visual_crypt(self)

    def click_browser_history(self):  # 3. browser_history
        from browser import browser_gui
        if self.stacked_layout.currentIndex() != 0:
            self.stacked_layout.setCurrentIndex(0)
        browser_gui.show_browser_history(self)

    def click_mar_word(self):  # 5. mar_word_talk
        from mar import mar_gui
        if self.stacked_layout.currentIndex() != 2:
            self.stacked_layout.setCurrentIndex(2)
        mar_gui.show_mar_gui(self)

    def click_PrivateFiles(self):  # 2. private_files
        try:
            self.AES = AES_128()
            from file_encrypt import file_gui
            if self.stacked_layout.currentIndex() != 3:
                self.stacked_layout.setCurrentIndex(3)
            file_gui.file_encrypt_gui(self)
        except Exception as err:
            print(err)

    def close_and_enc(self):
        try:
            sno = identity.global_vari.login_sno
            key = identity.global_vari.login_password

            base_dir = r"./identity/datasets"
            img_dir = base_dir + "\\" + "stu_" + sno
            lists = os.listdir(img_dir)
            for img in lists:
                path = img_dir + "\\" + img
                enc_pic(key, path)

            self.close()
        except Exception as err:
            print(err)

    def click_face_collect(self):
        try:
            logging.config.fileConfig('./identity/config/logging.cfg')
            window = DataRecordUI()
            window.show()
        except Exception as err:
            print(err)

    def click_build_model(self):
        try:
            logging.config.fileConfig('./identity/config/logging.cfg')
            window = DataManageUI()
            window.show()
        except Exception as err:
            print(err)

    def click_password_book(self):
        self.controler = Controller()
        self.controler.show_login()

    def click_set_user_password(self):
        if self.stacked_layout.currentIndex() != 4:
            self.stacked_layout.setCurrentIndex(4)

        self.right_min_info = QtWidgets.QLabel("学号:")
        self.right_layout5.addWidget(self.right_min_info, 1, 1, 1, 1)

        self.lineedit = QLineEdit(self)
        self.right_layout5.addWidget(self.lineedit, 1, 2, 1, 1)
        self.lineedit.setPlaceholderText("输入新用户的学号")

        self.right_min_info2 = QtWidgets.QLabel("密码:")
        self.right_layout5.addWidget(self.right_min_info2, 2, 1, 1, 1)

        self.lineedit2 = QLineEdit(self)
        self.right_layout5.addWidget(self.lineedit2, 2, 2, 1, 1)
        self.lineedit2.setPlaceholderText("输入新用户的密码")

        self.bt = QPushButton('插入', self)
        self.right_layout5.addWidget(self.bt, 3, 1, 1, 1)
        self.bt.clicked.connect(self.insert)

    def insert(self):
        sno = self.lineedit.text()
        password = self.lineedit2.text()
        mysql_insert_data(sno, password)
        QMessageBox.about(self, "通知", "新用户密码插入数据库成功!")
Пример #10
0
class mainWindow(QMainWindow):
    end_game = False

    def __init__(self):
        super().__init__()
        self.setWindowTitle('Oczko 21')
        self.setGeometry(400, 40, 700, 640)
        self.create_welcome_layout()
        self.stacked_layout = QStackedLayout()
        self.stacked_layout.addWidget(self.welcome_widget)

        self.central_widget = QWidget()
        self.central_widget.setLayout(self.stacked_layout)
        self.setCentralWidget(self.central_widget)

        #====================Create New Game Layout=====================
        self.create_new_game_layout()
        self.stacked_layout.addWidget(self.new_game_widget)

        #==========================MAIN MENU====================================
        self.statusBar()
        newGame = QAction('&New Game', self)
        newGame.setStatusTip('Starts a new game...')
        newGame.triggered.connect(self.newGame_opt)

        help = QAction('&Help', self)
        help.setStatusTip('Help...')
        help.triggered.connect(self.help_opt)

        quitGame = QAction('&Quit', self)
        quitGame.setStatusTip('Quits the game...')
        quitGame.triggered.connect(self.quit_opt)

        mainMenu = self.menuBar()

        optionsMenu = mainMenu.addMenu('&Options')
        optionsMenu.addAction(newGame)
        optionsMenu.addAction(help)
        optionsMenu.addAction(quitGame)

        #=======================END MAIN MENU===========================================

    def newGame_opt(self):  #options from menu bar

        if self.stacked_layout.currentIndex() != 0:
            choice = QMessageBox.question(self, 'Start a new game',
                                          'Do you want to start a new game?',
                                          QMessageBox.Yes | QMessageBox.No)

            if choice == QMessageBox.Yes:
                self.new_game_radio_button.check_first()
                self.stacked_layout.setCurrentIndex(1)
                self.player1_line_edit.setText('Player 1')
                self.player2_line_edit.setText('Player 2')
            else:
                pass

        else:
            self.new_game_radio_button.check_first()
            self.stacked_layout.setCurrentIndex(1)
            self.player1_line_edit.setText('Player 1')
            self.player2_line_edit.setText('Player 2')

    def quit_opt(self):  #options from menu bar

        choice = QMessageBox.question(self, 'Exit',
                                      'Do you really want to exit the game?',
                                      QMessageBox.Yes | QMessageBox.No)

        if choice == QMessageBox.Yes:
            sys.exit()
        else:
            pass

    def help_opt(self):  # options from menu bar

        self.dialog = HelpWindow()
        self.dialog.show()

    @classmethod
    def end_game_change_value(cls,
                              value):  #method used to verify if game has ended
        cls.end_game = value

    def create_welcome_layout(self):  #first layout

        self.welcome_layout = QVBoxLayout()
        self.welcome_widget = QWidget()
        self.welcome_widget.setLayout(self.welcome_layout)

    def create_new_game_layout(self):  #start new game layout (new game menu)

        self.player1_label = QLabel('First player name:')
        self.player2_label = QLabel('Second player name:')

        self.player1_line_edit = QLineEdit()
        self.player2_line_edit = QLineEdit()

        self.cancel_button = QPushButton('Cancel')
        self.cancel_button.setMaximumWidth(330)
        self.cancel_button.setMinimumWidth(330)
        self.cancel_button.setMinimumHeight(60)

        self.start_button = QPushButton('Start New Game')
        self.start_button.setMaximumWidth(330)
        self.start_button.setMinimumWidth(330)
        self.start_button.setMinimumHeight(60)

        self.start_button.clicked.connect(self.start_new_game)
        self.cancel_button.clicked.connect(self.cancel)

        self.player_grid = QGridLayout()
        self.new_game_grid = QGridLayout()

        #player grid
        self.player_grid.addWidget(self.player1_label, 0, 0)
        self.player_grid.addWidget(self.player2_label, 1, 0)
        self.player_grid.addWidget(self.player1_line_edit, 0, 1)
        self.player_grid.addWidget(self.player2_line_edit, 1, 1)

        #new game grid

        self.new_game_radio_button = RadioButton('Play with',
                                                 ('NPC', 'Friend'))
        self.new_game_grid.addWidget(self.new_game_radio_button, 0, 0)
        self.new_game_grid.addLayout(self.player_grid, 0, 1)
        self.new_game_grid.addWidget(self.cancel_button, 1, 0)
        self.new_game_grid.addWidget(self.start_button, 1, 1)

        self.new_game_widget = QWidget()
        self.new_game_widget.setLayout(self.new_game_grid)

    def create_game_layout(self, player_type):

        self.player1_points = QLabel('0')
        self.player1_points.setAlignment(Qt.AlignTop)
        self.player2_points = QLabel('0')
        self.player2_points.setAlignment(Qt.AlignTop)

        self.player1_name = QLabel(self.player1_line_edit.text())

        if player_type == 1:
            self.player2_name = QLabel(self.player2_line_edit.text() +
                                       ' (NPC)')
        else:
            self.player2_name = QLabel(self.player2_line_edit.text())

        self.points1_label = QLabel('Points:')
        self.points1_label.setAlignment(Qt.AlignBottom)
        self.points2_label = QLabel('Points:')
        self.points2_label.setAlignment(Qt.AlignBottom)

        self.player1_card = QLabel()
        self.player2_card = QLabel()

        self.stop_button_player1 = QPushButton('Stop')
        self.pull_button_player1 = QPushButton('Pull')

        self.stop_button_player2 = QPushButton('Stop')
        self.pull_button_player2 = QPushButton('Pull')

        self.new_deal_button = QPushButton('New Deal')

        self.information_field = QPlainTextEdit('Log here baby')
        self.information_field.setMaximumHeight(243)
        self.information_field.setMaximumWidth(200)

        #Buttons connection

        self.stop_button_player1.clicked.connect(
            lambda: self.stop_card_player1(player_type))
        self.stop_button_player1.setMinimumHeight(30)
        self.pull_button_player1.clicked.connect(
            lambda: self.pull_card_player1(player_type))
        self.pull_button_player1.setMinimumHeight(30)

        self.stop_button_player2.clicked.connect(self.stop_card_player2)
        self.stop_button_player2.setMinimumHeight(30)
        self.pull_button_player2.clicked.connect(self.pull_card_player2)
        self.pull_button_player2.setMinimumHeight(30)

        self.new_deal_button.clicked.connect(self.new_deal)
        self.new_deal_button.setMaximumWidth(90)
        self.new_deal_button.setMinimumHeight(80)

        #Table

        self.table = QTableWidget()
        self.table.setRowCount(11)
        self.table.setColumnCount(2)
        self.table.setHorizontalHeaderLabels(
            ("{0};{1};").format(self.player1_name.text(),
                                self.player2_name.text()).split(";"))
        self.table.setVerticalHeaderLabels(
            ("1;2;3;4;5;6;7;8;9;10;SUM").split(";"))
        self.table.setMaximumHeight(355)
        self.table.setMaximumWidth(237)

        #Grids definitions

        self.main_game_grid = QGridLayout()
        self.board_grid = QGridLayout()
        self.table_grid = QGridLayout()
        self.below_table_grid = QGridLayout()

        self.player1_grid = QGridLayout()
        self.player2_grid = QGridLayout()

        self.player1_board_grid = QGridLayout()
        self.player2_board_grid = QGridLayout()

        self.player1_buttons_grid = QGridLayout()
        self.player2_buttons_grid = QGridLayout()

        self.player1_points_grid = QGridLayout()
        self.player2_points_grid = QGridLayout()

        #player points grids

        self.player1_points_grid.addWidget(self.points1_label, 0, 0)
        self.player1_points_grid.addWidget(self.player1_points, 1, 0)

        self.player2_points_grid.addWidget(self.points2_label, 0, 0)
        self.player2_points_grid.addWidget(self.player2_points, 1, 0)

        #player buttons grids

        self.player1_buttons_grid.addWidget(self.stop_button_player1, 0, 0)
        self.player1_buttons_grid.addWidget(self.pull_button_player1, 0, 1)

        self.player2_buttons_grid.addWidget(self.stop_button_player2, 0, 0)
        self.player2_buttons_grid.addWidget(self.pull_button_player2, 0, 1)

        #player board grids

        self.player1_board_grid.addWidget(self.player1_name, 0, 0)
        self.player1_board_grid.addWidget(self.player1_card, 0, 1)
        self.player1_board_grid.addLayout(self.player1_points_grid, 0, 3)

        self.player2_board_grid.addWidget(self.player2_name, 0, 0)
        self.player2_board_grid.addWidget(self.player2_card, 0, 1)
        self.player2_board_grid.addLayout(self.player2_points_grid, 0, 3)

        #player grids

        self.player1_grid.addLayout(self.player1_buttons_grid, 0, 0)
        self.player1_grid.addLayout(self.player1_board_grid, 1, 0)

        self.player2_grid.addLayout(self.player2_buttons_grid, 1, 0)
        self.player2_grid.addLayout(self.player2_board_grid, 0, 0)

        #below table grid

        self.below_table_grid.addWidget(self.information_field, 0, 0)
        self.below_table_grid.addWidget(self.new_deal_button, 0, 1)

        #three main grids

        self.board_grid.addLayout(self.player1_grid, 0, 0)
        self.board_grid.addLayout(self.player2_grid, 1, 0)

        self.table_grid.addWidget(self.table, 0, 0)
        self.table_grid.addLayout(self.below_table_grid, 1, 0)

        self.main_game_grid.addLayout(self.board_grid, 0, 0)
        self.main_game_grid.addLayout(self.table_grid, 0, 1)

        # layout

        self.game_widget = QWidget()
        self.game_widget.setLayout(self.main_game_grid)

    def cancel(self):

        self.stacked_layout.setCurrentIndex(0)

    def start_new_game(self):

        player_type = self.new_game_radio_button.selected_button()

        if len(self.player1_line_edit.text()) > 10 or len(
                self.player2_line_edit.text()) > 10:
            QMessageBox.information(
                self, "Too long name",
                "At least one of player's name is too long. It has to be shorter than 10 characters."
            )

        elif self.player1_line_edit.text(
        ) == '' or self.player2_line_edit.text() == '':
            QMessageBox.information(
                self, "Empty name",
                "At least one of player's name is empty. Please provide correct one."
            )

        else:
            if self.stacked_layout.count() > 2:
                self.stacked_layout.removeWidget(self.game_widget)

            self.create_game_layout(player_type)
            self.stacked_layout.addWidget(self.game_widget)
            self.stacked_layout.setCurrentIndex(2)
            self.player1_score = 0
            self.player2_score = 0
            self.match = -1
            self.new_match()

    def new_match(self):
        self.end_game_change_value(False)
        self.new_deal_button.setDisabled(True)
        self.match += 1
        self.deck = Deck()
        self.turn = 0
        self.disable_player2_buttons()
        self.stop_counter = 0
        self.player1_allcards = []
        self.player2_allcards = []
        self.pixmap = QPixmap('karty\empty.png')
        self.pixmap = self.pixmap.scaledToWidth(180)
        self.player1_card.setPixmap(self.pixmap)
        self.player2_card.setPixmap(self.pixmap)
        self.information_field.setPlainText('New deal! {0} starts'.format(
            self.player1_name.text()))

    def pull_card_player1(self, player_type):
        #card pixmap
        self.pixmap1 = QPixmap(
            os.path.join('karty', '{0}.png').format(self.deck.pack[self.turn]))
        self.pixmap1 = self.pixmap1.scaledToWidth(180)
        self.player1_card.setPixmap(self.pixmap1)

        self.player1_points.setText(
            str(
                int(self.player1_points.text()) +
                self.points(self.deck.pack[self.turn][:2])))
        #log info
        self.information_field.setPlainText(
            self.information_field.toPlainText() +
            '\n{0} pulls and gains {1} points'.format(
                self.player1_name.text(),
                str(self.points(self.deck.pack[self.turn][:2]))))

        self.player1_allcards.append(self.deck.pack[self.turn])

        self.turn += 1
        self.stop_counter = 0
        self.disable_player1_buttons()
        if player_type == 1:
            self.game_function()
            if self.end_game == False:
                self.npc_turn()
        elif player_type == 2 and self.end_game == False:
            self.enable_player2_buttons()
            self.game_function()
        else:
            self.disable_player1_buttons()
            self.disable_player2_buttons()

    def stop_card_player1(self, player_type):

        self.stop_counter += 1
        #log info
        self.information_field.setPlainText(
            self.information_field.toPlainText() +
            '\n{0} stops the card'.format(self.player1_name.text()))

        self.disable_player1_buttons()

        if player_type == 1:
            self.game_function()
            if self.end_game == False:
                self.npc_turn()
        elif player_type == 2 and self.end_game == False:
            self.enable_player2_buttons()
            self.game_function()
        else:
            self.disable_player1_buttons()
            self.disable_player2_buttons()

    def pull_card_player2(self):
        #card pixmap
        self.pixmap2 = QPixmap(
            os.path.join('karty', '{0}.png').format(self.deck.pack[self.turn]))
        self.pixmap2 = self.pixmap2.scaledToWidth(180)
        self.player2_card.setPixmap(self.pixmap2)

        self.player2_points.setText(
            str(
                int(self.player2_points.text()) +
                self.points(self.deck.pack[self.turn][:2])))

        #log info
        self.information_field.setPlainText(
            self.information_field.toPlainText() +
            '\n{0} pulls and gains {1} points'.format(
                self.player2_name.text(),
                str(self.points(self.deck.pack[self.turn][:2]))))

        self.player2_allcards.append(self.deck.pack[self.turn])

        self.turn += 1
        self.stop_counter = 0
        self.disable_player2_buttons()

        if self.end_game == False:
            self.enable_player1_buttons()
            self.game_function()
        else:
            self.disable_player1_buttons()

    def stop_card_player2(self):

        self.disable_player2_buttons()
        self.stop_counter += 1
        #log info
        self.information_field.setPlainText(
            self.information_field.toPlainText() +
            '\n{0} stops the card'.format(self.player2_name.text()))

        if self.end_game == False:
            self.enable_player1_buttons()
            self.game_function()

    def game_function(self):  #check whether there is a winning result

        if int(self.player1_points.text()) == 21 and int(
                self.player2_points.text()) == 21:
            self.draw()

        if int(self.player1_points.text()) == 21 and self.stop_counter == 1:
            self.player1_wins()

        if int(self.player2_points.text()) == 21 and self.stop_counter == 1:
            self.player2_wins()

        # =====================Two Aces========================

        if int(self.player1_points.text()
               ) == 22 and 'AA' in self.player1_allcards[
                   0] and 'AA' in self.player1_allcards[1]:
            self.player1_wins()
            self.information_field.setPlainText(
                self.information_field.toPlainText() +
                '\n{0} has two Aces!'.format(self.player1_name.text()))

        if int(self.player2_points.text()
               ) == 22 and 'AA' in self.player2_allcards[
                   0] and 'AA' in self.player2_allcards[1]:
            self.player2_wins()
            self.information_field.setPlainText(
                self.information_field.toPlainText() +
                '\n{0} has two Aces!'.format(self.player1_name.text()))

        # ==================================================================

        #============================Two times Stop button in row============================

        if self.stop_counter == 2:
            if int(self.player1_points.text()) > int(
                    self.player2_points.text()):
                self.player1_wins()

            elif int(self.player1_points.text()) < int(
                    self.player2_points.text()):
                self.player2_wins()

            else:
                self.draw()

        if int(self.player1_points.text()) > 21:  # player 1 exceeds 21 points
            self.information_field.setPlainText(
                self.information_field.toPlainText() + '. 21 is exceeded!')
            self.player2_wins()

        if int(self.player2_points.text()) > 21:  # player 2 exceeds 21 points
            self.disable_player1_buttons()
            self.information_field.setPlainText(
                self.information_field.toPlainText() + '. 21 is exceeded!')
            self.player1_wins()

    def npc_turn(self):  #determines when npc pulls or stops the card
        time.sleep(0.5)
        if int(self.player1_points.text()) == 21 and int(
                self.player2_points.text()) in [18, 19]:
            self.pull_card_player2()
        elif int(self.player1_points.text()) == 21 and int(
                self.player2_points.text()) == 20:
            self.stop_card_player2()
        elif int(self.player1_points.text()) >= 21:
            self.stop_card_player2()
        elif int(self.player1_points.text()) >= int(
                self.player2_points.text()) or int(
                    self.player2_points.text()) <= 11:
            self.pull_card_player2()
        elif int(self.player2_points.text()) == 12:
            if random.randint(0, 100) < 85:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        elif int(self.player2_points.text()) == 13:
            if random.randint(0, 100) < 80:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        elif int(self.player2_points.text()) == 14:
            if random.randint(0, 100) < 70:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        elif int(self.player2_points.text()) == 15:
            if random.randint(0, 100) < 50:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        elif int(self.player2_points.text()) == 16:
            if random.randint(0, 100) < 35:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        elif int(self.player2_points.text()) == 17:
            if random.randint(0, 100) < 20:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        elif int(self.player2_points.text()) >= 18:
            if random.randint(0, 100) < 5:
                self.pull_card_player2()
            else:
                self.stop_card_player2()
        else:
            self.stop_card_player2()

    def player1_wins(self):  #action when player 1 wins
        self.player1_score += 1
        self.sum_rows()
        self.disable_player1_buttons()
        self.disable_player2_buttons()
        self.table.setItem(self.match, 0, QTableWidgetItem('1'))
        self.table.setItem(self.match, 1, QTableWidgetItem('0'))
        self.end_game_change_value(True)
        #log
        self.information_field.setPlainText(
            self.information_field.toPlainText() +
            '\n{0} wins the deal with {1} points!'.format(
                self.player1_name.text(), self.player1_points.text()))
        if self.match < 9:
            self.new_deal_button.setDisabled(False)
        else:
            self.result_message(self.player1_score, self.player2_score)

    def player2_wins(self):  #action when player 2 wins
        self.player2_score += 1
        self.sum_rows()
        self.disable_player1_buttons()
        self.disable_player2_buttons()
        self.table.setItem(self.match, 0, QTableWidgetItem('0'))
        self.table.setItem(self.match, 1, QTableWidgetItem('1'))
        self.end_game_change_value(True)
        #log
        self.information_field.setPlainText(
            self.information_field.toPlainText() +
            '\n{0} wins the deal with {1} points!'.format(
                self.player2_name.text(), self.player2_points.text()))
        if self.match < 9:
            self.new_deal_button.setDisabled(False)
        else:
            self.result_message(self.player1_score, self.player2_score)

    def draw(self):  #action when there is a draw
        self.disable_player1_buttons()
        self.disable_player2_buttons()
        self.table.setItem(self.match, 0, QTableWidgetItem('0'))
        self.table.setItem(self.match, 1, QTableWidgetItem('0'))
        self.end_game_change_value(True)
        #log
        self.information_field.setPlainText(
            self.information_field.toPlainText() + '\nDraw!')
        if self.match < 9:
            self.new_deal_button.setDisabled(False)
        else:
            self.result_message(self.player1_score, self.player2_score)

    def result_message(self, player1_score, player2_score):
        if player1_score > player2_score:
            QMessageBox.information(
                self, "{0} won!".format(self.player1_name.text()),
                "The score is {0}:{1}. Good luck next time {2}!".format(
                    player1_score, player2_score, self.player2_name.text()))
        elif player1_score < player2_score:
            QMessageBox.information(
                self, "{0} won!".format(self.player2_name.text()),
                "The score is {0}:{1}. Good luck next time {2}!".format(
                    player2_score, player1_score, self.player1_name.text()))
        else:
            QMessageBox.information(
                self, "Draw!",
                "Both players scored {0} points".format(player1_score))

    def disable_player1_buttons(self):
        self.pull_button_player1.setDisabled(True)
        self.stop_button_player1.setDisabled(True)

    def enable_player1_buttons(self):
        self.pull_button_player1.setDisabled(False)
        self.stop_button_player1.setDisabled(False)

    def disable_player2_buttons(self):
        self.pull_button_player2.setDisabled(True)
        self.stop_button_player2.setDisabled(True)

    def enable_player2_buttons(self):
        self.pull_button_player2.setDisabled(False)
        self.stop_button_player2.setDisabled(False)

    def points(self,
               value):  #method to match card's name with its points value
        score = {
            '11': 1,
            '22': 2,
            '33': 3,
            '44': 4,
            '55': 5,
            '66': 6,
            '77': 7,
            '88': 8,
            '99': 9,
            '10': 10,
            'WW': 2,
            'DD': 3,
            'KK': 4,
            'AA': 11
        }
        return score[value]

    def sum_rows(self):  #sums rows from the table
        self.table.setItem(10, 0, QTableWidgetItem(str(self.player1_score)))
        self.table.setItem(10, 1, QTableWidgetItem(str(self.player2_score)))

    def new_deal(self):  #start new deal

        self.enable_player1_buttons()
        self.player1_card.setText('')
        self.player2_card.setText('')
        self.player1_points.setText('0')
        self.player2_points.setText('0')
        self.new_match()
Пример #11
0
class ComboEditor(QWidget):
    # Signals
    closeSplit = pyqtSignal('PyQt_PyObject')
    splitEditor = pyqtSignal(
        'PyQt_PyObject', 'PyQt_PyObject', Qt.Orientation)
    allFilesClosed = pyqtSignal()
    about_to_close_combo_editor = pyqtSignal()
    fileClosed = pyqtSignal("PyQt_PyObject")

    def __init__(self, original=False):
        super(ComboEditor, self).__init__(None)
        self.__original = original
        self.__undocked = []
        self._symbols_index = []
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)

        self.bar = ActionBar(main_combo=original)
        vbox.addWidget(self.bar)

        # Info bar
        # self.info_bar = InfoBar(self)
        # self.info_bar.setVisible(False)
        # vbox.addWidget(self.info_bar)

        self.stacked = QStackedLayout()
        vbox.addLayout(self.stacked)

        self._main_container = IDE.get_service('main_container')

        if not self.__original:
            self._main_container.fileOpened['QString'].connect(
                self._file_opened_by_main)

        self.bar.combo_files.showComboSelector.connect(
            self._main_container.show_files_handler)
        self.bar.combo_files.hideComboSelector.connect(
            self._main_container.hide_files_handler)
        self.bar.change_current['PyQt_PyObject',
                                int].connect(self._set_current)
        self.bar.splitEditor[bool].connect(self.split_editor)
        self.bar.runFile['QString'].connect(self._run_file)
        self.bar.closeSplit.connect(lambda: self.closeSplit.emit(self))
        self.bar.addToProject['QString'].connect(self._add_to_project)
        self.bar.showFileInExplorer['QString'].connect(
            self._show_file_in_explorer)
        self.bar.goToSymbol[int].connect(self._go_to_symbol)
        self.bar.undockEditor.connect(self.undock_editor)
        self.bar.reopenTab['QString'].connect(
            lambda path: self._main_container.open_file(path))
        self.bar.closeImageViewer.connect(self._close_image)
        self.bar.code_navigator.previousPressed.connect(self._navigate_code)
        self.bar.code_navigator.nextPressed.connect(self._navigate_code)
        # self.connect(self.bar, SIGNAL("recentTabsModified()"),
        #             lambda: self._main_container.recent_files_changed())
        # self.connect(self.bar.code_navigator.btnPrevious,
        #                SIGNAL("clicked()"),
        #             lambda: self._navigate_code(False))
        # self.connect(self.bar.code_navigator.btnNext, SIGNAL("clicked()"),
        #             lambda: self._navigate_code(True))

    def _navigate_code(self, operation, forward=True):
        self._main_container.navigate_code_history(operation, forward)
    #    op = self.bar.code_navigator.operation
    #    self._main_container.navigate_code_history(val, op)

    def current_editor(self):
        return self.stacked.currentWidget()

    def setFocus(self):
        super(ComboEditor, self).setFocus()
        self.current_editor().setFocus()
        self._editor_with_focus()

    def _file_opened_by_main(self, path):
        index = self.stacked.currentIndex()
        ninjaide = IDE.get_service('ide')
        editable = ninjaide.get_or_create_editable(path)
        self.add_editor(editable)
        self.bar.set_current_by_index(index)
        if index == -1:
            self.bar.set_current_by_index(0)

    def add_image_viewer(self, viewer):
        """Add Image Viewer widget to the UI area"""

        self.stacked.addWidget(viewer)
        viewer.scaleFactorChanged.connect(
            self.bar.image_viewer_controls.update_scale_label)
        viewer.imageSizeChanged.connect(
            self.bar.image_viewer_controls.update_size_label)
        self.bar.add_item(viewer.display_name(), None)
        viewer.create_scene()
        if not self.bar.isVisible():
            self.bar.setVisible(True)

    def add_editor(self, neditable, keep_index=False):
        """Add Editor Widget to the UI area."""
        if neditable.editor:
            if self.__original:
                editor = neditable.editor
            else:
                # editor = neditable.editor.clone()
                editor = self._main_container.create_editor_from_editable(
                   neditable)
                neditable.editor.link(editor)

            current_index = self.stacked.currentIndex()
            new_index = self.stacked.addWidget(editor)
            self.stacked.setCurrentIndex(new_index)
            self.bar.add_item(neditable.display_name, neditable)
            # Bar is not visible because all the files have been closed,
            # so if a new file is opened, show the bar
            if not self.bar.isVisible():
                self.bar.setVisible(True)
            if keep_index:
                self.bar.set_current_by_index(current_index)

            # Connections
            neditable.fileClosing.connect(self._close_file)
            neditable.fileSaved.connect(self._update_symbols)
            editor.editorFocusObtained.connect(self._editor_with_focus)
            editor.modificationChanged.connect(self._editor_modified)
            editor.cursor_position_changed[int, int].connect(
                self._update_cursor_position)
            editor.current_line_changed[int].connect(self._set_current_symbol)
            if neditable._swap_file.dirty:
                self._editor_modified(True, sender=editor)
            neditable.checkersUpdated.connect(self._show_notification_icon)
            # Connect file system signals only in the original
            if self.__original:
                neditable.askForSaveFileClosing.connect(self._ask_for_save)
                neditable.fileChanged.connect(self._file_has_been_modified)
            # Load Symbols
            self._load_symbols(neditable)

    def show_combo_file(self):
        self.bar.combo.showPopup()

    def show_combo_symbol(self):
        self.bar.symbols_combo.showPopup()

    def show_combo_set_language(self):
        self.bar.set_language_combo.showPopup()

    def unlink_editors(self):
        for index in range(self.stacked.count()):
            widget = self.stacked.widget(index)
            # widget.setDocument(QsciDocument())

    def clone(self):
        combo = ComboEditor()
        for neditable in self.bar.get_editables():
            combo.add_editor(neditable)
        return combo

    def split_editor(self, orientation):
        new_combo = self.clone()
        self.splitEditor.emit(self, new_combo, orientation)

    def undock_editor(self):
        new_combo = ComboEditor()
        for neditable in self.bar.get_editables():
            new_combo.add_editor(neditable)
        self.__undocked.append(new_combo)
        new_combo.setWindowTitle("NINJA-IDE")
        editor = self.current_editor()
        new_combo.set_current(editor.neditable)
        new_combo.resize(700, 500)
        new_combo.about_to_close_combo_editor.connect(self._remove_undock)
        new_combo.show()

    def _remove_undock(self):
        widget = self.sender()
        self.__undocked.remove(widget)

    def close_current_file(self):
        self.bar.about_to_close_file()

    def _close_image(self, index):
        layout_item = self.stacked.takeAt(index)
        layout_item.widget().deleteLater()
        if self.stacked.isEmpty():
            self.bar.hide()
            self.allFilesClosed.emit()

    def _close_file(self, neditable):
        index = self.bar.close_file(neditable)
        layoutItem = self.stacked.takeAt(index)
        # neditable.editor.completer.cc.unload_module()
        self.fileClosed.emit(neditable.nfile)
        layoutItem.widget().deleteLater()

        if self.stacked.isEmpty():
            self.bar.hide()
            self.allFilesClosed.emit()
            tree_symbols = IDE.get_service("symbols_explorer")
            if tree_symbols is not None:
                tree_symbols.clear()

    def _editor_with_focus(self):
        self._main_container.combo_area = self
        editor = self.current_editor()
        if editor is not None:
            self._main_container.current_editor_changed(
                editor.neditable.file_path)
            self._load_symbols(editor.neditable)
            editor.neditable.update_checkers_display()

    def _ask_for_save(self, neditable):
        val = QMessageBox.No
        fileName = neditable.nfile.file_name
        val = QMessageBox.question(
            self, (self.tr('The file %s was not saved') %
                   fileName),
            self.tr("Do you want to save before closing?"),
            QMessageBox.Yes | QMessageBox.No |
            QMessageBox.Cancel)
        if val == QMessageBox.No:
            neditable.nfile.close(force_close=True)
        elif val == QMessageBox.Yes:
            neditable.ignore_checkers = True
            self._main_container.save_file(neditable.editor)
            neditable.nfile.close()

    @pyqtSlot("PyQt_PyObject")
    def _recovery(self, neditable):
        print("lalalal")

    def _file_has_been_modified(self, neditable):
        index = self.bar.combo_files.findData(neditable)
        self.stacked.setCurrentIndex(index)
        self.bar.combo_files.setCurrentIndex(index)

        msg_box = QMessageBox(self)
        msg_box.setIcon(QMessageBox.Information)
        msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        msg_box.setDefaultButton(QMessageBox.Yes)
        msg_box.setWindowTitle(translations.TR_FILE_HAS_BEEN_MODIFIED)
        msg_box.setText(
            translations.TR_FILE_MODIFIED_OUTSIDE % neditable.display_name)

        result = msg_box.exec_()
        if result == QMessageBox.Yes:
            neditable.reload_file()
        return

    def _run_file(self, path):
        self._main_container.run_file(path)

    def _add_to_project(self, path):
        self._main_container._add_to_project(path)

    def _show_file_in_explorer(self, path):
        '''Connected to ActionBar's showFileInExplorer(QString)
        signal, forwards the file path on to the main container.'''

        self._main_container._show_file_in_explorer(path)

    def set_current(self, neditable):
        if neditable:
            self.bar.set_current_file(neditable)

    def _set_current(self, neditable, index):
        self.stacked.setCurrentIndex(index)
        if neditable:
            self.bar.image_viewer_controls.setVisible(False)
            self.bar.code_navigator.setVisible(True)
            self.bar.symbols_combo.setVisible(True)
            self.bar.lbl_position.setVisible(True)

            editor = self.current_editor()
            self._update_cursor_position(ignore_sender=True)
            editor.setFocus()
            self._main_container.current_editor_changed(
                neditable.file_path)
            self._load_symbols(neditable)
            # self._show_file_in_explorer(neditable.file_path)
            neditable.update_checkers_display()
        else:
            self.bar.combo_files.setCurrentIndex(index)
            viewer_widget = self.stacked.widget(index)
            self._main_container.current_editor_changed(
                viewer_widget.image_filename)
            self.bar.image_viewer_controls.setVisible(True)
            self.bar.code_navigator.setVisible(False)
            self.bar.symbols_combo.setVisible(False)
            self.bar.lbl_position.setVisible(False)

    def widget(self, index):
        return self.stacked.widget(index)

    def count(self):
        """Return the number of editors opened."""
        return self.stacked.count()

    def _update_cursor_position(self, line=0, col=0, ignore_sender=False):
        obj = self.sender()
        editor = self.current_editor()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            line += 1
            self.bar.update_line_col(line, col)

    def _set_current_symbol(self, line, ignore_sender=False):
        obj = self.sender()
        editor = self.current_editor()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            index = bisect.bisect(self._symbols_index, line)
            if (index >= len(self._symbols_index) or
                    self._symbols_index[index] > (line + 1)):
                index -= 1
            self.bar.set_current_symbol(index)

    def _editor_modified(self, value, sender=None):
        if sender is None:
            sender = self.sender()
        neditable = sender.neditable
        if value:
            text = "\u2022 %s" % neditable.display_name
            self.bar.update_item_text(neditable, text)
        else:
            self.bar.update_item_text(neditable, neditable.display_name)

    def _go_to_symbol(self, index):
        line = self._symbols_index[index]
        editor = self.current_editor()
        editor.go_to_line(line, center=True)
        editor.setFocus()

    def _update_symbols(self, neditable):
        editor = self.current_editor()
        # Check if it's current to avoid signals from other splits.
        if editor.neditable == neditable:
            self._load_symbols(neditable)

    def _update_combo_info(self, neditable):
        self.bar.update_item_text(neditable, neditable.display_name)
        self._main_container.current_editor_changed(neditable.file_path)

    def _load_symbols(self, neditable):
        # Get symbols handler by language
        symbols_handler = handlers.get_symbols_handler(neditable.language())
        if symbols_handler is None:
            return
        source = neditable.editor.text
        source = source.encode(neditable.editor.encoding)
        symbols, symbols_simplified = symbols_handler.obtain_symbols(
            source, simple=True)
        self._symbols_index = sorted(symbols_simplified.keys())
        symbols_simplified = sorted(
            list(symbols_simplified.items()), key=lambda x: x[0])
        self.bar.add_symbols(symbols_simplified)
        line, _ = neditable.editor.cursor_position
        self._set_current_symbol(line, True)
        tree_symbols = IDE.get_service('symbols_explorer')
        if tree_symbols is not None:
            tree_symbols.update_symbols_tree(symbols, neditable.file_path)

    def _show_notification_icon(self, neditable):
        checkers = neditable.sorted_checkers
        icon = QIcon()
        for items in checkers:
            checker, color, _ = items
            if checker.checks:
                if isinstance(checker.checker_icon, int):
                    icon = self.style().standardIcon(checker.checker_icon)
                elif isinstance(checker.checker_icon, str):
                    icon = QIcon(checker.checker_icon)
                # FIXME: sucks
                else:
                    icon = QIcon(checker.checker_icon)
                break
        self.bar.update_item_icon(neditable, icon)

    def show_menu_navigation(self):
        self.bar.code_navigator.show_menu_navigation()

    def closeEvent(self, event):
        self.about_to_close_combo_editor.emit()
        # self.emit(SIGNAL("aboutToCloseComboEditor()"))
        super(ComboEditor, self).closeEvent(event)

    def reject(self):
        if not self.__original:
            super(ComboEditor, self).reject()
Пример #12
0
class Demo(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("测试")
        # 窗口大小
        self.resize(1400, 800)
        # self.setFixedSize(1500, 600)  # 设置窗口为固定尺寸, 此时窗口不可调整大小
        # self.setMinimumSize(1800, 1000)  # 设置窗口最大尺寸
        # self.setMaximumSize(900, 300)  # 设置窗口最小尺寸
        # self.setWindowFlag(Qt.WindowStaysOnTopHint)   # 设置窗口顶层显示
        # self.setWindowFlags(Qt.FramelessWindowHint)  # 设置无边框窗口样式,不显示最上面的标题栏

        self.content_font = QFont("微软雅黑", 12, QFont.Medium)  # 定义字体样式

        self.center()

        self.__setup_ui__()

    # 控制窗口显示在屏幕中心的方法

    def center(self):
        # 获得窗口
        qr = self.frameGeometry()
        # 获得屏幕中心点
        cp = QDesktopWidget().availableGeometry().center()
        # 显示到屏幕中心
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    # 关闭窗口的时候,触发了QCloseEvent,需要重写closeEvent()事件处理程序,这样就可以弹出是否退出的确认窗口
    def closeEvent(self, event):
        reply = QMessageBox.question(
            self,
            "退出程序",  # 提示框标题
            "确定退出xxxx程序吗?",  # 消息对话框中显示的文本
            QMessageBox.Yes | QMessageBox.No,  # 指定按钮的组合 Yes和No
            QMessageBox.No  # 默认的按钮焦点,这里默认是No按钮
        )
        # 判断按钮的选择
        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

    def __setup_ui__(self):
        # 工具栏
        self.frame_tool = QFrame(self)
        self.frame_tool.setObjectName("frame_tool")
        self.frame_tool.setGeometry(0, 0, self.width(), 25)
        self.frame_tool.setStyleSheet("border-color: rgb(0, 0, 0);")
        self.frame_tool.setFrameShape(QFrame.Panel)
        self.frame_tool.setFrameShadow(QFrame.Raised)

        # 1.1 界面1按钮
        self.window1_btn = QToolButton(self.frame_tool)
        self.window1_btn.setCheckable(True)
        self.window1_btn.setText("window1")
        self.window1_btn.setObjectName("menu_btn")
        self.window1_btn.resize(100, 25)
        self.window1_btn.clicked.connect(self.click_window1)
        self.window1_btn.setAutoRaise(
            True)  # 去掉工具按钮的边框线如果是QPushButton按钮的话,就是用setFlat(True)这个方法,用法相同

        # 1.2 界面2按钮
        self.window2_btn = QToolButton(self.frame_tool)
        self.window2_btn.setCheckable(True)
        self.window2_btn.setText("window2")
        self.window2_btn.setObjectName("menu_btn")
        self.window2_btn.resize(100, 25)
        self.window2_btn.move(self.window1_btn.width(), 0)
        self.window2_btn.clicked.connect(self.click_window2)
        self.window2_btn.setAutoRaise(True)

        self.btn_group = QButtonGroup(self.frame_tool)
        self.btn_group.addButton(self.window1_btn, 1)
        self.btn_group.addButton(self.window2_btn, 2)

        # 1.3 帮助下拉菜单栏
        # 创建帮助工具按钮
        help_btn = QToolButton(self.frame_tool)
        help_btn.setText("帮助")
        help_btn.setObjectName("menu_btn")
        help_btn.resize(100, 25)
        help_btn.move(self.window2_btn.x() + self.window2_btn.width(), 0)
        help_btn.setAutoRaise(True)
        help_btn.setPopupMode(QToolButton.InstantPopup)
        # 创建关于菜单
        help_menu = QMenu("帮助", self.frame_tool)
        feedback_action = QAction(QIcon("xxx.png"), "反馈", help_menu)
        feedback_action.triggered.connect(self.click_feedback)
        about_action = QAction(QIcon("xxx.png"), "关于", help_menu)
        about_action.triggered.connect(self.click_about)
        # 把两个QAction放入help_menu
        help_menu.addAction(feedback_action)
        help_menu.addAction(about_action)
        # 把help_menu放入help_btn
        help_btn.setMenu(help_menu)

        # 2. 工作区域
        self.main_frame = QFrame(self)
        self.main_frame.setGeometry(0, 25, self.width(),
                                    self.height() - self.frame_tool.height())
        # self.main_frame.setStyleSheet("background-color: rgb(65, 95, 255)")

        # 创建堆叠布局
        self.stacked_layout = QStackedLayout(self.main_frame)

        # 第一个布局
        self.main_frame1 = QMainWindow()
        self.frame1_bar = QStatusBar()
        self.frame1_bar.setObjectName("frame1_bar")
        self.main_frame1.setStatusBar(self.frame1_bar)
        self.frame1_bar.showMessage("欢迎进入frame1")

        rom_frame = QFrame(self.main_frame1)
        rom_frame.setGeometry(0, 0, self.width(),
                              self.main_frame.height() - 25)
        rom_frame.setFrameShape(QFrame.Panel)
        rom_frame.setFrameShadow(QFrame.Raised)

        # 超链接
        self.super_link = QLabel(rom_frame)
        self.super_link.setText("""
            超链接: <a href="https://blog.csdn.net/s_daqing">点击打开查看</a>
            """)
        self.super_link.setGeometry(20, 30, 300, 25)
        self.super_link.setFont(self.content_font)  # 使用字体样式
        self.super_link.setOpenExternalLinks(True)  # 使其成为超链接
        self.super_link.setTextInteractionFlags(
            Qt.TextBrowserInteraction)  # 双击可以复制文本

        self.start_btn = QPushButton("开 始", rom_frame)
        self.start_btn.setGeometry(self.width() * 0.7,
                                   self.height() * 0.8, 100, 40)
        # self.start_btn.clicked.connect(self.start_btn_click)
        self.quit_btn = QPushButton("退 出", rom_frame)
        self.quit_btn.setGeometry(self.width() * 0.85,
                                  self.height() * 0.8, 100, 40)
        self.quit_btn.setStatusTip("点击关闭程序")
        # self.quit_btn.clicked.connect(QCoreApplication.instance().quit)  # 点击退出可以直接退出
        self.quit_btn.clicked.connect(self.close)  # 点击退出按钮的退出槽函数

        #rom_frame1 = QFrame()
        #rom_frame1.setFrameShape(QFrame.Panel)
        #rom_frame1.setFrameShadow(QFrame.Raised)

        #rom_frame2 = QFrame()
        #rom_frame2.setFrameShape(QFrame.Panel)
        #rom_frame2.setFrameShadow(QFrame.Raised)

        # 创建布局管理器
        self.layout1 = QBoxLayout(QBoxLayout.TopToBottom)

        # 给管理器对象设置父控件
        rom_frame.setLayout(self.layout1)
        self.main_frame1.setCentralWidget(rom_frame)

        # 把子控件添加到布局管理器中
        #self.layout1.addWidget(rom_frame1, 1)
        #self.layout1.addWidget(rom_frame2, 1)

        self.layout1.setContentsMargins(0, 0, 0, 0)  # 设置布局的左上右下外边距
        self.layout1.setSpacing(0)  # 设置子控件的内边距

        frame1_bar_frame = QFrame(self.main_frame1)
        frame1_bar_frame.setGeometry(0, self.main_frame.height(), self.width(),
                                     25)

        # 第二个布局
        self.main_frame2 = QMainWindow()
        self.frame2_bar = QStatusBar()
        self.frame2_bar.setObjectName("frame2_bar")
        self.main_frame2.setStatusBar(self.frame2_bar)
        self.frame2_bar.showMessage("欢迎进入frame2")

        custom_frame = QFrame(self.main_frame2)
        custom_frame.setGeometry(0, 0, self.width(),
                                 self.main_frame.height() - 25)
        custom_frame.setFrameShape(QFrame.Panel)
        custom_frame.setFrameShadow(QFrame.Raised)

        custom_frame1 = QFrame()
        custom_frame1.setFrameShape(QFrame.Panel)
        custom_frame1.setFrameShadow(QFrame.Raised)

        custom_frame2 = QFrame()
        custom_frame2.setFrameShape(QFrame.Panel)
        custom_frame2.setFrameShadow(QFrame.Raised)

        custom_frame3 = QFrame()
        custom_frame3.setFrameShape(QFrame.Panel)
        custom_frame3.setFrameShadow(QFrame.Raised)

        # 创建布局管理器
        self.layout2 = QBoxLayout(QBoxLayout.TopToBottom)

        # 给管理器对象设置父控件
        custom_frame.setLayout(self.layout2)
        """
        使用了父类为QMainWindow的话,在里面使用布局类,QGridLayout, QHBoxLayout ,QVBoxLayout 等等时,发现不好用,
        加上下面这句代码就可以了,QMainWindow对象.setCentralWidget(这里填布局管理器的父控件对象)
        """
        self.main_frame2.setCentralWidget(custom_frame)

        # 把子控件添加到布局管理器中
        self.layout2.addWidget(custom_frame1, 1)
        self.layout2.addWidget(custom_frame2, 1)
        self.layout2.addWidget(custom_frame3, 1)

        self.layout2.setContentsMargins(0, 0, 0, 0)  # 设置布局的左上右下外边距
        self.layout2.setSpacing(0)  # 设置子控件的内边距

        frame2_bar_frame = QFrame(self.main_frame2)
        frame2_bar_frame.setGeometry(0, self.main_frame.height(), self.width(),
                                     25)

        # 把两个布局放进去
        self.stacked_layout.addWidget(self.main_frame1)
        self.stacked_layout.addWidget(self.main_frame2)

    def click_window1(self):
        if self.stacked_layout.currentIndex() != 0:
            self.stacked_layout.setCurrentIndex(0)
            self.frame1_bar.showMessage("欢迎进入frame1")

    def click_window2(self):
        if self.stacked_layout.currentIndex() != 1:
            self.stacked_layout.setCurrentIndex(1)
            self.frame2_bar.showMessage("欢迎进入frame2")
            QDesktopServices.openUrl(QUrl("https://www.csdn.net/")
                                     )  # 点击window2按钮后,执行这个槽函数的时候,会在浏览器自动打开这个网址

    def click_feedback(self, event):
        QMessageBox.about(self, "反馈",
                          "使用过程中如有疑问,请联系:xxxx.163.com\r\n\r\n版本:V1.0.1")

    def click_about(self, event):
        QMessageBox.about(self, "关于", "使用文档,请参考:xxxxxx")
Пример #13
0
class ComboEditor(QDialog):
    
    closeSplit = pyqtSignal(QWidget)#closeSplit
    allFilesClosed = pyqtSignal()
    splitEditor = pyqtSignal("QWidget*", "QWidget*", bool)
    recentTabsModified = pyqtSignal()
    aboutToCloseComboEditor = pyqtSignal()

    class NAVIGATE:
        prev = 0
        next = 1

    Q_ENUMS(NAVIGATE)

    def __init__(self, original=False):
        super(ComboEditor, self).__init__(None, Qt.WindowStaysOnTopHint)
        self.__original = original
        self.__undocked = []
        self._symbols_index = []
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)

        self.bar = ActionBar(main_combo=original)
        vbox.addWidget(self.bar)

        self.stacked = QStackedLayout()
        vbox.addLayout(self.stacked)

        self._main_container = IDE.get_service('main_container')

        if not self.__original:
            self._main_container.fileOpened.connect(self._file_opened_by_main)

        self.bar.combo.showComboSelector.connect(self._main_container.change_tab)
        self.bar.changeCurrent.connect(self._set_current)
        self.bar.editorSplited.connect(self.split_editor)
        self.bar.runFile[str].connect(self._run_file)
        self.bar.closeFile.connect(lambda: self.closeSplit.emit(self))
        self.bar.addToProject[str].connect(self._add_to_project)
        self.bar.showFileInExplorer.connect(self._show_file_in_explorer)
        self.bar.goToSymbol.connect(self._go_to_symbol)
        self.bar.undockEditor.connect(self.undock_editor)
        self.bar.reopenTab[str].connect(self._main_container.open_file)
        self.bar.recentTabsModified.connect(self._main_container.recent_files_changed)
        self.bar.code_navigator.btnPrevious.clicked['bool'].connect(lambda: self._navigate_code(self.NAVIGATE.prev))
        self.bar.code_navigator.btnNext.clicked['bool'].connect(lambda: self._navigate_code(self.NAVIGATE.prev))

    def _navigate_code(self, val):
        op = self.bar.code_navigator.operation
        self._main_container.navigate_code_history(val, op)

    def currentWidget(self):
        return self.stacked.currentWidget()

    def setFocus(self):
        super(ComboEditor, self).setFocus()
        w = self.stacked.currentWidget()
        if w:
            w.setFocus()
        self._editor_with_focus()

    def _file_opened_by_main(self, path):
        index = self.stacked.currentIndex()
        ninjaide = IDE.getInstance()
        editable = ninjaide.get_or_create_editable(path)
        print("_file_opened_by_main", editable)
        self.add_editor(editable)
        self.bar.set_current_by_index(index)
        if index == -1:
            self.bar.set_current_by_index(0)

    def add_editor(self, neditable, keep_index=False):
        """Add Editor Widget to the UI area."""
        if neditable.editor:
            if self.__original:
                editor = neditable.editor
            else:
                editor = self._main_container.create_editor_from_editable(
                    neditable)
            index = self.stacked.currentIndex()
            self.stacked.addWidget(editor)
            self.bar.add_item(neditable.display_name, neditable)
            if keep_index:
                self.bar.set_current_by_index(index)

            # Editor Signals
            editor.cursorPositionChanged[int, int].connect(self._update_cursor_position)
            editor.editorFocusObtained.connect(self._editor_with_focus)
            editor.currentLineChanged.connect(self._set_current_symbol)
            editor.modificationChanged['bool'].connect(self._editor_modified)
            neditable.checkersUpdated.connect(self._show_notification_icon)
            neditable.fileSaved.connect(self._update_symbols)
            neditable.fileSaved.connect(self._update_combo_info)

            # Connect file system signals only in the original
            neditable.fileClosing.connect(self._close_file)
            if self.__original:
                neditable.askForSaveFileClosing.connect(self._ask_for_save)
                neditable.fileChanged.connect(self._file_has_been_modified)

            # Load Symbols
            self._load_symbols(neditable)

    def show_combo_file(self):
        print("show_combo_file")
        self.bar.combo.showPopup()

    def show_combo_symbol(self):
        self.bar.symbols_combo.showPopup()

    def unlink_editors(self):
        for index in range(self.stacked.count()):
            widget = self.stacked.widget(index)
            widget.setDocument(QsciDocument())

    def split_editor(self, orientationVertical):
        new_widget = ComboEditor()
        for neditable in self.bar.get_editables():
            print("\nsplit_editor", neditable, new_widget)
            new_widget.add_editor(neditable)
        self.splitEditor.emit(self, new_widget, orientationVertical)

    def undock_editor(self):
        new_combo = ComboEditor()
        new_combo.setWindowTitle("NINJA-IDE")
        self.__undocked.append(new_combo)
        for neditable in self.bar.get_editables():
            print("undock_editor", neditable)
            new_combo.add_editor(neditable)
        new_combo.resize(500, 500)
        new_combo.aboutToCloseComboEditor.connect(self._remove_undock)
        new_combo.show()

    def _remove_undock(self):
        widget = self.sender()
        self.__undocked.remove(widget)

    def close_current_file(self):
        self.bar.about_to_close_file()

    def _close_file(self, neditable):
        index = self.bar.close_file(neditable)
        layoutItem = self.stacked.takeAt(index)
        #neditable.editor.completer.cc.unload_module()
        self._add_to_last_opened(neditable.file_path)
        layoutItem.widget().deleteLater()

        if self.stacked.isEmpty():
            self.allFilesClosed.emit()

    def _add_to_last_opened(self, path):
        if path not in settings.LAST_OPENED_FILES:
            settings.LAST_OPENED_FILES.append(path)
            if len(settings.LAST_OPENED_FILES) > settings.MAX_REMEMBER_TABS:
                self.__lastOpened = self.__lastOpened[1:]
            self.recentTabsModified.emit()

    def _editor_with_focus(self):
        if self._main_container.current_widget is not self:
            self._main_container.current_widget = self
            editor = self.stacked.currentWidget()
            self._main_container.current_editor_changed(
                editor.neditable.file_path)
            self._load_symbols(editor.neditable)
            editor.neditable.update_checkers_display()

    def _ask_for_save(self, neditable):
        val = QMessageBox.No
        fileName = neditable.nfile.file_name
        val = QMessageBox.question(
            self, (self.tr('The file %s was not saved') %
                   fileName),
            self.tr("Do you want to save before closing?"),
            QMessageBox.Yes | QMessageBox.No |
            QMessageBox.Cancel)
        if val == QMessageBox.No:
            neditable.nfile.close(force_close=True)
        elif val == QMessageBox.Yes:
            neditable.ignore_checkers = True
            self._main_container.save_file(neditable.editor)
            neditable.nfile.close()

    def _file_has_been_modified(self, neditable):
        val = QMessageBox.No
        fileName = neditable.file_path
        val = QMessageBox.question(
            self, translations.TR_FILE_HAS_BEEN_MODIFIED,
            "%s%s" % (fileName, translations.TR_FILE_MODIFIED_OUTSIDE),
            QMessageBox.Yes | QMessageBox.No)
        if val == QMessageBox.Yes:
            neditable.reload_file()

    def _run_file(self, path):
        self._main_container.run_file(path)

    def _add_to_project(self, path):
        self._main_container._add_to_project(path)

    def _show_file_in_explorer(self, path):
        '''Connected to ActionBar's showFileInExplorer(QString)
        signal, forwards the file path on to the main container.'''
        self._main_container._show_file_in_explorer(path)

    def set_current(self, neditable):
        if neditable:
            self.bar.set_current_file(neditable)

    def _set_current(self, neditable, index):
        if neditable:
            self.stacked.setCurrentIndex(index)
            editor = self.stacked.currentWidget()
            self._update_cursor_position(ignore_sender=True)
            editor.setFocus()
            self._main_container.current_editor_changed(
                neditable.file_path)
            self._load_symbols(neditable)
            self._show_file_in_explorer(neditable.file_path)
            neditable.update_checkers_display()

    def widget(self, index):
        return self.stacked.widget(index)

    def count(self):
        """Return the number of editors opened."""
        return self.stacked.count()

    def _update_cursor_position(self, line=0, col=0, ignore_sender=False):
        obj = self.sender()
        editor = self.stacked.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            line += 1
            self.bar.update_line_col(line, col)

    def _set_current_symbol(self, line, ignore_sender=False):
        obj = self.sender()
        editor = self.stacked.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            index = bisect.bisect(self._symbols_index, line)
            if (index >= len(self._symbols_index) or
                    self._symbols_index[index] > (line + 1)):
                index -= 1
            self.bar.set_current_symbol(index)

    def _editor_modified(self, value):
        obj = self.sender()
        neditable = obj.neditable
        if value:
            text = "\u2022 %s" % neditable.display_name
            self.bar.update_item_text(neditable, text)
        else:
            self.bar.update_item_text(neditable, neditable.display_name)

    def _go_to_symbol(self, index):
        print("_go_to_symbol in index:", index)
        line = self._symbols_index[index]
        editor = self.stacked.currentWidget()
        editor.go_to_line(line)

    def _update_symbols(self, neditable):
        editor = self.stacked.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if editor == neditable.editor:
            self._load_symbols(neditable)

    def _update_combo_info(self, neditable):
        self.bar.update_item_text(neditable, neditable.display_name)
        self._main_container.current_editor_changed(neditable.file_path)

    def _load_symbols(self, neditable):
        symbols_handler = handlers.get_symbols_handler('py')
        source = neditable.editor.text()
        source = source.encode(neditable.editor.encoding)
        symbols, symbols_simplified = symbols_handler.obtain_symbols(
            source, simple=True)
        self._symbols_index = sorted(symbols_simplified.keys())
        symbols_simplified = sorted(
            list(symbols_simplified.items()), key=lambda x: x[0])
        self.bar.add_symbols(symbols_simplified)
        line, _ = neditable.editor.getCursorPosition()
        self._set_current_symbol(line, True)
        tree_symbols = IDE.get_service('symbols_explorer')
        tree_symbols.update_symbols_tree(symbols, neditable.file_path)

    def _show_notification_icon(self, neditable):
        checkers = neditable.sorted_checkers
        icon = QIcon()
        for items in checkers:
            checker, color, _ = items
            if checker.checks:
                if isinstance(checker.checker_icon, int):
                    icon = self.style().standardIcon(checker.checker_icon)
                elif isinstance(checker.checker_icon, str):
                    icon = QIcon(checker.checker_icon)
                break
        self.bar.update_item_icon(neditable, icon)

    def show_menu_navigation(self):
        self.bar.code_navigator.show_menu_navigation()

    def closeEvent(self, event):
        self.aboutToCloseComboEditor.emit()
        super(ComboEditor, self).closeEvent(event)

    def reject(self):
        if not self.__original:
            super(ComboEditor, self).reject()
Пример #14
0
class MainWindow(QWidget):
    """
    Root widget for application.
    Handles signals.
    """

    def __init__(self, items):
        """
        Init gui.
        Connect signals.
        Create layout.
        """

        super().__init__()

        self.items = items
        self.user = None
        self.communication = Communication()
        self.frames_layout = QStackedLayout()
        self.data_frame_index = None
        self.top_system_frame_height = 0

        self._init_gui()
        self._set_shortcuts()

    def _init_gui(self):
        self._set_sys_attributes()
        self._create_layout()
        self.communication.menu_btn_clicked.connect(self.menu_btn_clicked)
        self.show()
        self._first_start_check()

    def _first_start_check(self):

        def _import_templates(value):
            if value:
                from app.model import template
                template.Template.import_(options.INIT_TEMPLATES_PATH)
                self.show_message('Готово!')
            db.KeyValue(key=options.FIRST_START_KEY, value='').save()

        try:
            first_time = db.KeyValue.get(key=options.FIRST_START_KEY).value
        except (exc.NoResultFound, AttributeError):
            first_time = True

        if first_time:
            self.create_alert(options.FIRST_START_WELCOME_TEXT, _import_templates)

    def _create_layout(self):
        """
        Add TopFrame and main frames.
        """

        MessageWidget(self)
        vbox = QVBoxLayout()
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)
        self.setLayout(vbox)

        ActionButton(self)
        vbox.addWidget(TopFrame(self, self.items), stretch=15)
        vbox.addLayout(self.frames_layout, stretch=40)
        self._add_frames()
        self.show()

    def _add_frames(self):
        """
        Add frames to stacked layout.
        """

        frames = [
            DataWidget(self, self.items),
            TemplateWidget(self, self.items),
            DBWidget(self),
            OptionsWidget(self, self.items),
            UsersWidget(self),
        ]

        for i, frame in enumerate(frames):
            if isinstance(frame, DataWidget):
                self.data_frame_index = i
            if isinstance(frame, UsersWidget):
                self.user_frame_index = i
            self.frames_layout.addWidget(frame)

        self.frames_layout.setCurrentIndex(len(frames) - 1)

    def _set_sys_attributes(self):
        """
        Set sys attributes like window titile.
        Disable OS-specific buttons.
        Remove borders.
        """

        self.setWindowFlags(Qt.FramelessWindowHint)

        self.setWindowTitle('Hospital Helper')
        dw = QDesktopWidget()
        w = min(1300, dw.geometry().size().width() * 0.75)
        self.setFixedSize(w, w * 0.6)
        qr = self.frameGeometry()
        cp = dw.availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def menu_btn_clicked(self, index):
        """
        Callback to switch between main frames.
        """

        if self.frames_layout.currentIndex() == index == self.data_frame_index:
            self.communication.toggle_select_item.emit()
            return
        else:
            self.communication.set_select_item_visibility.emit(False)
        self.frames_layout.setCurrentIndex(index)

    def input_changed(self, item):
        """
        Change TopFrame label when client name is changed.
        Emit signal for TopFrame.
        """

        # Well it doesnt look good, but i was never good with UI.
        if self.items.index(item) == 0:
            text = []
            for i, key in enumerate(item.keys()):
                if item[key]:
                    text.append(str(item[key]))
                if i == 2:
                    break

            self.communication.input_changed_signal.emit(' '.join(text))

    def _set_shortcuts(self):
        """
        Set shortcuts for fast items switch on DataWidget.
        """

        def _shortcut_callback(key):
            if self.frames_layout.currentIndex() != self.data_frame_index:
                return
            self.communication.shortcut_pressed.emit(key)

        QShortcut(QKeySequence('Esc'), self).activated.connect(self.close)
        keys = [str(i) for i in range(0, 11)] + [chr(c) for c in range(ord('A'), ord('Z') + 1)]
        for key in keys:
            QShortcut(QKeySequence('Ctrl+{}'.format(key)), self).activated.connect(
                functools.partial(_shortcut_callback, key))

    def create_crud_widget(self, model, callback, db_object=None):
        """
        Add CrudWidget with self as parent
        """

        CrudWidget(self, model, callback, db_object)

    def create_alert(self, text, callback=None):
        AlertWidget(self, text, callback)

    def show_message(self, text):
        self.communication.set_message_text.emit(text)

    def user_selected(self, user, go_to_data_frame=False):
        """
        Callback when user is selected.
        Sets user, emits signal.
        """

        self.user = user
        self.communication.user_selected.emit(user)
        if go_to_data_frame:
            self.communication.menu_btn_clicked.emit(self.data_frame_index)

    def create_report(self):
        """
        Render and save report.
        Open report in default OS program.
        """

        r = report.Report(self.user, self.items)
        db_report = r.render_and_save()
        r.open(db_report.path)
        self.show_message('Отчет создан')

    def clean_input(self):
        def _clean_input(value):
            if not value:
                return

            self.communication.clean_items.emit()
            self.communication.input_changed_signal.emit('')
            for item in self.items:
                item.clean()
            self.show_message('Ok')

        self.create_alert('Очистить все поля?', _clean_input)

    def resized(self, top_frame, top_sys_btns, event):
        """
        Called when window is resized.
        Calculates Y position of the border between TopFrame and DataFrame
        """

        waterline = top_frame.y() + top_frame.height()
        self.top_system_frame_height = top_sys_btns.height()
        self.communication.resized.emit(self.width(), waterline, self.top_system_frame_height)

    def keyPressEvent(self, event):
        """
        If key is Ctrl - toggle SelectItemMenu visibility.
        If key is Ctrl+Return - opens ReportFrame
        Emits signal.
        """

        mods = event.modifiers()
        if mods & Qt.ControlModifier and self.frames_layout.currentIndex() == self.data_frame_index:
            if event.text() is '':
                self.communication.ctrl_hotkey.emit(True)
                return
            elif event.key() == Qt.Key_Return:
                self.communication.menu_btn_clicked.emit(self.data_frame_index + 1)

    def keyReleaseEvent(self, event):
        """
        If key is Ctrl - toggle SelectItemMenu visibility.
        """

        if event.text() is '':
            self.communication.ctrl_hotkey.emit(False)

    def close(self, event=None):
        """
        Close the application
        """

        QCoreApplication.instance().quit()

    def minimize(self, event=None):
        """
        Minimize the application
        """

        self.setWindowState(Qt.WindowMinimized)
Пример #15
0
class MainWindow(QWidget):
    """
    Root widget for application.
    Handles signals.
    """
    def __init__(self, items):
        """
        Init gui.
        Connect signals.
        Create layout.
        """

        super().__init__()

        self.items = items
        self.user = None
        self.communication = Communication()
        self.frames_layout = QStackedLayout()
        self.data_frame_index = None
        self.top_system_frame_height = 0

        self._init_gui()
        self._set_shortcuts()

    def _init_gui(self):
        self._set_sys_attributes()
        self._create_layout()
        self.communication.menu_btn_clicked.connect(self.menu_btn_clicked)
        self.show()
        self._first_start_check()

    def _first_start_check(self):
        def _import_templates(value):
            if value:
                from app.model import template
                template.Template.import_(options.INIT_TEMPLATES_PATH)
                # self.show_message('Готово!')
                self.show_message('Feito!')
            db.KeyValue(key=options.FIRST_START_KEY, value='').save()

        # try:
        #     first_time = db.KeyValue.get(key=options.FIRST_START_KEY).value
        # except (exc.NoResultFound, AttributeError):
        #     first_time = True

        # if first_time:
        #     self.create_alert(options.FIRST_START_WELCOME_TEXT, _import_templates)

    def _create_layout(self):
        """
        Add TopFrame and main frames.
        """

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

        vbox.addWidget(TopFrame(self, self.items), stretch=15)
        vbox.addLayout(self.frames_layout, stretch=40)
        self._add_frames()
        self.show()

    def _add_frames(self):
        """
        Add frames to stacked layout.
        """

        # frames = [
        #     DataWidget(self, self.items),
        #     TemplateWidget(self, self.items),
        #     DBWidget(self),
        #     OptionsWidget(self, self.items),
        #     UsersWidget(self),
        # ]

        # for i, frame in enumerate(frames):
        #     if isinstance(frame, DataWidget):
        #         self.data_frame_index = i
        #     if isinstance(frame, UsersWidget):
        #         self.user_frame_index = i
        #     self.frames_layout.addWidget(frame)

        # self.frames_layout.setCurrentIndex(len(frames) - 1)

    def _set_sys_attributes(self):
        """
        Set sys attributes like window title.
        Disable OS-specific buttons.
        Remove borders.
        """

        self.setWindowFlags(Qt.FramelessWindowHint)

        self.setWindowTitle('Hospital Helper')
        dw = QDesktopWidget()
        w = min(1300, dw.geometry().size().width() * 0.75)
        self.setFixedSize(w, w * 0.65)
        qr = self.frameGeometry()
        cp = dw.availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def menu_btn_clicked(self, index):
        """
        Callback to switch between main frames.
        """

        if self.frames_layout.currentIndex() == index == self.data_frame_index:
            self.communication.toggle_select_item.emit()
            return
        else:
            self.communication.set_select_item_visibility.emit(False)
        self.frames_layout.setCurrentIndex(index)

    def input_changed(self, item):
        """
        Change TopFrame label when client name is changed.
        Emit signal for TopFrame.
        """

        # Well it doesnt look good, but i was never good with UI.
        if self.items.index(item) == 0:
            text = []
            for i, key in enumerate(item.keys()):
                if item[key]:
                    text.append(str(item[key]))
                if i == 2:
                    break

            self.communication.input_changed_signal.emit(' '.join(text))

    def _set_shortcuts(self):
        """
        Set shortcuts for fast items switch on DataWidget.
        """
        def _shortcut_callback(key):
            if self.frames_layout.currentIndex() != self.data_frame_index:
                return
            self.communication.shortcut_pressed.emit(key)

        # QShortcut(QKeySequence('Esc'), self).activated.connect(self.close)
        keys = [str(i) for i in range(0, 11)
                ] + [chr(c) for c in range(ord('A'),
                                           ord('Z') + 1)]
        for key in keys:
            QShortcut(QKeySequence('Ctrl+{}'.format(key)),
                      self).activated.connect(
                          functools.partial(_shortcut_callback, key))

    def create_crud_widget(self, model, callback, db_object=None):
        """
        Add CrudWidget with self as parent
        """

        CrudWidget(self, model, callback, db_object)

    def create_alert(self, text, callback=None):
        AlertWidget(self, text, callback)

    def show_message(self, text):
        self.communication.set_message_text.emit(text)

    def user_selected(self, user, go_to_data_frame=False):
        """
        Callback when user is selected.
        Sets user, emits signal.
        """

        self.user = user
        self.communication.user_selected.emit(user)
        if go_to_data_frame:
            self.communication.menu_btn_clicked.emit(self.data_frame_index)

    def create_report(self, event=None):
        """
        Render and save report.
        Open report in default OS program.
        """

        r = report.Report(self.user, self.items)
        db_report = r.render_and_save()
        r.open(db_report.path)
        # self.show_message('Отчет создан')
        self.show_message('Relatório criado')

    def clean_input(self):
        def _clean_input(value):
            if not value:
                return

            self.communication.clean_items.emit()
            self.communication.input_changed_signal.emit('')
            for item in self.items:
                item.clean()
            self.show_message('Ok')

        # self.create_alert('Очистить все поля?', _clean_input)
        self.create_alert('Limpar todos os campos?', _clean_input)

    def resized(self, top_frame, top_sys_btns, event):
        """
        Called when window is resized.
        Calculates Y position of the border between TopFrame and DataFrame
        """

        waterline = top_frame.y() + top_frame.height()
        self.top_system_frame_height = top_sys_btns.height()
        self.communication.resized.emit(self.width(), waterline,
                                        self.top_system_frame_height)

    def keyPressEvent(self, event):
        """
        If key is Ctrl - toggle SelectItemMenu visibility.
        If key is Ctrl+Return - opens ReportFrame
        Emits signal.
        """

        mods = event.modifiers()
        if mods & Qt.ControlModifier and self.frames_layout.currentIndex(
        ) == self.data_frame_index:
            if event.text() is '':
                self.communication.ctrl_hotkey.emit(True)
                return
            elif event.key() == Qt.Key_Return:
                self.communication.menu_btn_clicked.emit(
                    self.data_frame_index + 1)

    def keyReleaseEvent(self, event):
        """
        If key is Ctrl - toggle SelectItemMenu visibility.
        """

        if event.text() is '':
            self.communication.ctrl_hotkey.emit(False)

    def close(self, event=None):
        """
        Close the application
        """

        QCoreApplication.instance().quit()

    def minimize(self, event=None):
        """
        Minimize the application
        """

        self.setWindowState(Qt.WindowMinimized)

    def excepthook(self, exctype, value, traceback):
        with open(options.LOG_FILE, 'a') as f:
            f.write('\n{}\n{}'.format(
                datetime.datetime.now(),
                '\n'.join(trb.format_exception(exctype, value, traceback))))

        # self.create_alert('Произошла непредвиденная ошибка.\n'
        #                   'Попробуйте повторить действие, хотя это вряд ли поможет')
        self.create_alert(
            'Um erro inesperado ocorreu.\n'
            'Tente repetir a ação, embora seja improvável que isso ajude.')
Пример #16
0
class TopForm(QMainWindow):
    def __init__(self, parent=None, client_list=None):
        #super(TopForm, self).__init__()
        #super().__init__()
        QMainWindow.__init__(self)
        self.client_list = client_list
        self.initUI(client_list)

    def initUI(self, client=None):

        # Hide default system buttons
        self.setWindowFlags(Qt.Window | Qt.WindowTitleHint
                            | Qt.WindowCloseButtonHint)

        #self.screen = QDesktopWidget().screenGeometry()
        #self.setGeometry(0,0,50,40)
        #self.resize(self.screen.width(),self.screen.height())
        self.cwid = QWidget(self)
        self.setCentralWidget(self.cwid)
        self.layout = QGridLayout()
        self.cwid.setLayout(self.layout)

        self.layout.setSpacing(0)
        self.layout.setContentsMargins(0, 0, 20, 0)

        self.mainForm = MainForm(self, client_list=client)
        self.loginForm = LoginForm(self)
        self.loginForm.loginBtn.clicked.connect(self.loginClicked)

        self.firststack = QStackedLayout()
        self.firststack.addWidget(self.loginForm)
        self.firststack.addWidget(self.mainForm)
        self.layout.addLayout(self.firststack, 1, 1)
        #self.layout.addLayout(self.firststack)

        #self.layout.insertStretch(1, 1)
        self.showFullScreen()

    def loginClicked(self):
        # Check username and password, if matched, then
        # close login form and show main form
        username = self.loginForm.userInput.text()
        password = self.loginForm.pwdInput.text()

        #check whether username/password stored
        #in the userdata module checks ok
        #userdata module can be extended to include mysql database
        #if ( 1== 0  ):
        if (not checkPass(username, password)):
            #user pass do not match
            #print an error message in the mainform
            self.loginForm.showErrorLogin()
        else:
            if self.firststack.currentIndex() == 0:
                self.firststack.setCurrentIndex(1)

        if username == password or username == 'admin':
            pass

        change_location(0, self.client_list)

        for i in range(len(check_list)):
            file_changed(check_list[i])

    # Function for place center

    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    # Default function for close event
    def closeEvent(self, event):
        # Show confirm prompt for exit
        reply = QMessageBox.question(self, 'Message', "Are you sure to quit?",
                                     QMessageBox.Yes, QMessageBox.No)

        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()
Пример #17
0
class excitation_input(
        QWidget, ):
    """
    class to take input of excited states for CCFULL
    
    if type = 0: inert. no input required. 
    if type = 1: vibrational case 
              omega, beta, lambda, nphonon 
              
              if nuclei='target', additional input 
              omega_2, beta_2, lambda_2, nphonon_2 
              
    if type =2 : rotational case 
              e2, beta2, beta4, nrot             
    """
    def __init__(self, nuclei='target', type_index=0):
        super().__init__()
        self.layout = QStackedLayout()
        self.setLayout(self.layout)
        self.nuclei = nuclei
        #---first page
        self.widget_first_page = QLabel('Inert ({})'.format(nuclei))
        self.layout.addWidget(self.widget_first_page)
        #--second page
        self.widget_second_page = QWidget()
        self.layout.addWidget(self.widget_second_page)
        self.second_layout = QGridLayout()
        self.widget_second_page.setLayout(self.second_layout)

        self.second_layout.addWidget(QLabel('Vibrational ({})'.format(nuclei)),
                                     0, 0)
        self.vib_lambda = QLineEdit('3')
        self.vib_omega = QLineEdit('1.81')
        self.vib_beta = QLineEdit('0.205')
        self.vib_nphonon = QLineEdit('1')
        self.vib_add_mod = QCheckBox('add. mod.')
        self.vib_lambda2 = QLineEdit('0')
        self.vib_omega2 = QLineEdit('0.0')
        self.vib_beta2 = QLineEdit('0.0')
        self.vib_nphonon2 = QLineEdit('0')

        self.vib_main_widget = combined_Widgets_grid(
            [[
                QLabel('lambda'), self.vib_lambda,
                QLabel('hbar omega'), self.vib_omega
            ],
             [
                 QLabel('beta_lambda'), self.vib_beta,
                 QLabel('number of phonons'), self.vib_nphonon
             ]])
        self.second_layout.addWidget(self.vib_main_widget)

        if nuclei == 'target':
            self.vib_2nd_widget = combined_Widgets_grid(
                [[QCheckBox('additional mode')],
                 [
                     QLabel('lambda'), self.vib_lambda2,
                     QLabel('hbar omega'), self.vib_omega2
                 ],
                 [
                     QLabel('beta_lambda'), self.vib_beta2,
                     QLabel('number of phonons'), self.vib_nphonon2
                 ]])
            self.second_layout.addWidget(self.vib_2nd_widget)

        #--third page
        self.widget_third_page = QWidget()
        self.layout.addWidget(self.widget_third_page)
        self.third_layout = QGridLayout()
        self.widget_third_page.setLayout(self.third_layout)

        self.linEdit_E2 = QLineEdit()
        self.linEdit_beta2 = QLineEdit()
        self.linEdit_beta4 = QLineEdit()
        self.linEdit_nrot = QLineEdit()
        self.rot_widget = combined_Widgets_grid(
            [[QLabel('Rotational ({})'.format(nuclei))],
             [QLabel('energy(2+)'), self.linEdit_E2],
             [QLabel('beta_2'), self.linEdit_beta2],
             [QLabel('beta_4'), self.linEdit_beta4],
             [QLabel('number of levels'), self.linEdit_nrot]])
        self.third_layout.addWidget(self.rot_widget)

        #---initial page
        self.layout.setCurrentIndex(type_index)

    def change_type(self, type_index):
        self.layout.setCurrentIndex(type_index)

    def read_input(self, ):
        output = {}
        type_index = self.layout.currentIndex()
        output['type'] = type_index
        output['nuclei'] = self.nuclei
        if type_index == 0:  # inert
            pass
        elif type_index == 1:  # vibrational
            output['vib'] = self.vib_main_widget.get_values()
            if self.nuclei == 'target':
                output['vib2'] = self.vib_2nd_widget.get_values()
        elif type_index == 2:  #rotational
            output['rot'] = self.rot_widget.get_values()
        return output

    def set_values(self, input_dict):
        #--opposite of read_input
        self.layout.setCurrentIndex(input_dict['type'])
        type_index = input_dict['type']
        self.nuclei = input_dict['nuclei']
        if type_index == 1:
            self.vib_main_widget.put_values(input_dict['vib'])
            if self.nuclei == 'target':
                self.vib_2nd_widget.put_values(input_dict['vib2'])
        elif type_index == 2:
            self.rot_widget.put_values(input_dict['rot'])
        return
Пример #18
0
class AppWindow(QMainWindow):
	"The application's main window"
	move_listener = pyqtSignal()
	db_activity_checker = pyqtSignal()
	graphics_blur = QGraphicsBlurEffect()
	def __init__(self):
		super().__init__()
		app_constants.GENERAL_THREAD = QThread(self)
		app_constants.GENERAL_THREAD.finished.connect(app_constants.GENERAL_THREAD.deleteLater)
		app_constants.GENERAL_THREAD.start()
		self.setAcceptDrops(True)
		self.initUI()
		self.start_up()
		QTimer.singleShot(3000, self._check_update)
		self.setFocusPolicy(Qt.NoFocus)
		self.set_shortcuts()
		self.graphics_blur.setParent(self)
		#ex = settings.ExProperties()
		#d = pewnet.ExHenManager(ex.ipb_id, ex.ipb_pass)
		#item = d.from_gallery_url('http://exhentai.org/g/861957/02741dc584/')
		#def a(): print(item.file)
		#if not item.file:
		#	item.file_rdy.connect(a)
		#else:
		#	a()

	def set_shortcuts(self):
		quit = QShortcut(QKeySequence('Ctrl+Q'), self, self.close)

	def init_watchers(self):

		def remove_gallery(g):
			index = self.manga_list_view.find_index(g.id, True)
			if index:
				self.manga_list_view.remove_gallery([index])

		def create_gallery(path):
			g_dia = gallerydialog.GalleryDialog(self, path)
			g_dia.SERIES.connect(self.manga_list_view.gallery_model.addRows)
			g_dia.show()

		def update_gallery(g):
			index = self.manga_list_view.find_index(g.id)
			if index:
				self.manga_list_view.replace_edit_gallery([g], index.row())
			else:
				log_e('Could not find gallery to update from watcher')

		def created(path):
			c_popup = io_misc.CreatedPopup(path, self)
			c_popup.ADD_SIGNAL.connect(create_gallery)
		def modified(path, gallery):
			mod_popup = io_misc.ModifiedPopup(path, gallery, self)
		def deleted(path, gallery):
			d_popup = io_misc.DeletedPopup(path, gallery, self)
			d_popup.UPDATE_SIGNAL.connect(update_gallery)
			d_popup.REMOVE_SIGNAL.connect(remove_gallery)
		def moved(new_path, gallery):
			mov_popup = io_misc.MovedPopup(new_path, gallery, self)
			mov_popup.UPDATE_SIGNAL.connect(update_gallery)

		self.watchers = io_misc.Watchers()
		self.watchers.gallery_handler.CREATE_SIGNAL.connect(created)
		self.watchers.gallery_handler.MODIFIED_SIGNAL.connect(modified)
		self.watchers.gallery_handler.MOVED_SIGNAL.connect(moved)
		self.watchers.gallery_handler.DELETED_SIGNAL.connect(deleted)

	admin_db_method_invoker = pyqtSignal(str)
	def start_up(self):
		hello = ["Hello!", "Hi!", "Onii-chan!", "Senpai!", "Hisashiburi!", "Welcome!", "Okaerinasai!", "Welcome back!", "Hajimemashite!"]
		self.notification_bar.add_text("{} Please don't hesitate to report any bugs you find.".format(hello[random.randint(0, len(hello)-1)])+
								 " Go to Settings -> About -> Bug Reporting for more info!")
		level = 5
		def normalize_first_time():
			settings.set(level, 'Application', 'first time level')
			settings.save()

		def done(status=True):
			gallerydb.DatabaseEmitter.RUN = True
			if app_constants.FIRST_TIME_LEVEL != level:
				normalize_first_time()
			if app_constants.ENABLE_MONITOR and\
				app_constants.MONITOR_PATHS and all(app_constants.MONITOR_PATHS):
				self.init_watchers()
				if app_constants.LOOK_NEW_GALLERY_STARTUP:
					if self.manga_list_view.gallery_model.db_emitter.count == app_constants.GALLERY_DATA:
						self.scan_for_new_galleries()
					else:
						self.manga_list_view.gallery_model.db_emitter.DONE.connect(self.scan_for_new_galleries)
			self.download_manager = pewnet.Downloader()
			app_constants.DOWNLOAD_MANAGER = self.download_manager
			self.download_manager.start_manager(4)

		if app_constants.FIRST_TIME_LEVEL < 4:
			log_i('Invoking first time level {}'.format(4))
			settings.set([], 'Application', 'monitor paths')
			settings.set([], 'Application', 'ignore paths')
			app_constants.MONITOR_PATHS = []
			app_constants.IGNORE_PATHS = []
			settings.save()
			done()
		elif app_constants.FIRST_TIME_LEVEL < 5:
			log_i('Invoking first time level {}'.format(5))
			app_widget = misc.ApplicationPopup(self)
			app_widget.note_info.setText("<font color='red'>IMPORTANT:</font> Application restart is required when done")
			app_widget.restart_info.hide()
			self.admin_db = gallerydb.AdminDB()
			self.admin_db.moveToThread(app_constants.GENERAL_THREAD)
			self.admin_db.DONE.connect(done)
			self.admin_db.DONE.connect(lambda: app_constants.NOTIF_BAR.add_text("Application requires a restart"))
			self.admin_db.DONE.connect(self.admin_db.deleteLater)
			self.admin_db.DATA_COUNT.connect(app_widget.prog.setMaximum)
			self.admin_db.PROGRESS.connect(app_widget.prog.setValue)
			self.admin_db_method_invoker.connect(self.admin_db.rebuild_db)
			self.admin_db_method_invoker.connect(app_widget.show)
			app_widget.adjustSize()
			db_p = os.path.join(os.path.split(database.db_constants.DB_PATH)[0], 'sadpanda.db')
			self.admin_db_method_invoker.emit(db_p)
		else:
			done()

	def initUI(self):
		self.center = QWidget()
		self.display = QStackedLayout()
		self._main_layout = QVBoxLayout()
		self._main_layout.setSpacing(0)
		self._main_layout.setContentsMargins(0,0,0,0)
		self._main_layout.addLayout(self.display)
		self.center.setLayout(self._main_layout)
		# init the manga view variables
		self.manga_display()
		log_d('Create manga display: OK')
		# init the chapter view variables
		#self.chapter_display()
		self.m_l_view_index = self.display.addWidget(self.manga_list_view)
		self.m_t_view_index = self.display.addWidget(self.manga_table_view)
		self.download_window = io_misc.GalleryDownloader(self)
		self.download_window.hide()
		# init toolbar
		self.init_toolbar()
		log_d('Create toolbar: OK')
		# init status bar
		self.init_stat_bar()
		log_d('Create statusbar: OK')

		self.tags_treeview = None
		if app_constants.TAGS_TREEVIEW_ON_START:
			def tags_tree_none(): self.tags_treeview = None
			self.tags_treeview = misc_db.DBOverview(self, True)
			self.tags_treeview.about_to_close.connect(tags_tree_none)
			self.tags_treeview.show()

		self.system_tray = misc.SystemTray(QIcon(app_constants.APP_ICO_PATH), self)
		app_constants.SYSTEM_TRAY = self.system_tray
		tray_menu = QMenu(self)
		self.system_tray.setContextMenu(tray_menu)
		self.system_tray.setToolTip('Happypanda {}'.format(app_constants.vs))
		tray_quit = QAction('Quit', tray_menu)
		tray_update = tray_menu.addAction('Check for update')
		tray_update.triggered.connect(self._check_update)
		tray_menu.addAction(tray_quit)
		tray_quit.triggered.connect(self.close)
		self.system_tray.show()
		def tray_activate(r=None):
			if not r or r == QSystemTrayIcon.Trigger:
				self.showNormal()
				self.activateWindow()
		self.system_tray.messageClicked.connect(tray_activate)
		self.system_tray.activated.connect(tray_activate)
		log_d('Create system tray: OK')
		#self.display.addWidget(self.chapter_main)

		self.setCentralWidget(self.center)
		self.setWindowIcon(QIcon(app_constants.APP_ICO_PATH))


		props = settings.win_read(self, 'AppWindow')
		if props.resize:
			x, y = props.resize
			self.resize(x, y)
		else:
			self.resize(app_constants.MAIN_W, app_constants.MAIN_H)
		posx, posy = props.pos
		self.move(posx, posy)
		self.init_spinners()
		self.show()
		log_d('Show window: OK')

		self.notification_bar = misc.NotificationOverlay(self)
		p = self.toolbar.pos()
		self.notification_bar.move(p.x(), p.y()+self.toolbar.height())
		self.notification_bar.resize(self.width())
		app_constants.NOTIF_BAR = self.notification_bar
		log_d('Create notificationbar: OK')

		log_d('Window Create: OK')

	def _check_update(self):
		class upd_chk(QObject):
			UPDATE_CHECK = pyqtSignal(str)
			def __init__(self, **kwargs):
				super().__init__(**kwargs)
			def fetch_vs(self):
				import requests
				import time
				log_d('Checking Update')
				time.sleep(1.5)
				try:
					if os.path.exists('cacert.pem'):
						r = requests.get("https://raw.githubusercontent.com/Pewpews/happypanda/master/VS.txt",
							  verify='cacert.pem')
					else:
						r = requests.get("https://raw.githubusercontent.com/Pewpews/happypanda/master/VS.txt")
					a = r.text
					vs = a.strip()
					self.UPDATE_CHECK.emit(vs)
				except:
					log.exception('Checking Update: FAIL')
					self.UPDATE_CHECK.emit('this is a very long text which is sure to be over limit')

		def check_update(vs):
			log_i('Received version: {}\nCurrent version: {}'.format(vs, app_constants.vs))
			if vs != app_constants.vs:
				if len(vs) < 10:
					self.notification_bar.begin_show()
					self.notification_bar.add_text("Version {} of Happypanda is".format(vs)+
									   " available. Click here to update!", False)
					self.notification_bar.clicked.connect(lambda: utils.open_web_link(
						'https://github.com/Pewpews/happypanda/releases'))
					self.notification_bar.set_clickable(True)
				else:
					self.notification_bar.add_text("An error occurred while checking for new version")

		self.update_instance = upd_chk()
		thread = QThread(self)
		self.update_instance.moveToThread(thread)
		thread.started.connect(self.update_instance.fetch_vs)
		self.update_instance.UPDATE_CHECK.connect(check_update)
		self.update_instance.UPDATE_CHECK.connect(self.update_instance.deleteLater)
		thread.finished.connect(thread.deleteLater)
		thread.start()

	def _web_metadata_picker(self, gallery, title_url_list, queue, parent=None):
		if not parent:
			parent = self
		text = "Which gallery do you want to extract metadata from?"
		s_gallery_popup = misc.SingleGalleryChoices(gallery, title_url_list,
											  text, parent)
		s_gallery_popup.USER_CHOICE.connect(queue.put)

	def get_metadata(self, gal=None):
		metadata_spinner = misc.Spinner(self)
		def move_md_spinner():
			metadata_spinner.update_move(
			QPoint(
				self.pos().x()+self.width()-65,
				self.pos().y()+self.toolbar.height()+55))
		metadata_spinner.set_text("Metadata")
		metadata_spinner.set_size(55)
		metadata_spinner.move(QPoint(self.pos().x()+self.width()-65,
							   self.pos().y()+self.toolbar.height()+55))
		self.move_listener.connect(move_md_spinner)
		thread = QThread(self)
		thread.setObjectName('App.get_metadata')
		fetch_instance = fetch.Fetch()
		if gal:
			if not isinstance(gal, list):
				galleries = [gal]
			else:
				galleries = gal
		else:
			if app_constants.CONTINUE_AUTO_METADATA_FETCHER:
				galleries = [g for g in self.manga_list_view.gallery_model._data if not g.exed]
			else:
				galleries = self.manga_list_view.gallery_model._data
			if not galleries:
				self.notification_bar.add_text('Looks like we\'ve already gone through all galleries!')
				return None
		fetch_instance.galleries = galleries

		self.notification_bar.begin_show()
		fetch_instance.moveToThread(thread)

		def done(status):
			self.notification_bar.end_show()
			fetch_instance.deleteLater()
			if not isinstance(status, bool):
				galleries = []
				for tup in status:
					galleries.append(tup[0])

				class GalleryContextMenu(QMenu):
					app_instance = self
					def __init__(self, parent=None):
						super().__init__(parent)
						show_in_library_act = self.addAction('Show in library')
						show_in_library_act.triggered.connect(self.show_in_library)

					def show_in_library(self):
						viewer = self.app_instance.manga_list_view
						index = viewer.find_index(self.gallery_widget.gallery.id, True)
						if index:
							self.app_instance.manga_table_view.scroll_to_index(index)
							self.app_instance.manga_list_view.scroll_to_index(index)

				g_popup = io_misc.GalleryPopup(('Fecthing metadata for these galleries failed.'+
									  ' Check happypanda.log for details.', galleries), self, menu=GalleryContextMenu())
				#errors = {g[0].id: g[1] for g in status}
				#for g_item in g_popup.get_all_items():
				#	g_item.setToolTip(errors[g_item.gallery.id])
				g_popup.graphics_blur.setEnabled(False)
				close_button = g_popup.add_buttons('Close')[0]
				close_button.clicked.connect(g_popup.close)

		fetch_instance.GALLERY_PICKER.connect(self._web_metadata_picker)
		fetch_instance.GALLERY_EMITTER.connect(self.manga_list_view.replace_edit_gallery)
		fetch_instance.AUTO_METADATA_PROGRESS.connect(self.notification_bar.add_text)
		thread.started.connect(fetch_instance.auto_web_metadata)
		fetch_instance.FINISHED.connect(done)
		fetch_instance.FINISHED.connect(metadata_spinner.close)
		fetch_instance.FINISHED.connect(lambda: self.move_listener.disconnect(move_md_spinner))
		thread.finished.connect(thread.deleteLater)
		thread.start()
		metadata_spinner.show()

	def init_stat_bar(self):
		self.status_bar = self.statusBar()
		self.status_bar.setMaximumHeight(20)
		self.status_bar.setSizeGripEnabled(False)
		self.stat_info = QLabel()
		self.stat_info.setIndent(5)
		self.sort_main = QAction("Asc", self)
		sort_menu = QMenu()
		self.sort_main.setMenu(sort_menu)
		s_by_title = QAction("Title", sort_menu)
		s_by_artist = QAction("Artist", sort_menu)
		sort_menu.addAction(s_by_title)
		sort_menu.addAction(s_by_artist)
		self.status_bar.addPermanentWidget(self.stat_info)
		#self.status_bar.addAction(self.sort_main)
		self.temp_msg = QLabel()
		self.temp_timer = QTimer()

		self.manga_list_view.gallery_model.ROWCOUNT_CHANGE.connect(self.stat_row_info)
		self.manga_list_view.gallery_model.db_emitter.COUNT_CHANGE.connect(self.stat_row_info)
		self.manga_list_view.gallery_model.STATUSBAR_MSG.connect(self.stat_temp_msg)
		self.manga_list_view.STATUS_BAR_MSG.connect(self.stat_temp_msg)
		self.manga_table_view.STATUS_BAR_MSG.connect(self.stat_temp_msg)
		self.stat_row_info()
		app_constants.STAT_MSG_METHOD = self.stat_temp_msg

	def stat_temp_msg(self, msg):
		self.temp_timer.stop()
		self.temp_msg.setText(msg)
		self.status_bar.addWidget(self.temp_msg)
		self.temp_timer.timeout.connect(self.temp_msg.clear)
		self.temp_timer.setSingleShot(True)
		self.temp_timer.start(5000)

	def stat_row_info(self):
		r = self.manga_list_view.model().rowCount()
		t = self.manga_list_view.gallery_model.db_emitter.count
		self.stat_info.setText("Loaded {} of {} ".format(r, t))

	def manga_display(self):
		"initiates the manga view and related things"
		#list view
		self.manga_list_view = gallery.MangaView(self)

		#table view

		self.manga_table_view = gallery.MangaTableView(self)
		self.manga_table_view.gallery_model = self.manga_list_view.gallery_model
		self.manga_table_view.sort_model = self.manga_list_view.sort_model
		self.manga_table_view.setModel(self.manga_table_view.sort_model)
		self.manga_table_view.sort_model.change_model(self.manga_table_view.gallery_model)
		self.manga_table_view.setColumnWidth(app_constants.FAV, 20)
		self.manga_table_view.setColumnWidth(app_constants.ARTIST, 200)
		self.manga_table_view.setColumnWidth(app_constants.TITLE, 400)
		self.manga_table_view.setColumnWidth(app_constants.TAGS, 300)
		self.manga_table_view.setColumnWidth(app_constants.TYPE, 60)
		self.manga_table_view.setColumnWidth(app_constants.CHAPTERS, 60)
		self.manga_table_view.setColumnWidth(app_constants.LANGUAGE, 100)
		self.manga_table_view.setColumnWidth(app_constants.LINK, 400)


	def init_spinners(self):
		# fetching spinner
		self.data_fetch_spinner = misc.Spinner(self)
		self.data_fetch_spinner.set_size(60)
		self.move_listener.connect(
			lambda: self.data_fetch_spinner.update_move(
				QPoint(self.pos().x()+self.width()//2, self.pos().y()+self.height()//2)))
		
		self.manga_list_view.gallery_model.ADD_MORE.connect(self.data_fetch_spinner.show)
		self.manga_list_view.gallery_model.db_emitter.START.connect(self.data_fetch_spinner.show)
		self.manga_list_view.gallery_model.ADDED_ROWS.connect(self.data_fetch_spinner.before_hide)
		self.manga_list_view.gallery_model.db_emitter.CANNOT_FETCH_MORE.connect(self.data_fetch_spinner.before_hide)

		## deleting spinner
		#self.gallery_delete_spinner = misc.Spinner(self)
		#self.gallery_delete_spinner.set_size(40,40)
		##self.gallery_delete_spinner.set_text('Removing...')
		#self.manga_list_view.gallery_model.rowsAboutToBeRemoved.connect(self.gallery_delete_spinner.show)
		#self.manga_list_view.gallery_model.rowsRemoved.connect(self.gallery_delete_spinner.before_hide)


	def search(self, srch_string):
		self.search_bar.setText(srch_string)
		self.search_backward.setVisible(True)
		self.manga_list_view.sort_model.init_search(srch_string)
		old_cursor_pos = self._search_cursor_pos[0]
		self.search_bar.end(False)
		if self.search_bar.cursorPosition() != old_cursor_pos+1:
			self.search_bar.setCursorPosition(old_cursor_pos)


	def favourite_display(self):
		"Switches to favourite display"
		self.manga_table_view.sort_model.fav_view()
		self.favourite_btn.selected = True
		self.library_btn.selected = False

	def catalog_display(self):
		"Switches to catalog display"
		self.manga_table_view.sort_model.catalog_view()
		self.library_btn.selected = True
		self.favourite_btn.selected = False

	def settings(self):
		sett = settingsdialog.SettingsDialog(self)
		sett.scroll_speed_changed.connect(self.manga_list_view.updateGeometries)
		#sett.show()

	def init_toolbar(self):
		self.toolbar = QToolBar()
		self.toolbar.setFixedHeight(25)
		self.toolbar.setWindowTitle("Show") # text for the contextmenu
		#self.toolbar.setStyleSheet("QToolBar {border:0px}") # make it user defined?
		self.toolbar.setMovable(False)
		self.toolbar.setFloatable(False)
		#self.toolbar.setIconSize(QSize(20,20))
		self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		self.toolbar.setIconSize(QSize(20,20))

		spacer_start = QWidget() # aligns the first actions properly
		spacer_start.setFixedSize(QSize(10, 1))
		self.toolbar.addWidget(spacer_start)

		self.favourite_btn = misc.ToolbarButton(self.toolbar, 'Favorites')
		self.toolbar.addWidget(self.favourite_btn)
		self.favourite_btn.clicked.connect(self.favourite_display) #need lambda to pass extra args

		self.library_btn = misc.ToolbarButton(self.toolbar, 'Library')
		self.toolbar.addWidget(self.library_btn)
		self.library_btn.clicked.connect(self.catalog_display) #need lambda to pass extra args
		self.library_btn.selected = True

		self.toolbar.addSeparator()

		gallery_menu = QMenu()
		gallery_action = QToolButton()
		gallery_action.setText('Gallery ')
		gallery_action.setPopupMode(QToolButton.InstantPopup)
		gallery_action.setToolTip('Contains various gallery related features')
		gallery_action.setMenu(gallery_menu)
		add_gallery_icon = QIcon(app_constants.PLUS_PATH)
		gallery_action_add = QAction(add_gallery_icon, "Add single gallery...", self)
		gallery_action_add.triggered.connect(self.manga_list_view.SERIES_DIALOG.emit)
		gallery_action_add.setToolTip('Add a single gallery thoroughly')
		gallery_menu.addAction(gallery_action_add)
		add_more_action = QAction(add_gallery_icon, "Add galleries...", self)
		add_more_action.setStatusTip('Add galleries from different folders')
		add_more_action.triggered.connect(lambda: self.populate(True))
		gallery_menu.addAction(add_more_action)
		populate_action = QAction(add_gallery_icon, "Populate from directory/archive...", self)
		populate_action.setStatusTip('Populates the DB with galleries from a single folder or archive')
		populate_action.triggered.connect(self.populate)
		gallery_menu.addAction(populate_action)
		gallery_menu.addSeparator()
		metadata_action = QAction('Get metadata for all galleries', self)
		metadata_action.triggered.connect(self.get_metadata)
		gallery_menu.addAction(metadata_action)
		scan_galleries_action = QAction('Scan for new galleries', self)
		scan_galleries_action.triggered.connect(self.scan_for_new_galleries)
		scan_galleries_action.setStatusTip('Scan monitored folders for new galleries')
		gallery_menu.addAction(scan_galleries_action)
		gallery_action_random = gallery_menu.addAction("Open random gallery")
		gallery_action_random.triggered.connect(self.manga_list_view.open_random_gallery)
		self.toolbar.addWidget(gallery_action)


		misc_action = QToolButton()
		misc_action.setText('Tools ')
		misc_action_menu = QMenu()
		misc_action.setMenu(misc_action_menu)
		misc_action.setPopupMode(QToolButton.InstantPopup)
		misc_action.setToolTip("Contains misc. features")
		gallery_downloader = QAction("Gallery Downloader", misc_action_menu)
		gallery_downloader.triggered.connect(self.download_window.show)
		misc_action_menu.addAction(gallery_downloader)
		duplicate_check_simple = QAction("Simple Duplicate Finder", misc_action_menu)
		duplicate_check_simple.triggered.connect(lambda: self.manga_list_view.duplicate_check())
		misc_action_menu.addAction(duplicate_check_simple)
		self.toolbar.addWidget(misc_action)

		spacer_middle = QWidget() # aligns buttons to the right
		spacer_middle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
		self.toolbar.addWidget(spacer_middle)


		sort_action = QToolButton()
		sort_action.setIcon(QIcon(app_constants.SORT_PATH))
		sort_action.setMenu(misc.SortMenu(self.toolbar, self.manga_list_view))
		sort_action.setPopupMode(QToolButton.InstantPopup)
		self.toolbar.addWidget(sort_action)
		
		self.grid_toggle_g_icon = QIcon(app_constants.GRID_PATH)
		self.grid_toggle_l_icon = QIcon(app_constants.LIST_PATH)
		self.grid_toggle = QToolButton()
		if self.display.currentIndex() == self.m_l_view_index:
			self.grid_toggle.setIcon(self.grid_toggle_l_icon)
		else:
			self.grid_toggle.setIcon(self.grid_toggle_g_icon)
		self.grid_toggle.setObjectName('gridtoggle')
		self.grid_toggle.clicked.connect(self.toggle_view)
		self.toolbar.addWidget(self.grid_toggle)

		spacer_mid2 = QWidget()
		spacer_mid2.setFixedSize(QSize(5, 1))
		self.toolbar.addWidget(spacer_mid2)

		def set_search_case(b):
			app_constants.GALLERY_SEARCH_CASE = b
			settings.set(b, 'Application', 'gallery search case')
			settings.save()

		def set_search_strict(b):
			app_constants.GALLERY_SEARCH_STRICT = b
			settings.set(b, 'Application', 'gallery search strict')
			settings.save()

		self.search_bar = misc.LineEdit()
		search_options = self.search_bar.addAction(QIcon(app_constants.SEARCH_OPTIONS_PATH), QLineEdit.TrailingPosition)
		search_options_menu = QMenu(self)
		search_options.triggered.connect(lambda: search_options_menu.popup(QCursor.pos()))
		search_options.setMenu(search_options_menu)
		case_search_option = search_options_menu.addAction('Case Sensitive')
		case_search_option.setCheckable(True)
		case_search_option.setChecked(app_constants.GALLERY_SEARCH_CASE)
		case_search_option.toggled.connect(set_search_case)
		strict_search_option = search_options_menu.addAction('Match whole terms')
		strict_search_option.setCheckable(True)
		strict_search_option.setChecked(app_constants.GALLERY_SEARCH_STRICT)
		strict_search_option.toggled.connect(set_search_strict)
		self.search_bar.setObjectName('search_bar')
		self.search_timer = QTimer(self)
		self.search_timer.setSingleShot(True)
		self.search_timer.timeout.connect(lambda: self.search(self.search_bar.text()))
		self._search_cursor_pos = [0, 0]
		def set_cursor_pos(old, new):
			self._search_cursor_pos[0] = old
			self._search_cursor_pos[1] = new
		self.search_bar.cursorPositionChanged.connect(set_cursor_pos)

		if app_constants.SEARCH_AUTOCOMPLETE:
			completer = QCompleter(self)
			completer_view = misc.CompleterPopupView()
			completer.setPopup(completer_view)
			completer_view._setup()
			completer.setModel(self.manga_list_view.gallery_model)
			completer.setCaseSensitivity(Qt.CaseInsensitive)
			completer.setCompletionMode(QCompleter.PopupCompletion)
			completer.setCompletionRole(Qt.DisplayRole)
			completer.setCompletionColumn(app_constants.TITLE)
			completer.setFilterMode(Qt.MatchContains)
			self.search_bar.setCompleter(completer)
			self.search_bar.returnPressed.connect(lambda: self.search(self.search_bar.text()))
		if not app_constants.SEARCH_ON_ENTER:
			self.search_bar.textEdited.connect(lambda: self.search_timer.start(800))
		self.search_bar.setPlaceholderText("Search title, artist, namespace & tags")
		self.search_bar.setMinimumWidth(150)
		self.search_bar.setMaximumWidth(500)
		self.search_bar.setFixedHeight(19)
		self.manga_list_view.sort_model.HISTORY_SEARCH_TERM.connect(lambda a: self.search_bar.setText(a))
		self.toolbar.addWidget(self.search_bar)

		def search_history(_, back=True): # clicked signal passes a bool
			sort_model =  self.manga_list_view.sort_model
			nav = sort_model.PREV if back else sort_model.NEXT
			history_term = sort_model.navigate_history(nav)
			if back:
				self.search_forward.setVisible(True)

		back = QShortcut(QKeySequence(QKeySequence.Back), self, lambda: search_history(None))
		forward = QShortcut(QKeySequence(QKeySequence.Forward), self, lambda: search_history(None, False))

		search_backbutton = QToolButton(self.toolbar)
		search_backbutton.setText(u'\u25C0')
		search_backbutton.setFixedWidth(15)
		search_backbutton.clicked.connect(search_history)
		self.search_backward = self.toolbar.addWidget(search_backbutton)
		self.search_backward.setVisible(False)
		search_forwardbutton = QToolButton(self.toolbar)
		search_forwardbutton.setText(u'\u25B6')
		search_forwardbutton.setFixedWidth(15)
		search_forwardbutton.clicked.connect(lambda: search_history(None, False))
		self.search_forward = self.toolbar.addWidget(search_forwardbutton)
		self.search_forward.setVisible(False)

		spacer_end = QWidget() # aligns settings action properly
		spacer_end.setFixedSize(QSize(10, 1))
		self.toolbar.addWidget(spacer_end)

		settings_act = QToolButton(self.toolbar)
		settings_act.setIcon(QIcon(app_constants.SETTINGS_PATH))
		settings_act.clicked.connect(self.settings)
		self.toolbar.addWidget(settings_act)

		spacer_end2 = QWidget() # aligns About action properly
		spacer_end2.setFixedSize(QSize(5, 1))
		self.toolbar.addWidget(spacer_end2)
		self.addToolBar(self.toolbar)

	def toggle_view(self):
		"""
		Toggles the current display view
		"""
		if self.display.currentIndex() == self.m_l_view_index:
			self.display.setCurrentIndex(self.m_t_view_index)
			self.grid_toggle.setIcon(self.grid_toggle_g_icon)
		else:
			self.display.setCurrentIndex(self.m_l_view_index)
			self.grid_toggle.setIcon(self.grid_toggle_l_icon)

	# TODO: Improve this so that it adds to the gallery dialog,
	# so user can edit data before inserting (make it a choice)
	def populate(self, mixed=None):
		"Populates the database with gallery from local drive'"
		if mixed:
			gallery_view = misc.GalleryListView(self, True)
			gallery_view.SERIES.connect(self.gallery_populate)
			gallery_view.show()
		else:
			msg_box = misc.BasePopup(self)
			l = QVBoxLayout()
			msg_box.main_widget.setLayout(l)
			l.addWidget(QLabel('Directory or Archive?'))
			l.addLayout(msg_box.buttons_layout)

			def from_dir():
				path = QFileDialog.getExistingDirectory(self, "Choose a directory containing your galleries")
				if not path:
					return
				msg_box.close()
				app_constants.OVERRIDE_SUBFOLDER_AS_GALLERY = True
				self.gallery_populate(path, True)
			def from_arch():
				path = QFileDialog.getOpenFileName(self, 'Choose an archive containing your galleries',
									   filter=utils.FILE_FILTER)
				path = [path[0]]
				if not all(path) or not path:
					return
				msg_box.close()
				app_constants.OVERRIDE_SUBFOLDER_AS_GALLERY = True
				self.gallery_populate(path, True)

			buttons = msg_box.add_buttons('Directory', 'Archive', 'Close')
			buttons[2].clicked.connect(msg_box.close)
			buttons[0].clicked.connect(from_dir)
			buttons[1].clicked.connect(from_arch)
			msg_box.adjustSize()
			msg_box.show()

	def gallery_populate(self, path, validate=False):
		"Scans the given path for gallery to add into the DB"
		if len(path) is not 0:
			data_thread = QThread(self)
			data_thread.setObjectName('General gallery populate')
			loading = misc.Loading(self)
			self.g_populate_inst = fetch.Fetch()
			self.g_populate_inst.series_path = path
			loading.show()

			def finished(status):
				def hide_loading():
					loading.hide()
				if status:
					if len(status) != 0:
						def add_gallery(gallery_list):
							def append_to_model(x):
								self.manga_list_view.sort_model.insertRows(x, None, len(x))
								self.manga_list_view.sort_model.init_search(
									self.manga_list_view.sort_model.current_term)

							class A(QObject):
								done = pyqtSignal()
								prog = pyqtSignal(int)
								def __init__(self, obj, parent=None):
									super().__init__(parent)
									self.obj = obj
									self.galleries = []

								def add_to_db(self):
									for y, x in enumerate(self.obj):
										gallerydb.add_method_queue(
											gallerydb.GalleryDB.add_gallery_return, False, x)
										self.galleries.append(x)
										y += 1
										self.prog.emit(y)
									append_to_model(self.galleries)
									self.done.emit()
							loading.progress.setMaximum(len(gallery_list))
							self.a_instance = A(gallery_list)
							thread = QThread(self)
							thread.setObjectName('Database populate')
							def loading_show(numb):
								if loading.isHidden():
									loading.show()
								loading.setText('Populating database ({}/{})\nPlease wait...'.format(
									numb, loading.progress.maximum()))
								loading.progress.setValue(numb)
								loading.show()

							def loading_hide():
								loading.close()
								self.manga_list_view.gallery_model.ROWCOUNT_CHANGE.emit()

							self.a_instance.moveToThread(thread)
							self.a_instance.prog.connect(loading_show)
							thread.started.connect(self.a_instance.add_to_db)
							self.a_instance.done.connect(loading_hide)
							self.a_instance.done.connect(self.a_instance.deleteLater)
							#a_instance.add_to_db()
							thread.finished.connect(thread.deleteLater)
							thread.start()
						#data_thread.quit
						hide_loading()
						log_i('Populating DB from gallery folder: OK')
						if validate:
							gallery_list = misc.GalleryListView(self)
							gallery_list.SERIES.connect(add_gallery)
							for ser in status:
								if ser.is_archive and app_constants.SUBFOLDER_AS_GALLERY:
									p = os.path.split(ser.path)[1]
									if ser.chapters[0].path:
										pt_in_arch = os.path.split(ser.path_in_archive)
										pt_in_arch = pt_in_arch[1] or pt_in_arch[0]
										text = '{}: {}'.format(p, pt_in_arch)
									else:
										text = p
									gallery_list.add_gallery(ser, text)
								else:
									gallery_list.add_gallery(ser, os.path.split(ser.path)[1])
							#self.manga_list_view.gallery_model.populate_data()
							gallery_list.update_count()
							gallery_list.show()
						else:
							add_gallery(status)
					else:
						log_d('No new gallery was found')
						loading.setText("No new gallery found")
						#data_thread.quit

				else:
					log_e('Populating DB from gallery folder: Nothing was added!')
					loading.setText("<font color=red>Nothing was added. Check happypanda_log for details..</font>")
					loading.progress.setStyleSheet("background-color:red;")
					data_thread.quit
					QTimer.singleShot(8000, loading.close)

			def skipped_gs(s_list):
				"Skipped galleries"
				msg_box = QMessageBox(self)
				msg_box.setIcon(QMessageBox.Question)
				msg_box.setText('Do you want to view skipped paths?')
				msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
				msg_box.setDefaultButton(QMessageBox.No)
				if msg_box.exec() == QMessageBox.Yes:
					list_wid = QTableWidget(self)
					list_wid.setAttribute(Qt.WA_DeleteOnClose)
					list_wid.setRowCount(len(s_list))
					list_wid.setColumnCount(2)
					list_wid.setAlternatingRowColors(True)
					list_wid.setEditTriggers(list_wid.NoEditTriggers)
					list_wid.setHorizontalHeaderLabels(['Reason', 'Path'])
					list_wid.setSelectionBehavior(list_wid.SelectRows)
					list_wid.setSelectionMode(list_wid.SingleSelection)
					list_wid.setSortingEnabled(True)
					list_wid.verticalHeader().hide()
					list_wid.setAutoScroll(False)
					for x, g in enumerate(s_list):
						list_wid.setItem(x, 0, QTableWidgetItem(g[1]))
						list_wid.setItem(x, 1, QTableWidgetItem(g[0]))
					list_wid.resizeColumnsToContents()
					list_wid.setWindowTitle('{} skipped paths'.format(len(s_list)))
					list_wid.setWindowFlags(Qt.Window)
					list_wid.resize(900,400)

					list_wid.doubleClicked.connect(lambda i: utils.open_path(
						list_wid.item(i.row(), 1).text(), list_wid.item(i.row(), 1).text()))

					list_wid.show()

			def a_progress(prog):
				loading.progress.setValue(prog)
				loading.setText("Preparing galleries...")

			self.g_populate_inst.moveToThread(data_thread)
			self.g_populate_inst.DATA_COUNT.connect(loading.progress.setMaximum)
			self.g_populate_inst.PROGRESS.connect(a_progress)
			self.g_populate_inst.FINISHED.connect(finished)
			self.g_populate_inst.FINISHED.connect(self.g_populate_inst.deleteLater)
			self.g_populate_inst.SKIPPED.connect(skipped_gs)
			data_thread.finished.connect(data_thread.deleteLater)
			data_thread.started.connect(self.g_populate_inst.local)
			data_thread.start()
			#.g_populate_inst.local()
			log_i('Populating DB from directory/archive')

	def scan_for_new_galleries(self):
		available_folders =  app_constants.ENABLE_MONITOR and\
									app_constants.MONITOR_PATHS and all(app_constants.MONITOR_PATHS)
		if available_folders and not app_constants.SCANNING_FOR_GALLERIES:
			app_constants.SCANNING_FOR_GALLERIES = True
			self.notification_bar.add_text("Scanning for new galleries...")
			log_i('Scanning for new galleries...')
			try:
				class ScanDir(QObject):
					final_paths_and_galleries = pyqtSignal(list, list)
					finished = pyqtSignal()
					def __init__(self, parent=None):
						super().__init__(parent)
						self.scanned_data = []
					def scan_dirs(self):
						paths = []
						for p in app_constants.MONITOR_PATHS:
							if os.path.exists(p):
								dir_content = scandir.scandir(p)
								for d in dir_content:
									paths.append(d.path)
							else:
								log_e("Monitored path does not exists: {}".format(p.encode(errors='ignore')))

						fetch_inst = fetch.Fetch(self)
						fetch_inst.series_path = paths
						def set_scanned_d(d):
							self.scanned_data = d
						fetch_inst.FINISHED.connect(set_scanned_d)
						fetch_inst.local()
						#contents = []
						#for g in self.scanned_data:
						#	contents.append(g)

						#paths = sorted(paths)
						#new_galleries = []
						#for x in contents:
						#	y = utils.b_search(paths, os.path.normcase(x.path))
						#	if not y:
						#		new_galleries.append(x)

						galleries = []
						final_paths = []
						if self.scanned_data:
							for g in self.scanned_data:
								try:
									if g.is_archive:
										g.profile = utils.get_gallery_img(g.chapters[0].path, g.path)
									else:
										g.profile = utils.get_gallery_img(g.chapters[0].path)
									if not g.profile:
										raise Exception
								except:
									g.profile = app_constants.NO_IMAGE_PATH
							
								galleries.append(g)
								final_paths.append(g.path)
						self.final_paths_and_galleries.emit(final_paths, galleries)
						self.finished.emit()
						self.deleteLater()
					#if app_constants.LOOK_NEW_GALLERY_AUTOADD:
					#	QTimer.singleShot(10000, self.gallery_populate(final_paths))
					#	return

				def show_new_galleries(final_paths, galleries):
					if final_paths and galleries:
						app_constants.OVERRIDE_MOVE_IMPORTED_IN_FETCH = True
						if app_constants.LOOK_NEW_GALLERY_AUTOADD:
							self.gallery_populate(final_paths)
						else:

							class NewGalleryMenu(QMenu):

								def __init__(self, parent=None):
									super().__init__(parent)

									ignore_act = self.addAction('Add to ignore list')
									ignore_act.triggered.connect(self.add_to_ignore)

								def add_to_ignore(self):
									gallery = self.gallery_widget.gallery
									app_constants.IGNORE_PATHS.append(gallery.path)
									settings.set(app_constants.IGNORE_PATHS, 'Application', 'ignore paths')
									if self.gallery_widget.parent_widget.gallery_layout.count() == 1:
										self.gallery_widget.parent_widget.close()
									else:
										self.gallery_widget.close()

							if len(galleries) == 1:
								self.notification_bar.add_text("{} new gallery was discovered in one of your monitored directories".format(len(galleries)))
							else:
								self.notification_bar.add_text("{} new galleries were discovered in one of your monitored directories".format(len(galleries)))
							text = "These new galleries were discovered! Do you want to add them?"\
								if len(galleries) > 1 else "This new gallery was discovered! Do you want to add it?"
							g_popup = io_misc.GalleryPopup((text, galleries), self, NewGalleryMenu())
							buttons = g_popup.add_buttons('Add', 'Close')

							def populate_n_close():
								g_popup.close()
								self.gallery_populate(final_paths)
							buttons[0].clicked.connect(populate_n_close)
							buttons[1].clicked.connect(g_popup.close)

				def finished(): app_constants.SCANNING_FOR_GALLERIES = False

				thread = QThread(self)
				self.scan_inst = ScanDir()
				self.scan_inst.moveToThread(thread)
				self.scan_inst.final_paths_and_galleries.connect(show_new_galleries)
				self.scan_inst.finished.connect(finished)
				thread.started.connect(self.scan_inst.scan_dirs)
				#self.scan_inst.scan_dirs()
				thread.finished.connect(thread.deleteLater)
				thread.start()
			except:
				self.notification_bar.add_text('An error occured while attempting to scan for new galleries. Check happypanda.log.')
				log.exception('An error occured while attempting to scan for new galleries.')
				app_constants.SCANNING_FOR_GALLERIES = False

	def dragEnterEvent(self, event):
		if event.mimeData().hasUrls():
			event.acceptProposedAction()
		else:
			self.notification_bar.add_text('File is not supported')

	def dropEvent(self, event):
		acceptable = []
		unaccept = []
		for u in event.mimeData().urls():
			path = u.toLocalFile()
			if os.path.isdir(path) or path.endswith(utils.ARCHIVE_FILES):
				acceptable.append(path)
			else:
				unaccept.append(path)
		log_i('Acceptable dropped items: {}'.format(len(acceptable)))
		log_i('Unacceptable dropped items: {}'.format(len(unaccept)))
		log_d('Dropped items: {}\n{}'.format(acceptable, unaccept).encode(errors='ignore'))
		if acceptable:
			self.notification_bar.add_text('Adding dropped items...')
			log_i('Adding dropped items')
			l = len(acceptable) == 1
			f_item = acceptable[0]
			if f_item.endswith(utils.ARCHIVE_FILES):
				f_item = utils.check_archive(f_item)
			else:
				f_item = utils.recursive_gallery_check(f_item)
			f_item_l = len(f_item) < 2
			subfolder_as_c = not app_constants.SUBFOLDER_AS_GALLERY
			if l and subfolder_as_c or l and f_item_l:
				g_d = gallerydialog.GalleryDialog(self, acceptable[0])
				g_d.SERIES.connect(self.manga_list_view.gallery_model.addRows)
				g_d.show()
			else:
				self.gallery_populate(acceptable, True)
		else:
			text = 'File not supported' if len(unaccept) < 2 else 'Files not supported'
			self.notification_bar.add_text(text)

		if unaccept:
			self.notification_bar.add_text('Some unsupported files did not get added')

	def resizeEvent(self, event):
		try:
			self.notification_bar.resize(event.size().width())
		except AttributeError:
			pass
		self.move_listener.emit()
		return super().resizeEvent(event)

	def moveEvent(self, event):
		self.move_listener.emit()
		return super().moveEvent(event)

	def showEvent(self, event):
		return super().showEvent(event)

	def cleanup_exit(self):
		self.system_tray.hide()
		# watchers
		try:
			self.watchers.stop_all()
		except AttributeError:
			pass

		# settings
		settings.set(self.manga_list_view.current_sort, 'General', 'current sort')
		settings.set(app_constants.IGNORE_PATHS, 'Application', 'ignore paths')
		settings.win_save(self, 'AppWindow')

		# temp dir
		try:
			for root, dirs, files in scandir.walk('temp', topdown=False):
				for name in files:
					os.remove(os.path.join(root, name))
				for name in dirs:
					os.rmdir(os.path.join(root, name))
			log_d('Flush temp on exit: OK')
		except:
			log.exception('Flush temp on exit: FAIL')

		if self.tags_treeview:
			self.tags_treeview.close()
		self.download_window.close()

		# check if there is db activity
		if not gallerydb.method_queue.empty():
			class DBActivityChecker(QObject):
				FINISHED = pyqtSignal()
				def __init__(self, **kwargs):
					super().__init__(**kwargs)

				def check(self):
					gallerydb.method_queue.join()
					self.FINISHED.emit()
					self.deleteLater()

			db_activity = DBActivityChecker()
			db_spinner = misc.Spinner(self)
			self.db_activity_checker.connect(db_activity.check)
			db_activity.moveToThread(app_constants.GENERAL_THREAD)
			db_activity.FINISHED.connect(db_spinner.close)
			db_spinner.set_size(50)
			db_spinner.set_text('Activity')
			db_spinner.move(QPoint(self.pos().x()+self.width()-70, self.pos().y()+self.height()-70))
			self.move_listener.connect(lambda: db_spinner.update_move(QPoint(self.pos().x()+self.width()-70,
																	self.pos().y()+self.height()-70)))
			db_spinner.show()
			self.db_activity_checker.emit()
			msg_box = QMessageBox(self)
			msg_box.setText('Database activity detected!')
			msg_box.setInformativeText("Closing now might result in data loss." +
								 " Do you still want to close?\n(Wait for the activity spinner to hide before closing)")
			msg_box.setIcon(QMessageBox.Critical)
			msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
			msg_box.setDefaultButton(QMessageBox.No)
			if msg_box.exec() == QMessageBox.Yes:
				return 1
			else:
				return 2
		else:
			return 0

	def closeEvent(self, event):
		r_code = self.cleanup_exit()
		if r_code == 1:
			log_d('Force Exit App: OK')
			super().closeEvent(event)
		elif r_code == 2:
			log_d('Ignore Exit App')
			event.ignore()
		else:
			log_d('Normal Exit App: OK')
			super().closeEvent(event)
Пример #19
0
class InsertRecord(QWidget):
    """Main widget for inserting new records in the database

    This class creates a stacked layout containing four insert form widgets
    (Books, Authors, Publishers, Series) selected with a drop down menu.
    It implements the function to insert the record in the database.
    """
    def __init__(self, *args, **kwargs):
        super(InsertRecord, self).__init__(*args, **kwargs)

        # Define main layout
        layout = QVBoxLayout()

        # Create menu with the database tables
        menu = QComboBox()
        menu.addItem('Books')
        menu.addItem('Authors')
        menu.addItem('Publishers')
        menu.addItem('Series')
        menu.currentIndexChanged[str].connect(self.change_table)

        layout.addWidget(menu)

        # Define stacked layout for the different tables in database
        self.layout_insert = QStackedLayout()

        # Create insert form for each table in database
        self.book_insert = InsertBookForm()
        self.author_insert = InsertAuthorForm()
        self.publisher_insert = InsertPublisherForm()
        self.series_insert = InsertSeriesForm()

        # Add search forms to layout
        self.layout_insert.addWidget(self.book_insert)
        self.layout_insert.addWidget(self.author_insert)
        self.layout_insert.addWidget(self.publisher_insert)
        self.layout_insert.addWidget(self.series_insert)

        layout.addLayout(self.layout_insert)

        # Define layout for buttons
        layout_button = QHBoxLayout()
        # Create buttons
        insert_button = QPushButton('Insert')
        clear_button = QPushButton('Clear')
        insert_button.setMinimumSize(400, 30)
        insert_button.setMaximumSize(500, 30)
        clear_button.setMinimumSize(400, 30)
        clear_button.setMaximumSize(500, 30)

        # Define buttons behavior
        insert_button.clicked.connect(self.insert_record)
        clear_button.clicked.connect(self.clear)

        # Add buttons to layout
        layout_button.addWidget(insert_button)
        layout_button.addWidget(clear_button)
        layout_button.addWidget(QWidget())
        layout_button.addWidget(QWidget())
        layout_button.setAlignment(insert_button, Qt.AlignLeft)
        layout_button.setAlignment(clear_button, Qt.AlignLeft)
        layout.addLayout(layout_button)

        # Set main layout
        self.setLayout(layout)

    # Function to clear all insert fields
    def clear(self):
        """Clear the text in the insert form."""

        self.book_insert.isbn.clear()
        self.book_insert.title.clear()
        self.book_insert.author.clear()
        self.book_insert.otherauthors.clear()
        self.book_insert.publisher.clear()
        self.book_insert.series.clear()
        self.book_insert.subseries.clear()
        self.book_insert.category.clear()
        self.book_insert.language.clear()
        self.book_insert.year.clear()
        self.book_insert.pages.clear()
        self.book_insert.owner.setCurrentIndex(0)
        self.book_insert.booktype.setCurrentIndex(0)

        self.author_insert.name.clear()
        self.author_insert.gender.setCurrentIndex(0)
        self.author_insert.nationality.clear()
        self.author_insert.birthyear.clear()
        self.author_insert.deathyear.clear()

        self.publisher_insert.name.clear()

        self.series_insert.name.clear()
        self.series_insert.author.clear()

    # Function to set insert form according to database table selected
    def change_table(self, table_name):
        """Select the insert form (Books, Authors, Publishers or Series)."""

        # Clear all fields
        self.clear()

        # Books
        if table_name == 'Books':
            self.layout_insert.setCurrentIndex(0)
        # Authors
        elif table_name == 'Authors':
            self.layout_insert.setCurrentIndex(1)
        # Publishers
        elif table_name == 'Publishers':
            self.layout_insert.setCurrentIndex(2)
        # Series
        else:
            self.layout_insert.setCurrentIndex(3)

    # Function to insert record in database
    def insert_record(self):
        """Insert record in the database

        The method reads the informations in the active insert form
        (Books, Authors, Publishers or Series) and uses them to insert
        a new record in the database.
        """

        sql_query = QSqlQuery()

        if self.layout_insert.currentIndex() == 0:
            # Get text from insert form
            isbn = QVariant(self.book_insert.isbn.text())
            title = QVariant(self.book_insert.title.text())
            author = QVariant(self.book_insert.author.text())
            otherauthors = QVariant(self.book_insert.otherauthors.text())
            publisher = QVariant(self.book_insert.publisher.text())
            series = QVariant(self.book_insert.series.text())
            subseries = QVariant(self.book_insert.subseries.text())
            category = QVariant(self.book_insert.category.text())
            language = QVariant(self.book_insert.language.text())
            year = QVariant(self.book_insert.year.text())
            pages = QVariant(self.book_insert.pages.text())
            owner = QVariant(self.book_insert.owner.currentText())
            booktype = QVariant(self.book_insert.booktype.currentText())

            # Set values to None where strings are empty
            if isbn.value() == '':
                isbn = QVariant()
            else:
                isbn = isbn.value()
                # Check is the ISBN is valid
                if ISBN_CHECK:
                    if '-' in isbn:
                        isbn = canonical(isbn)
                    if len(isbn) == 10:
                        if not is_isbn10(isbn):
                            # Show an error if the ISBN is invalid
                            error = ErrorDialog(
                                'The ISBN inserted is invalid. Operation failed.'
                            )
                            error.show()

                            return
                    elif len(isbn) == 13:
                        if not is_isbn13(isbn):
                            # Show an error if the ISBN is invalid
                            error = ErrorDialog(
                                'The ISBN inserted is invalid. Operation failed.'
                            )
                            error.show()

                            return
                    else:
                        # Show an error if the ISBN is invalid
                        error = ErrorDialog(
                            'The ISBN inserted is invalid. Operation failed.')
                        error.show()

                        return

                    isbn = QVariant(isbn)
            if title.value() == '':
                title = QVariant()
            if author.value() == '':
                author = QVariant()
            if otherauthors.value() == '':
                otherauthors = QVariant()
            if publisher.value() == '':
                publisher = QVariant()
            if series.value() == '':
                series = QVariant()
            if subseries.value() == '':
                subseries = QVariant()
            if category.value() == '':
                category = QVariant()
            if language.value() == '':
                language = QVariant()
            if year.value() == '':
                year = QVariant()
            if pages.value() == '':
                pages = QVariant()
            if owner.value() == '':
                owner = QVariant()
            if booktype.value() == '':
                booktype = QVariant()

            # Get Author Id from Name
            if not author.isNull():
                value = author.value().replace("'", "\\'")
                sql_query.prepare(
                    f'SELECT Id FROM Authors WHERE Name LIKE \'%{value}%\'')

                if sql_query.exec_():
                    if sql_query.size() == 0:
                        # Author cannot be NULL, show error
                        error = ErrorDialog(
                            'Author not found. Operation failed')
                        error.show()

                        return

                    if sql_query.size() == 1:
                        sql_query.next()
                        author = sql_query.value(0)
                    else:
                        # Show warning if string matches multiple authors
                        warning = WarningDialog('String matches multiple authors. ' +\
                                'Using exact match')
                        warning.show()

                        # Get Author Id from Name using exact match
                        sql_query.prepare(
                            f'SELECT Id FROM Authors WHERE Name=\'{author.value()}\''
                        )

                        if sql_query.exec_():
                            if sql_query.size() == 0:
                                # Author cannot be NULL, show error
                                error = ErrorDialog(
                                    'Author not found. Operation failed')
                                error.show()

                                return

                            if sql_query.size() == 1:
                                sql_query.next()
                                author = sql_query.value(0)
                        else:
                            #Show error if query failed
                            error = ErrorDialog(
                                str(sql_query.lastError().databaseText()))
                            error.show()

                            return
                else:
                    #Show error if query failed
                    error = ErrorDialog(
                        str(sql_query.lastError().databaseText()))
                    error.show()

                    return

            # Get Publisher Id from Name
            if not publisher.isNull():
                value = publisher.value().replace("'", "\\'")
                sql_query.prepare('SELECT Id FROM Publishers WHERE ' +\
                        f'Name LIKE \'%{value}%\'')

                if sql_query.exec_():
                    if sql_query.size() == 0:
                        publisher = QVariant()
                        # Show warning if string doesn't match any Publisher
                        warning = WarningDialog(
                            'Publisher not found, set to \'NULL\'')
                        warning.show()
                    elif sql_query.size() == 1:
                        sql_query.next()
                        publisher = sql_query.value(0)
                    else:
                        # Show warning if string matches multiple publishers
                        warning = WarningDialog('String matches multiple publishers.' +\
                                'Using exact match')
                        warning.show()

                        # Get Publisher Id from Name using exact match
                        sql_query.prepare('SELECT Id FROM Publishers WHERE ' +\
                                f'Name=\'{publisher.value()}\'')

                        if sql_query.exec_():
                            if sql_query.size() == 0:
                                publisher = QVariant()
                                # Show warning if exact match is not found
                                warning = WarningDialog(
                                    'Publisher not found, set to \'NULL\'')
                                warning.show()
                            elif sql_query.size() == 1:
                                sql_query.next()
                                publisher = sql_query.value(0)
                        else:
                            #Show error if query failed
                            error = ErrorDialog(
                                str(sql_query.lastError().databaseText()))
                            error.show()

                            return
                else:
                    #Show error if query failed
                    error = ErrorDialog(
                        str(sql_query.lastError().databaseText()))
                    error.show()

                    return

            # Get Series Id from Name
            if not series.isNull():
                value = series.value().replace("'", "\\'")
                sql_query.prepare(
                    f'SELECT Id FROM Series WHERE Name LIKE \'%{value}%\'')

                if sql_query.exec_():
                    if sql_query.size() == 0:
                        series = QVariant()
                        # Show warning if string doesn't match any Series
                        warning = WarningDialog(
                            'Series not found, set to \'NULL\'')
                        warning.show()
                    elif sql_query.size() == 1:
                        sql_query.next()
                        series = sql_query.value(0)
                    else:
                        # Show warning is string matches multiple Series
                        warning = WarningDialog(
                            'String matches multiple series. Using exact match'
                        )
                        warning.show()

                        # Get Series Id from Name using exact match
                        sql_query.prepare(
                            f'SELECT Id FROM Series WHERE Name=\'{series.value()}\''
                        )

                        if sql_query.exec_():
                            if sql_query.size() == 0:
                                series = QVariant()
                                # Show warning if exact match is not found
                                warning = WarningDialog(
                                    'Series not found, set to \'NULL\'')
                                warning.show()
                            elif sql_query.size() == 1:
                                sql_query.next()
                                series = sql_query.value(0)
                        else:
                            #Show error if query failed
                            error = ErrorDialog(
                                str(sql_query.lastError().databaseText()))
                            error.show()

                            return
                else:
                    #Show error if query failed
                    error = ErrorDialog(
                        str(sql_query.lastError().databaseText()))
                    error.show()

                    return

            sql_query.prepare('INSERT INTO Books(ISBN, Title, Author, OtherAuthors, Publisher, ' +\
                    'Series, Subseries, Category, Language, Year, Pages, Owner, Type) ' +\
                    'Values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
            sql_query.bindValue(0, isbn)
            sql_query.bindValue(1, title)
            sql_query.bindValue(2, author)
            sql_query.bindValue(3, otherauthors)
            sql_query.bindValue(4, publisher)
            sql_query.bindValue(5, series)
            sql_query.bindValue(6, subseries)
            sql_query.bindValue(7, category)
            sql_query.bindValue(8, language)
            sql_query.bindValue(9, year)
            sql_query.bindValue(10, pages)
            sql_query.bindValue(11, owner)
            sql_query.bindValue(12, booktype)

            # Execute the query
            if sql_query.exec_():
                # Show message if insertion succeeded
                info = InfoDialog('Record inserted successfully into Books')
                info.show()
            else:
                # Create error message box
                error = ErrorDialog(str(sql_query.lastError().databaseText()))
                error.show()

        elif self.layout_insert.currentIndex() == 1:
            # Get text from insert form
            name = QVariant(self.author_insert.name.text())
            gender = QVariant(self.author_insert.gender.currentText())
            nationality = QVariant(self.author_insert.nationality.text())
            birthyear = QVariant(self.author_insert.birthyear.text())
            deathyear = QVariant(self.author_insert.deathyear.text())

            # Set values to None where strings are empty
            if name.value() == '':
                name = QVariant()
            if gender.value() == '':
                gender = QVariant()
            if nationality.value() == '':
                nationality = QVariant()
            if birthyear.value() == '':
                birthyear = QVariant()
            if deathyear.value() == '':
                deathyear = QVariant()

            sql_query.prepare('INSERT INTO Authors(' +\
                    'Name, Gender, Nationality, BirthYear, DeathYear) ' +\
                    'Values(?, ?, ?, ?, ?)')
            sql_query.bindValue(0, name)
            sql_query.bindValue(1, gender)
            sql_query.bindValue(2, nationality)
            sql_query.bindValue(3, birthyear)
            sql_query.bindValue(4, deathyear)

            # Execute the query
            if sql_query.exec_():
                # Show message if insertion succeeded
                info = InfoDialog('Record inserted successfully into Authors')
                info.show()
            else:
                # Create error message box
                error = ErrorDialog(str(sql_query.lastError().databaseText()))
                error.show()

        elif self.layout_insert.currentIndex() == 2:
            # Get text from insert form
            name = QVariant(self.publisher_insert.name.text())

            # Set value to None if string is empty
            if name.value() == '':
                name = QVariant()

            sql_query.prepare('INSERT INTO Publishers(Name) Values(?)')
            sql_query.bindValue(0, name)

            # Execute the query
            if sql_query.exec_():
                # Show message if insertion succeeded
                info = InfoDialog(
                    'Record inserted successfully into Publishers')
                info.show()
            else:
                # Create error message box
                error = ErrorDialog(str(sql_query.lastError().databaseText()))
                error.show()

        elif self.layout_insert.currentIndex() == 3:
            # Get text from insert form
            name = QVariant(self.series_insert.name.text())
            author = QVariant(self.series_insert.author.text())

            # Set values to None where strings are empty
            if name.value() == '':
                name = QVariant()

            if author.value() == '':
                author = QVariant()

            if not author.isNull():
                # Get Author Id from Name
                value = author.value().replace("'", "\\'")
                sql_query.prepare(
                    f'SELECT Id FROM Authors WHERE Name LIKE \'%{value}%\'')

                if sql_query.exec_():
                    if sql_query.size() == 0:
                        # Author cannot be NULL, show error
                        error = ErrorDialog(
                            'Author not found. Operation failed')
                        error.show()

                        return

                    if sql_query.size() == 1:
                        sql_query.next()
                        author = sql_query.value(0)
                    else:
                        # Show warning if string matches multiple authors
                        warning = WarningDialog('String matches multiple authors. ' +\
                                'Using exact match')
                        warning.show()

                        # Get Author Id from Name using exact match
                        sql_query.prepare(f'SELECT Id FROM Authors WHERE ' +\
                                'Name = \'{author.value()}\'')

                        if sql_query.exec_():
                            if sql_query.size() == 0:
                                # Author cannot be NULL, show error
                                error = ErrorDialog(
                                    'Author not found. Operation failed')
                                error.show()

                                return

                            if sql_query.size() == 1:
                                sql_query.next()
                                author = sql_query.value(0)
                        else:
                            #Show error if query failed
                            error = ErrorDialog(
                                str(sql_query.lastError().databaseText()))
                            error.show()
                else:
                    #Show error if query failed
                    error = ErrorDialog(
                        str(sql_query.lastError().databaseText()))
                    error.show()

            sql_query.prepare('INSERT INTO Series(Name, Author) Values(?, ?)')
            sql_query.bindValue(0, name)
            sql_query.bindValue(1, author)

            # Execute the query
            if sql_query.exec_():
                # Show message if insertion succeeded
                info = InfoDialog('Record inserted successfully into Series')
                info.show()
            else:
                # Create error message box
                error = ErrorDialog(str(sql_query.lastError().databaseText()))
                error.show()
Пример #20
0
class Game(QWidget):
    """
    Define the Window and all the elements that makes the
    graphic interface
    """
    def __init__(self, h, w):

        QWidget.__init__(self)
        self.h = h
        self.w = w
        self.initUI()

    def initUI(self):
        # Set the Window
        self.setWindowTitle("The Game")
        self.pal = self.palette()
        self.pal.setColor(self.backgroundRole(), Qt.white)
        self.setPalette(self.pal)
        self.autoFillBackground = True
        # Set the QStackeLayout, where we put all the layouts
        self.layouts = QStackedLayout()
        self.counter = 0  # Count the number of layout add
        self.setLayout(self.layouts)
        # Define a button
        self.start = basic_widgets.Button("startover")
        self.start.clicked.connect(self.display_grid)
        # The table_layouts is usefull for the choice of layout to print
        self.table_layouts = []
        # Set the first layout : the rules
        self.rules = rules.Show_rules()
        self.table_layouts.append(self.rules)
        self.layouts.addWidget(self.rules)
        self.counter += 1
        self.rules.next.clicked.connect(self.layout_up)
        # Set the second layout : the choice of the map
        self.map_chosen = choose_map.Choose_map()
        self.table_layouts.append(self.map_chosen)
        self.layouts.addWidget(self.map_chosen)
        self.counter += 1
        # Set the third layout : the choice of the number of players
        self.player_chosen = choose_player.Choose_player()
        self.table_layouts.append(self.player_chosen)
        self.layouts.addWidget(self.player_chosen)
        self.counter += 1
        # Set the buttons for the selection of the map
        self.map_chosen.button[0].clicked.connect(self.map_choice_1)
        self.map_chosen.button[1].clicked.connect(self.map_choice_2)
        self.map_chosen.button[2].clicked.connect(self.map_choice_3)
        self.map_chosen.button[3].clicked.connect(self.map_choice_4)
        self.map_chosen.back.clicked.connect(self.go_back)
        # Set the buttons for the selection of the players
        self.player_chosen.button[0].clicked.connect(self.player_choice_1)
        self.player_chosen.button[1].clicked.connect(self.player_choice_2)
        self.player_chosen.button[2].clicked.connect(self.player_choice_3)
        self.player_chosen.button[3].clicked.connect(self.player_choice_4)

        self.player_chosen.back.clicked.connect(self.go_back)
        # We chose the size (w, h) for our Window
        self.resize(self.w, self.h)

    def go_back(self):
        """
        Go back into the Layouts
        """
        index = self.layouts.currentIndex()
        self.layouts.setCurrentWidget(self.table_layouts[index - 1])

    # Functions that select the name of the map
    def map_choice_1(self):
        self.name = "TheForest"
        self.layout_up()

    def map_choice_2(self):
        self.name = "TheTunnel"
        self.layout_up()

    def map_choice_3(self):
        self.name = "ThePrison"
        self.layout_up()

    def map_choice_4(self):
        self.name = "PracticeField"
        self.layout_up()

    # Functions that select the number of player of the map
    def player_choice_1(self):
        self.nb = 1
        self.display_grid()

    def player_choice_2(self):
        self.nb = 2
        self.display_grid()

    def player_choice_3(self):
        self.nb = 3
        self.display_grid()

    def player_choice_4(self):
        self.nb = 4
        self.display_grid()

    def display_grid(self):
        """
        Create the Layout where the Grid is printed and where
        you can play
        """
        self.game = layout_game.Controls(self.name, self.nb, self.h, self.w)
        self.game.grid_button.addWidget(self.start, 3, 1)
        self.table_layouts.append(self.game)
        self.layouts.addWidget(self.game)
        self.counter += 1
        self.layouts.setCurrentWidget(self.table_layouts[self.counter - 1])
        for i in range(4):
            self.game.button_move[i].clicked.connect(self.end)

    def layout_up(self):
        """
        Go forward into the Layouts
        """
        index = self.layouts.currentIndex()
        self.layouts.setCurrentWidget(self.table_layouts[index + 1])

    def end(self):
        """
        If we reach the dooor, we need to print the final Layout
        """
        if self.game.state == 2:
            self.the_end = the_end.The_End()
            self.table_layouts.append(self.the_end)
            self.layouts.addWidget(self.the_end)
            self.counter += 1
            self.the_end.quit.clicked.connect(self.close)
            self.the_end.button.clicked.connect(self.start_over)
            self.layouts.setCurrentWidget(self.the_end)

    def start_over(self):
        """
        If we want to play a new game
        """
        self.layouts.setCurrentWidget(self.rules)
Пример #21
0
class ComboEditor(ui_tools.StyledBar):
    # Signals
    closeSplit = pyqtSignal('PyQt_PyObject')
    splitEditor = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject', bool)
    allFilesClosed = pyqtSignal()
    about_to_close_combo_editor = pyqtSignal()

    def __init__(self, original=False):
        super(ComboEditor, self).__init__(None)
        self.__original = original
        self.__undocked = []
        self._symbols_index = []
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)

        self.bar = ActionBar(main_combo=original)
        vbox.addWidget(self.bar)

        # Info bar
        self.info_bar = InfoBar(self)
        self.info_bar.setVisible(False)
        vbox.addWidget(self.info_bar)

        self.stacked = QStackedLayout()
        vbox.addLayout(self.stacked)

        self._main_container = IDE.get_service('main_container')

        if not self.__original:
            self._main_container.fileOpened['QString'].connect(
                self._file_opened_by_main)

        # self.bar.combo.showComboSelector.connect(
        #    lambda: self._main_container.change_tab())
        self.bar.change_current['PyQt_PyObject',
                                int].connect(self._set_current)
        self.bar.splitEditor[bool].connect(self.split_editor)
        self.bar.runFile['QString'].connect(self._run_file)
        self.bar.closeSplit.connect(lambda: self.closeSplit.emit(self))
        self.bar.addToProject['QString'].connect(self._add_to_project)
        self.bar.showFileInExplorer['QString'].connect(
            self._show_file_in_explorer)
        self.bar.goToSymbol[int].connect(self._go_to_symbol)
        self.bar.undockEditor.connect(self.undock_editor)
        self.bar.reopenTab['QString'].connect(
            lambda path: self._main_container.open_file(path))

        # self.connect(self.bar, SIGNAL("recentTabsModified()"),
        #             lambda: self._main_container.recent_files_changed())
        # self.connect(self.bar.code_navigator.btnPrevious, SIGNAL("clicked()"),
        #             lambda: self._navigate_code(False))
        # self.connect(self.bar.code_navigator.btnNext, SIGNAL("clicked()"),
        #             lambda: self._navigate_code(True))

    # def _navigate_code(self, val):
    #    op = self.bar.code_navigator.operation
    #    self._main_container.navigate_code_history(val, op)

    def currentWidget(self):
        return self.stacked.currentWidget()

    def setFocus(self):
        super(ComboEditor, self).setFocus()
        self.stacked.currentWidget().setFocus()
        self._editor_with_focus()

    def _file_opened_by_main(self, path):
        index = self.stacked.currentIndex()
        ninjaide = IDE.get_service('ide')
        editable = ninjaide.get_or_create_editable(path)
        self.add_editor(editable)
        self.bar.set_current_by_index(index)
        if index == -1:
            self.bar.set_current_by_index(0)

    def add_editor(self, neditable, keep_index=False):
        """Add Editor Widget to the UI area."""
        if neditable.editor:
            if self.__original:
                editor = neditable.editor
            else:
                # editor = neditable.editor.clone()
                editor = self._main_container.create_editor_from_editable(
                    neditable)
            current_index = self.stacked.currentIndex()
            new_index = self.stacked.addWidget(editor)
            self.stacked.setCurrentIndex(new_index)
            self.bar.add_item(neditable.display_name, neditable)
            # Bar is not visible because all the files have been closed,
            # so if a new file is opened, show the bar
            if not self.bar.isVisible():
                self.bar.setVisible(True)
            if keep_index:
                self.bar.set_current_by_index(current_index)
            # Connections
            neditable.fileClosing.connect(self._close_file)
            editor.editorFocusObtained.connect(self._editor_with_focus)
            editor.modificationChanged.connect(self._editor_modified)
            neditable.checkersUpdated.connect(self._show_notification_icon)
            # Connect file system signals only in the original
            if self.__original:
                neditable.askForSaveFileClosing.connect(self._ask_for_save)
                neditable.fileChanged.connect(self._file_has_been_modified)
            # Editor Signals
            editor.cursor_position_changed[int, int].connect(
                self._update_cursor_position)
            editor.current_line_changed[int].connect(self._set_current_symbol)
            """
            # self.connect(editor, SIGNAL("editorFocusObtained()"),
            #             self._editor_with_focus)
            editor.editorFocusObtained.connect(self._editor_with_focus)
            neditable.fileSaved['PyQt_PyObject'].connect(
                self._update_combo_info)
            neditable.fileSaved['PyQt_PyObject'].connect(
                self._update_symbols)
            editor.modificationChanged[bool].connect(self._editor_modified)
            neditable.checkersUpdated.connect(self._show_notification_icon)

            # Connect file system signals only in the original
            neditable.fileClosing['PyQt_PyObject'].connect(self._close_file)
            if self.__original:
                neditable.askForSaveFileClosing['PyQt_PyObject'].connect(
                    self._ask_for_save)

                neditable.fileChanged['PyQt_PyObject'].connect(
                    self._file_has_been_modified)
                self.info_bar.reloadClicked.connect(neditable.reload_file)

            # Load Symbols
            self._load_symbols(neditable)
            """

    def show_combo_file(self):
        self.bar.combo.showPopup()

    def show_combo_symbol(self):
        self.bar.symbols_combo.showPopup()

    def unlink_editors(self):
        for index in range(self.stacked.count()):
            widget = self.stacked.widget(index)
            # widget.setDocument(QsciDocument())

    def split_editor(self, orientation_vertical):
        new_widget = ComboEditor()
        for neditable in self.bar.get_editables():
            new_widget.add_editor(neditable)
        self.splitEditor.emit(self, new_widget, orientation_vertical)
        # for neditable in self.bar.get_editables():
        #    new_widget.add_editor(neditable)
        # self.splitEditor.emit(self, new_widget, orientationVertical)
        # self.emit(SIGNAL("splitEditor(PyQt_PyObject, PyQt_PyObject, bool)"),
        #          self, new_widget, orientationVertical)

    def undock_editor(self):
        new_combo = ComboEditor()
        new_combo.setWindowTitle("NINJA-IDE")
        editor = self.currentWidget()
        new_combo.add_editor(editor.neditable)
        new_combo.show()
        """
        for neditable in self.bar.get_editables():
            new_combo.add_editor(neditable)
        neditor = self.currentWidget().clone()
        new_combo.set_current(neditor.neditable)
        new_combo.resize(700, 500)
        new_combo.about_to_close_combo_editor.connect(self._remove_undock)
        new_combo.show()
        """

    def _remove_undock(self):
        widget = self.sender()
        self.__undocked.remove(widget)

    def close_current_file(self):
        self.bar.about_to_close_file()

    def _close_file(self, neditable):
        index = self.bar.close_file(neditable)
        print(index)
        layoutItem = self.stacked.takeAt(index)
        # neditable.editor.completer.cc.unload_module()
        self._add_to_last_opened(neditable.file_path)
        layoutItem.widget().deleteLater()

        if self.stacked.isEmpty():
            self.bar.hide()
            self.allFilesClosed.emit()

    def _add_to_last_opened(self, path):
        if path not in settings.LAST_OPENED_FILES:
            settings.LAST_OPENED_FILES.append(path)
            if len(settings.LAST_OPENED_FILES) > settings.MAX_REMEMBER_TABS:
                self.__lastOpened = self.__lastOpened[1:]
            print("RecentTabsModified")
            # self.emit(SIGNAL("recentTabsModified()"))

    def _editor_with_focus(self):
        if self._main_container.current_widget is not self:
            self._main_container.current_widget = self
            editor = self.stacked.currentWidget()
            self._main_container.current_editor_changed(
                editor.neditable.file_path)
            self._load_symbols(editor.neditable)
            editor.neditable.update_checkers_display()

    def _ask_for_save(self, neditable):
        val = QMessageBox.No
        fileName = neditable.nfile.file_name
        val = QMessageBox.question(
            self, (self.tr('The file %s was not saved') % fileName),
            self.tr("Do you want to save before closing?"),
            QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
        if val == QMessageBox.No:
            neditable.nfile.close(force_close=True)
        elif val == QMessageBox.Yes:
            neditable.ignore_checkers = True
            self._main_container.save_file(neditable.editor)
            neditable.nfile.close()

    def _file_has_been_modified(self, neditable):
        self.info_bar.show_message(translations.TR_FILE_MODIFIED_OUTSIDE)
        # val = QMessageBox.No
        # fileName = neditable.file_path
        # val = QMessageBox.question(
        #    self, translations.TR_FILE_HAS_BEEN_MODIFIED,
        #    "%s%s" % (fileName, translations.TR_FILE_MODIFIED_OUTSIDE),
        #    QMessageBox.Yes | QMessageBox.No)
        # if val == QMessageBox.Yes:
        #    neditable.reload_file()

    def _run_file(self, path):
        self._main_container.run_file(path)

    def _add_to_project(self, path):
        self._main_container._add_to_project(path)

    def _show_file_in_explorer(self, path):
        '''Connected to ActionBar's showFileInExplorer(QString)
        signal, forwards the file path on to the main container.'''

        self._main_container._show_file_in_explorer(path)

    def set_current(self, neditable):
        if neditable:
            self.bar.set_current_file(neditable)

    def _set_current(self, neditable, index):
        if neditable:
            self.stacked.setCurrentIndex(index)
            editor = self.stacked.currentWidget()
            self._update_cursor_position(ignore_sender=True)
            editor.setFocus()
            self._main_container.current_editor_changed(neditable.file_path)
            self._load_symbols(neditable)
            # self._show_file_in_explorer(neditable.file_path)
            neditable.update_checkers_display()

    def widget(self, index):
        return self.stacked.widget(index)

    def count(self):
        """Return the number of editors opened."""
        return self.stacked.count()

    def _update_cursor_position(self, line=0, col=0, ignore_sender=False):
        obj = self.sender()
        editor = self.stacked.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            line += 1
            self.bar.update_line_col(line, col)

    def _set_current_symbol(self, line, ignore_sender=False):
        obj = self.sender()
        editor = self.stacked.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            index = bisect.bisect(self._symbols_index, line)
            if (index >= len(self._symbols_index)
                    or self._symbols_index[index] > (line + 1)):
                index -= 1
            self.bar.set_current_symbol(index)

    def _editor_modified(self, value):
        obj = self.sender()
        neditable = obj.neditable
        if value:
            text = "\u2022 %s" % neditable.display_name
            self.bar.update_item_text(neditable, text)
        else:
            self.bar.update_item_text(neditable, neditable.display_name)

    def _go_to_symbol(self, index):
        # FIXME: index 0 invalid
        line = self._symbols_index[index]
        editor = self.stacked.currentWidget()
        editor.go_to_line(line)

    def _update_symbols(self, neditable):
        editor = self.stacked.currentWidget()
        # Check if it's current to avoid signals from other splits.
        if editor == neditable.editor:
            self._load_symbols(neditable)

    def _update_combo_info(self, neditable):
        self.bar.update_item_text(neditable, neditable.display_name)
        self._main_container.current_editor_changed(neditable.file_path)

    def _load_symbols(self, neditable):
        symbols_handler = handlers.get_symbols_handler('py')
        source = neditable.editor.text
        source = source.encode(neditable.editor.encoding)
        symbols, symbols_simplified = symbols_handler.obtain_symbols(
            source, simple=True)
        self._symbols_index = sorted(symbols_simplified.keys())
        symbols_simplified = sorted(list(symbols_simplified.items()),
                                    key=lambda x: x[0])
        self.bar.add_symbols(symbols_simplified)
        line, _ = neditable.editor.cursor_position
        self._set_current_symbol(line, True)
        tree_symbols = IDE.get_service('symbols_explorer')
        tree_symbols.update_symbols_tree(symbols, neditable.file_path)

    def _show_notification_icon(self, neditable):
        checkers = neditable.sorted_checkers
        icon = QIcon()
        for items in checkers:
            checker, color, _ = items
            if checker.checks:
                if isinstance(checker.checker_icon, int):
                    icon = self.style().standardIcon(checker.checker_icon)
                elif isinstance(checker.checker_icon, str):
                    icon = QIcon(checker.checker_icon)
                # FIXME: sucks
                else:
                    icon = QIcon(checker.checker_icon)
                break
        self.bar.update_item_icon(neditable, icon)

    def show_menu_navigation(self):
        self.bar.code_navigator.show_menu_navigation()

    def closeEvent(self, event):
        self.about_to_close_combo_editor.emit()
        # self.emit(SIGNAL("aboutToCloseComboEditor()"))
        super(ComboEditor, self).closeEvent(event)

    def reject(self):
        if not self.__original:
            super(ComboEditor, self).reject()
Пример #22
0
class ExpressionDialog(QDialog):
    def __init__(self, expr_pool):
        super().__init__()
        self.pool = expr_pool
        self.stack = QStackedLayout()
        self.stack.addWidget(self.build_first_page())
        self.stack.addWidget(self.build_second_page())
        self.stack.addWidget(self.build_third_page())
        self.stack.addWidget(self.build_fourth_page())
        self.stack.addWidget(self.build_fifth_page())
        self.setLayout(self.stack)
        self.setWindowTitle('Add expression')

    def build_first_page(self):
        first_page = QWidget()
        expression_type_box = QGroupBox('Select expression type')
        self.simple_button = QRadioButton(
            'Simple expression\nUse variables, operators, numbers and existing'
            'expressions to create a new expression. Example: B+H+(V^2)/(2*9.81)'
        )
        self.simple_button.setChecked(True)
        self.condition_button = QRadioButton(
            'Conditional expression\nUse existing conditions and expressions'
            'to create a conditional expression. '
            'Example: IF (B > 0) THEN (B) ELSE (0)')
        self.max_min_button = QRadioButton(
            'Max/Min between two expressions\nUse two existing expressions and'
            'MAX or MIN to create a new expression. Example: MAX(B, RB+0.5)')
        self.masked_button = QRadioButton(
            'Masked expression\nUse an expression containing polygonal values '
            'and a non-polygonal expression\nto create a masked expression. '
            'Example: IF (POLY1) THEN (B+POLY1) ELSE (B)')

        self.condition_button.setEnabled(
            self.pool.ready_for_conditional_expression())
        self.max_min_button.setEnabled(
            self.pool.ready_for_max_min_expression())
        self.masked_button.setEnabled(self.pool.ready_for_masked_expression())
        vlayout = QVBoxLayout()
        vlayout.addWidget(self.simple_button)
        vlayout.addWidget(self.condition_button)
        vlayout.addWidget(self.max_min_button)
        vlayout.addWidget(self.masked_button)
        expression_type_box.setLayout(vlayout)
        next_button = QPushButton('Next')
        cancel_button = QPushButton('Cancel')
        for bt in (next_button, cancel_button):
            bt.setMaximumWidth(200)
            bt.setFixedHeight(30)
        hlayout = QHBoxLayout()
        hlayout.addStretch()
        hlayout.addWidget(next_button)
        hlayout.addWidget(cancel_button)
        vlayout = QVBoxLayout()
        vlayout.addWidget(expression_type_box)
        vlayout.addStretch()
        vlayout.addLayout(hlayout, Qt.AlignRight)
        first_page.setLayout(vlayout)

        next_button.clicked.connect(self.turn_page)
        cancel_button.clicked.connect(self.reject)
        return first_page

    def build_second_page(self):
        second_page = QWidget()
        self.expression_text = QTextEdit()
        var_list = VariableList(self.pool, self.expression_text)
        ok_button = QPushButton('OK')
        cancel_button = QPushButton('Cancel')
        for bt in (ok_button, cancel_button):
            bt.setMaximumWidth(200)
            bt.setFixedHeight(30)
        hlayout = QHBoxLayout()
        vlayout = QVBoxLayout()
        lb = QLabel('Available variables and expressions')
        vlayout.addWidget(lb)
        vlayout.addWidget(var_list)
        vlayout.setAlignment(lb, Qt.AlignHCenter)
        hlayout.addLayout(vlayout)
        vlayout = QVBoxLayout()
        vlayout.addWidget(
            QLabel(
                '<p style="font-size:10pt">'
                '<b>Help</b>: double click on the list to add variables or existing expressions.<br>'
                'You can also enter operators, parentheses and numbers.<br>'
                'Supported operators: <tt>+ - * / ^ sqrt sin cos atan</tt>.</p>'
            ))
        vlayout.addItem(QSpacerItem(10, 10))
        vlayout.addWidget(QLabel('Expression Editor'))
        vlayout.addWidget(self.expression_text)
        hlayout.addLayout(vlayout)
        hlayout.setSpacing(10)
        vlayout = QVBoxLayout()
        vlayout.addLayout(hlayout)
        hlayout = QHBoxLayout()
        hlayout.addStretch()
        hlayout.addWidget(ok_button)
        hlayout.addWidget(cancel_button)
        vlayout.addLayout(hlayout)
        second_page.setLayout(vlayout)

        ok_button.clicked.connect(self.check)
        cancel_button.clicked.connect(self.reject)
        return second_page

    def build_third_page(self):
        third_page = QWidget()
        if not self.condition_button.isEnabled():
            return third_page
        self.condition_box = QComboBox()
        self.true_box = QComboBox()
        self.false_box = QComboBox()
        ok_button = QPushButton('OK')
        cancel_button = QPushButton('Cancel')
        for bt in (ok_button, cancel_button):
            bt.setMaximumWidth(200)
            bt.setFixedHeight(30)
        for box in (self.condition_box, self.true_box, self.false_box):
            box.setFixedHeight(30)
            box.setMaximumWidth(250)
        for i in range(1, self.pool.nb_expressions() + 1):
            expr = self.pool.expressions()[i]
            if expr.masked:
                continue
            self.true_box.addItem(str(expr))
            self.false_box.addItem(str(expr))
        for i in range(1, self.pool.nb_conditions() + 1):
            self.condition_box.addItem(str(self.pool.conditions()[i]))
        vlayout = QVBoxLayout()
        glayout = QGridLayout()
        glayout.addWidget(QLabel('Condition'), 1, 1, Qt.AlignHCenter)
        glayout.addWidget(QLabel('True'), 1, 2, Qt.AlignHCenter)
        glayout.addWidget(QLabel('False'), 1, 3, Qt.AlignHCenter)
        glayout.addWidget(self.condition_box, 2, 1)
        glayout.addWidget(self.true_box, 2, 2)
        glayout.addWidget(self.false_box, 2, 3)
        glayout.setVerticalSpacing(12)
        glayout.setRowStretch(0, 1)
        vlayout.addLayout(glayout)
        vlayout.addStretch()
        hlayout = QHBoxLayout()
        hlayout.addStretch()
        hlayout.addWidget(ok_button)
        hlayout.addWidget(cancel_button)
        vlayout.addLayout(hlayout)
        third_page.setLayout(vlayout)

        ok_button.clicked.connect(self.check)
        cancel_button.clicked.connect(self.reject)
        return third_page

    def build_fourth_page(self):
        fourth_page = QWidget()
        if not self.max_min_button.isEnabled():
            return fourth_page
        self.max_min_box = QComboBox()
        self.max_min_box.addItem('MAX')
        self.max_min_box.addItem('MIN')
        self.first_box = QComboBox()
        self.second_box = QComboBox()
        ok_button = QPushButton('OK')
        cancel_button = QPushButton('Cancel')
        for bt in (ok_button, cancel_button):
            bt.setMaximumWidth(200)
            bt.setFixedHeight(30)
        for box in (self.first_box, self.second_box):
            box.setFixedHeight(30)
            box.setMaximumWidth(250)
        self.max_min_box.setFixedSize(100, 30)
        for i in range(1, self.pool.nb_expressions() + 1):
            expr = self.pool.expressions()[i]
            if expr.masked:
                continue
            self.first_box.addItem(str(expr))
            self.second_box.addItem(str(expr))
        vlayout = QVBoxLayout()
        glayout = QGridLayout()
        glayout.addWidget(QLabel('Condition'), 1, 1, Qt.AlignHCenter)
        glayout.addWidget(QLabel('True'), 1, 2, Qt.AlignHCenter)
        glayout.addWidget(QLabel('False'), 1, 3, Qt.AlignHCenter)
        glayout.addWidget(self.max_min_box, 2, 1)
        glayout.addWidget(self.first_box, 2, 2)
        glayout.addWidget(self.second_box, 2, 3)
        glayout.setVerticalSpacing(12)
        glayout.setRowStretch(0, 1)
        vlayout.addLayout(glayout)
        vlayout.addStretch()
        hlayout = QHBoxLayout()
        hlayout.addStretch()
        hlayout.addWidget(ok_button)
        hlayout.addWidget(cancel_button)
        vlayout.addLayout(hlayout)
        fourth_page.setLayout(vlayout)

        ok_button.clicked.connect(self.check)
        cancel_button.clicked.connect(self.reject)
        return fourth_page

    def build_fifth_page(self):
        fifth_page = QWidget()
        if not self.masked_button.isEnabled():
            return fifth_page
        self.poly_box = QComboBox()
        self.inside_box = QComboBox()
        self.outside_box = QComboBox()
        ok_button = QPushButton('OK')
        cancel_button = QPushButton('Cancel')
        for bt in (ok_button, cancel_button):
            bt.setMaximumWidth(200)
            bt.setFixedHeight(30)
        for box in (self.poly_box, self.inside_box, self.outside_box):
            box.setFixedHeight(30)
            box.setMaximumWidth(250)
        for i in range(1, self.pool.nb_masks() + 1):
            mask = self.pool.masks()[i]
            if mask.nb_children > 0:
                self.poly_box.addItem(mask.code())
        for i in range(1, self.pool.nb_expressions() + 1):
            expr = self.pool.expressions()[i]
            if not expr.polygonal:
                self.outside_box.addItem(str(expr))
        self.update_inside_mask(self.poly_box.currentText())
        self.poly_box.currentTextChanged.connect(self.update_inside_mask)
        vlayout = QVBoxLayout()
        glayout = QGridLayout()
        glayout.addWidget(QLabel('Mask'), 1, 1, Qt.AlignHCenter)
        glayout.addWidget(QLabel('Inside'), 1, 2, Qt.AlignHCenter)
        glayout.addWidget(QLabel('Outside'), 1, 3, Qt.AlignHCenter)
        glayout.addWidget(self.poly_box, 2, 1)
        glayout.addWidget(self.inside_box, 2, 2)
        glayout.addWidget(self.outside_box, 2, 3)
        glayout.setVerticalSpacing(12)
        glayout.setRowStretch(0, 1)
        vlayout.addLayout(glayout)
        vlayout.addStretch()
        hlayout = QHBoxLayout()
        hlayout.addStretch()
        hlayout.addWidget(ok_button)
        hlayout.addWidget(cancel_button)
        vlayout.addLayout(hlayout)
        fifth_page.setLayout(vlayout)

        ok_button.clicked.connect(self.check)
        cancel_button.clicked.connect(self.reject)
        return fifth_page

    def update_inside_mask(self, current_mask):
        mask = self.pool.get_mask(current_mask)
        self.inside_box.clear()
        for child_code in mask.children:
            expr = self.pool.get_expression(child_code)
            self.inside_box.addItem(str(expr))

    def turn_page(self):
        if self.simple_button.isChecked():
            self.stack.setCurrentIndex(1)
        elif self.condition_button.isChecked():
            self.stack.setCurrentIndex(2)
        elif self.max_min_button.isChecked():
            self.stack.setCurrentIndex(3)
        else:
            self.stack.setCurrentIndex(4)

    def polygonal_success_message(self):
        QMessageBox.information(
            None, 'Polygonal expression created',
            'You just created an expression containing polygon values.\n'
            'To use it, click "Add Expression" then choose "Masked expression"\n'
            '(You will also need at least one non-polygonal expression).',
            QMessageBox.Ok)

    def polygonal_fail_message(self):
        QMessageBox.critical(
            None, 'Error',
            'One expression can only use only one polygonal mask!',
            QMessageBox.Ok)

    def check(self):
        current_page = self.stack.currentIndex()
        if current_page == 1:
            literal_expression = self.expression_text.toPlainText()
            success_code = self.pool.add_simple_expression(literal_expression)
            if success_code == -1:
                QMessageBox.critical(None, 'Error', 'Invalid expression.',
                                     QMessageBox.Ok)
                return
            elif success_code == -2:
                self.polygonal_fail_message()
                return
            elif success_code == 1:
                self.polygonal_success_message()

        elif current_page == 2:
            str_true, str_false = self.true_box.currentText(
            ), self.false_box.currentText()
            if str_true == str_false:
                QMessageBox.critical(
                    None, 'Error',
                    'The True/False expressions cannot be identical!',
                    QMessageBox.Ok)
                return
            str_cond = self.condition_box.currentText()
            success_code = self.pool.add_conditional_expression(
                self.pool.get_condition(str_cond),
                self.pool.get_expression(str_true),
                self.pool.get_expression(str_false))
            if success_code == -2:
                self.polygonal_fail_message()
                return
            elif success_code == 1:
                self.polygonal_success_message()
        elif current_page == 3:
            is_max = self.max_min_box.currentText() == 'MAX'
            str_first, str_second = self.first_box.currentText(
            ), self.second_box.currentText()
            if str_first == str_second:
                QMessageBox.critical(
                    None, 'Error', 'The two expressions cannot be identical!',
                    QMessageBox.Ok)
                return
            success_code = self.pool.add_max_min_expression(
                self.pool.get_expression(str_first),
                self.pool.get_expression(str_second), is_max)
            if success_code == -2:
                self.polygonal_fail_message()
                return
            elif success_code == 1:
                self.polygonal_success_message()
        else:
            str_inside, str_outside = self.inside_box.currentText(
            ), self.outside_box.currentText()
            self.pool.add_masked_expression(
                self.pool.get_expression(str_inside),
                self.pool.get_expression(str_outside))
        self.accept()
Пример #23
0
class Tex0WidgetGroup(QWidget):
    def __init__(self,
                 parent,
                 tex0s=None,
                 max_rows=0,
                 max_columns=4,
                 brres=None):
        super().__init__(parent)
        main_layout = QVBoxLayout(self)
        self.stack = QStackedLayout(self)
        self.stack_widget = QWidget(self)
        self.map_box = QComboBox()
        self.map_box.activated.connect(self.on_map_change)
        self.__init_context_menu()
        main_layout.addWidget(self.map_box)
        self.stack_widget.setLayout(self.stack)
        main_layout.addWidget(self.stack_widget)
        self.subscriber = parent
        if tex0s is not None:
            self.set_tex0s(tex0s)
            if brres is None:
                self.brres = tex0s[0].parent
        if brres:
            self.brres = brres
        self.setLayout(main_layout)

    def __init_context_menu(self):
        self.setContextMenuPolicy(Qt.ActionsContextMenu)
        create_action = QAction('&Add Map', self)
        create_action.setToolTip('Add new map')
        create_action.triggered.connect(self.create_map)
        self.addAction(create_action)
        replace_action = QAction('&Replace', self)
        replace_action.setToolTip('Replace map')
        replace_action.triggered.connect(self.replace_map)
        self.addAction(replace_action)
        export_action = QAction('&Export', self)
        export_action.setToolTip('Export as png')
        export_action.triggered.connect(self.export)
        self.addAction(export_action)
        remove_action = QAction('&Delete', self)
        remove_action.setToolTip('Remove the map')
        remove_action.triggered.connect(self.remove)
        self.addAction(remove_action)

    def export(self):
        self.stack.currentWidget().export()

    def remove(self):
        self.remove_map_widget(self.stack.currentWidget())

    def replace_map(self):
        self.stack.currentWidget().replace_map()

    def get_tex0(self, index):
        return self.stack.itemAt(index).tex0

    def on_map_replace(self, tex):
        if self.subscriber is not None:
            self.subscriber.on_map_replace(tex, self.stack.currentIndex())

    def on_map_change(self, index):
        self.stack.setCurrentIndex(index)
        if self.subscriber is not None:
            self.subscriber.on_map_change(self.stack.currentWidget().tex0,
                                          index)

    def reset(self):
        for i in reversed(range(self.stack.count())):
            widget = self.stack.itemAt(i).widget()
            widget.del_widget()
            self.map_box.removeItem(i)

    def set_brres(self, brres):
        self.brres = brres

    def set_tex0s(self, tex0s):
        self.reset()
        for x in tex0s:
            self.add_tex0(x)

    def add_tex0(self, x):
        widget = MapWidget(self, x)
        self.add_map_widget(widget)

    def add_map_widget(self, map_widget):
        self.stack.addWidget(map_widget)
        self.map_box.addItem(map_widget.name)

    def remove_map_widget(self, map_widget):
        tex0 = map_widget.tex0
        index = self.stack.currentIndex()
        if self.subscriber is not None:
            self.subscriber.on_map_remove(tex0, index)

    def create_map(self):
        self.importer = MapImporter(self, self.brres)

    def on_import(self, tex0):
        index = self.stack.count()
        if self.subscriber:
            self.subscriber.on_map_add(tex0, index)
        self.importer = None
Пример #24
0
class ConditionDialog(QDialog):
    def __init__(self, expr_pool):
        super().__init__()
        self.expr_pool = expr_pool
        self.stack = QStackedLayout()
        self.stack.addWidget(self.build_first_page())
        self.stack.addWidget(self.build_second_page())
        self.stack.addWidget(self.build_third_page())
        self.setLayout(self.stack)
        self.setWindowTitle('Add condition')

    def build_first_page(self):
        first_page = QWidget()
        expression_type_box = QGroupBox('Select condition type')
        self.simple_button = QRadioButton(
            'Simple condition\nUse an expression, a comparator and a threshold value'
            'to create a new condition. Example: B > 0')
        self.simple_button.setChecked(True)
        self.and_or_button = QRadioButton(
            'AND/OR condition\nUse two existing conditions and AND/OR operators'
            'to create a new condition. Example: (B > 0) AND (B < 100)')
        self.and_or_button.setEnabled(self.expr_pool.nb_conditions() > 1)
        vlayout = QVBoxLayout()
        vlayout.addWidget(self.simple_button)
        vlayout.addWidget(self.and_or_button)
        expression_type_box.setLayout(vlayout)
        next_button = QPushButton('Next')
        cancel_button = QPushButton('Cancel')
        for bt in (next_button, cancel_button):
            bt.setMaximumWidth(200)
            bt.setFixedHeight(30)
        hlayout = QHBoxLayout()
        hlayout.addStretch()
        hlayout.addWidget(next_button)
        hlayout.addWidget(cancel_button)
        vlayout = QVBoxLayout()
        vlayout.addWidget(expression_type_box)
        vlayout.addStretch()
        vlayout.addLayout(hlayout, Qt.AlignRight)
        first_page.setLayout(vlayout)

        next_button.clicked.connect(self.turn_page)
        cancel_button.clicked.connect(self.reject)
        return first_page

    def build_second_page(self):
        second_page = QWidget()
        buttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
        buttons.accepted.connect(self.check)
        buttons.rejected.connect(self.reject)

        self.expression_box = QComboBox()
        self.expression_box.setFixedHeight(30)
        self.expression_box.setMinimumWidth(150)
        self.expression_box.setMaximumWidth(250)

        for i in range(1, self.expr_pool.nb_expressions() + 1):
            expr = self.expr_pool.expressions()[i]
            if expr.masked:
                continue
            self.expression_box.addItem(str(expr))

        self.comparator_box = QComboBox()
        for comparator in ['>', '<', '>=', '<=']:
            self.comparator_box.addItem(comparator)
        self.comparator_box.setFixedSize(50, 30)

        self.threshold_box = QLineEdit()
        self.threshold_box.setFixedSize(150, 30)

        vlayout = QVBoxLayout()
        glayout = QGridLayout()
        glayout.addWidget(QLabel('Expression'), 1, 1, Qt.AlignHCenter)
        glayout.addWidget(QLabel('Comparator'), 1, 2, Qt.AlignHCenter)
        glayout.addWidget(QLabel('Threshold'), 1, 3, Qt.AlignHCenter)
        glayout.addWidget(self.expression_box, 2, 1)
        glayout.addWidget(self.comparator_box, 2, 2)
        glayout.addWidget(self.threshold_box, 2, 3)
        glayout.setVerticalSpacing(12)
        glayout.setRowStretch(0, 1)
        vlayout.addLayout(glayout)
        vlayout.addStretch()
        vlayout.addWidget(buttons)
        second_page.setLayout(vlayout)
        return second_page

    def build_third_page(self):
        third_page = QWidget()
        if not self.and_or_button.isEnabled():
            return third_page
        self.and_or_box = QComboBox()
        self.and_or_box.addItem('AND')
        self.and_or_box.addItem('OR')
        self.first_box = QComboBox()
        self.second_box = QComboBox()
        ok_button = QPushButton('OK')
        cancel_button = QPushButton('Cancel')
        for bt in (ok_button, cancel_button):
            bt.setMaximumWidth(200)
            bt.setFixedHeight(30)
        for box in (self.first_box, self.second_box):
            box.setFixedHeight(30)
            box.setMaximumWidth(250)
        self.and_or_box.setFixedSize(100, 30)
        for i in range(1, self.expr_pool.nb_conditions() + 1):
            condition = str(self.expr_pool.conditions()[i])
            self.first_box.addItem(condition)
            self.second_box.addItem(condition)
        vlayout = QVBoxLayout()
        glayout = QGridLayout()
        glayout.addWidget(QLabel('Condition 1'), 1, 1, Qt.AlignHCenter)
        glayout.addWidget(QLabel('Operator'), 1, 2, Qt.AlignHCenter)
        glayout.addWidget(QLabel('Condition 2'), 1, 3, Qt.AlignHCenter)
        glayout.addWidget(self.first_box, 2, 1)
        glayout.addWidget(self.and_or_box, 2, 2)
        glayout.addWidget(self.second_box, 2, 3)
        glayout.setVerticalSpacing(12)
        glayout.setRowStretch(0, 1)
        vlayout.addLayout(glayout)
        vlayout.addStretch()
        hlayout = QHBoxLayout()
        hlayout.addStretch()
        hlayout.addWidget(ok_button)
        hlayout.addWidget(cancel_button)
        vlayout.addLayout(hlayout)
        third_page.setLayout(vlayout)

        ok_button.clicked.connect(self.check)
        cancel_button.clicked.connect(self.reject)
        return third_page

    def turn_page(self):
        if self.simple_button.isChecked():
            self.stack.setCurrentIndex(1)
        else:
            self.stack.setCurrentIndex(2)

    def check(self):
        current_page = self.stack.currentIndex()
        if current_page == 1:
            threshold = self.threshold_box.text()
            try:
                threshold = float(threshold)
            except ValueError:
                QMessageBox.critical(None, 'Error',
                                     'The threshold is not a number!',
                                     QMessageBox.Ok)
                return
            expr_text = self.expression_box.currentText()
            self.expr_pool.add_condition(
                self.expr_pool.get_expression(expr_text),
                self.comparator_box.currentText(), threshold)
        else:
            is_and = self.and_or_box.currentText() == 'AND'
            first_text, second_text = self.first_box.currentText(
            ), self.second_box.currentText()
            if first_text == second_text:
                QMessageBox.critical(
                    None, 'Error', 'The two conditions cannot be identical!',
                    QMessageBox.Ok)
                return
            success_code = self.expr_pool.add_and_or_condition(
                self.expr_pool.get_condition(first_text),
                self.expr_pool.get_condition(second_text), is_and)
            if success_code == -2:
                QMessageBox.critical(
                    None, 'Error',
                    'One condition can only use only one polygonal mask!',
                    QMessageBox.Ok)
                return
        self.accept()
Пример #25
0
class MainView(QLabel):

    DirPath = 'Images'

    def __init__(self, *args, **kwargs):
        super(MainView, self).__init__(*args, **kwargs)
        self.setScaledContents(True)
        rect = QApplication.instance().desktop().availableGeometry()
        # 桌面大小的2/3
        self.resize(int(rect.width() * 2 / 3), int(rect.height() * 2 / 3))
        # 布局
        layout = QHBoxLayout(self, spacing=0)
        layout.setContentsMargins(0, 0, 0, 0)
        Signals.setParent(self)
        NetWork.setParent(self)

        # 获取上一页图片的按钮
        layout.addWidget(
            QPushButton(self,
                        objectName='previousButton',
                        clicked=self.onPreviousPage))
        # 故事控件
        layout.addWidget(StoryView(self))
        # 层叠布局
        self.stackLayout = QStackedLayout(spacing=0)
        self.stackLayout.setContentsMargins(0, 0, 0, 0)
        layout.addLayout(self.stackLayout)

        # 获取下一页图片的按钮
        layout.addWidget(
            QPushButton(self, objectName='nextButton',
                        clicked=self.onNextPage))

        # 当前日期的图片被下载
        Signals.currentImageAdded.connect(self.loadCurrentImage)
        # 单个item鼠标悬停离开信号
        Signals.imageHovered.connect(self.onImageHovered)

    def closeEvent(self, event):
        """关闭窗口时保存窗口的截图文件"""
        os.makedirs(self.DirPath, exist_ok=True)
        self.grab().save(os.path.join(self.DirPath, 'tmp.jpg'))
        super(MainView, self).closeEvent(event)

    def onImageHovered(self, hovered, image):
        self.setPixmap(QPixmap.fromImage(image) if hovered else self.oldImage)

    def onPreviousPage(self):
        """上一页"""
        index = self.stackLayout.currentIndex()
        if index > 0:
            index -= 1
            self.stackLayout.setCurrentIndex(index)

    def onNextPage(self):
        """下一页"""
        index = self.stackLayout.currentIndex()
        count = self.stackLayout.count() - 1
        if index < count:
            index += 1
            self.stackLayout.setCurrentIndex(index)

    def splist(self, src, length):
        # 等分列表
        return (src[i:i + length] for i in range(len(src)) if i % length == 0)

    def addImages(self, _, datas):
        """解析json数据并生成层叠2x2的网格页面"""
        try:
            imagesGroup = self.splist(
                json.loads(datas.decode()).get('images', []), 4)  # 每组4个
        except Exception as e:
            print(e)
            imagesGroup = []
        for images in imagesGroup:
            pageView = PageView(self)
            pageView.addImages(images)
            self.stackLayout.addWidget(pageView)
        # 设置当前索引
        self.stackLayout.setCurrentIndex(0)

    def loadCurrentImage(self, path):
        """加载当前日期的图片作为背景"""
        self.oldImage = QPixmap(path)
        self.setPixmap(self.oldImage)
        # 延迟1秒后显示
        QTimer.singleShot(1000, self.onShow)

    def onShow(self):
        self.setCursor(Qt.ArrowCursor)
        self.setVisible(True)
        Signals.splashClosed.emit(self)  # 通知关闭启动界面

    def initData(self):
        """加载api接口数据"""
        # 获取最近几天的
        url = 'https://cn.bing.com/HPImageArchive.aspx?format=js&idx=-1&n=8'
        NetWork.get(self.createRequest(url, self.addImages))
        # 获取之前的
        url = 'https://cn.bing.com/HPImageArchive.aspx?format=js&idx=7&n=8'
        NetWork.get(self.createRequest(url, self.addImages))
        # 获取每日故事
        url = 'http://cn.bing.com/cnhp/coverstory/'
        NetWork.get(self.createRequest(url, Signals.storyAdded.emit))

    def createRequest(self, url, callback):
        """创建网络请求"""
        req = QNetworkRequest(QUrl(url))
        # 回调函数用于加载图片显示
        req.setAttribute(QNetworkRequest.User + 3, callback)
        return req
Пример #26
0
class AppWindow(QMainWindow):
    "The application's main window"

    def __init__(self):
        super().__init__()
        self.initUI()
        self.start_up()
        QTimer.singleShot(3000, self._check_update)

    def init_watchers(self):
        def remove_gallery(g):
            index = self.manga_list_view.find_index(g.id)
            if index:
                self.manga_list_view.remove_gallery([index])

        def create_gallery(path):
            g_dia = gallerydialog.GalleryDialog(self, path)
            g_dia.SERIES.connect(self.manga_list_view.gallery_model.addRows)
            g_dia.show()

        def update_gallery(g):
            index = self.manga_list_view.find_index(g.id)
            if index:
                self.manga_list_view.replace_edit_gallery([g], index.row())
            else:
                log_e("Could not find gallery to update from Watcher")

        def created(path):
            c_popup = file_misc.CreatedPopup(path, self)
            c_popup.ADD_SIGNAL.connect(create_gallery)

        def modified(path, gallery):
            mod_popup = file_misc.ModifiedPopup(path, gallery, self)

        def deleted(path, gallery):
            d_popup = file_misc.DeletedPopup(path, gallery, self)
            d_popup.UPDATE_SIGNAL.connect(update_gallery)
            d_popup.REMOVE_SIGNAL.connect(remove_gallery)

        def moved(new_path, gallery):
            mov_popup = file_misc.MovedPopup(new_path, gallery, self)
            mov_popup.UPDATE_SIGNAL.connect(update_gallery)

        self.watchers = file_misc.Watchers()
        self.watchers.gallery_handler.CREATE_SIGNAL.connect(created)
        self.watchers.gallery_handler.MODIFIED_SIGNAL.connect(modified)
        self.watchers.gallery_handler.MOVED_SIGNAL.connect(moved)
        self.watchers.gallery_handler.DELETED_SIGNAL.connect(deleted)

        if gui_constants.LOOK_NEW_GALLERY_STARTUP:
            self.notification_bar.add_text("Looking for new galleries...")
            try:

                class ScanDir(QObject):
                    final_paths_and_galleries = pyqtSignal(list, list)

                    def __init__(self, model_data, parent=None):
                        super().__init__(parent)
                        self.model_data = model_data

                    def scan_dirs(self):
                        db_data = self.model_data
                        paths = []
                        for g in range(len(db_data)):
                            paths.append(os.path.normcase(db_data[g].path))

                        contents = []
                        case_path = []  # needed for tile and artist parsing... e.g to avoid lowercase
                        for m_path in gui_constants.MONITOR_PATHS:
                            for p in os.listdir(m_path):
                                abs_p = os.path.join(m_path, p)
                                if os.path.isdir(abs_p) or p.endswith(utils.ARCHIVE_FILES):
                                    case_path.append(abs_p)
                                    contents.append(os.path.normcase(abs_p))

                        paths = sorted(paths)
                        new_galleries = []
                        for c, x in enumerate(contents):
                            y = utils.b_search(paths, x)
                            if not y:
                                # (path, number for case_path)
                                new_galleries.append((x, c))

                        galleries = []
                        final_paths = []
                        if new_galleries:
                            for g in new_galleries:
                                gallery = gallerydb.Gallery()
                                try:
                                    gallery.profile = utils.get_gallery_img(g[0])
                                except:
                                    gallery.profile = gui_constants.NO_IMAGE_PATH
                                parser_dict = utils.title_parser(os.path.split(case_path[g[1]])[1])
                                gallery.title = parser_dict["title"]
                                gallery.artist = parser_dict["artist"]
                                galleries.append(gallery)
                                final_paths.append(case_path[g[1]])
                        self.final_paths_and_galleries.emit(final_paths, galleries)
                        # if gui_constants.LOOK_NEW_GALLERY_AUTOADD:
                        # 	QTimer.singleShot(10000, self.gallery_populate(final_paths))
                        # 	return

                def show_new_galleries(final_paths, galleries):
                    if final_paths and galleries:
                        if gui_constants.LOOK_NEW_GALLERY_AUTOADD:
                            self.gallery_populate(final_paths)
                        else:
                            if len(galleries) == 1:
                                self.notification_bar.add_text(
                                    "{} new gallery was discovered in one of your monitored directories".format(
                                        len(galleries)
                                    )
                                )
                            else:
                                self.notification_bar.add_text(
                                    "{} new galleries were discovered in one of your monitored directories".format(
                                        len(galleries)
                                    )
                                )
                            text = (
                                "These new galleries were discovered! Do you want to add them?"
                                if len(galleries) > 1
                                else "This new gallery was discovered! Do you want to add it?"
                            )
                            g_popup = file_misc.GalleryPopup((text, galleries), self)
                            buttons = g_popup.add_buttons("Add", "Close")

                            def populate_n_close():
                                self.gallery_populate(final_paths)
                                g_popup.close()

                            buttons[0].clicked.connect(populate_n_close)
                            buttons[1].clicked.connect(g_popup.close)

                thread = QThread(self)
                self.scan_inst = ScanDir(self.manga_list_view.gallery_model._data)
                self.scan_inst.moveToThread(thread)
                self.scan_inst.final_paths_and_galleries.connect(show_new_galleries)
                self.scan_inst.final_paths_and_galleries.connect(lambda a: self.scan_inst.deleteLater())
                thread.started.connect(self.scan_inst.scan_dirs)
                thread.finished.connect(thread.deleteLater)
                thread.start()
            except:
                self.notification_bar.add_text(
                    "An error occured while attempting to scan for new galleries. Check happypanda.log."
                )
                log.exception("An error occured while attempting to scan for new galleries.")

    def start_up(self):
        def normalize_first_time():
            settings.set(2, "Application", "first time level")

        def done():
            self.manga_list_view.gallery_model.init_data()
            if gui_constants.ENABLE_MONITOR and gui_constants.MONITOR_PATHS and all(gui_constants.MONITOR_PATHS):
                self.init_watchers()
            if gui_constants.FIRST_TIME_LEVEL != 2:
                normalize_first_time()

        if gui_constants.FIRST_TIME_LEVEL < 2:

            class FirstTime(file_misc.BasePopup):
                def __init__(self, parent=None):
                    super().__init__(parent)
                    main_layout = QVBoxLayout()
                    info_lbl = QLabel(
                        "Hi there! Some big changes are about to occur!\n"
                        + "Please wait.. This will take at most a few minutes.\n"
                        + "If not then try restarting the application."
                    )
                    info_lbl.setAlignment(Qt.AlignCenter)
                    main_layout.addWidget(info_lbl)
                    prog = QProgressBar(self)
                    prog.setMinimum(0)
                    prog.setMaximum(0)
                    prog.setTextVisible(False)
                    main_layout.addWidget(prog)
                    main_layout.addWidget(QLabel("Note: This popup will close itself when everything is ready"))
                    self.main_widget.setLayout(main_layout)

            ft_widget = FirstTime(self)
            log_i("Invoking first time level 2")
            bridge = gallerydb.Bridge()
            thread = QThread(self)
            thread.setObjectName("Startup")
            bridge.moveToThread(thread)
            thread.started.connect(bridge.rebuild_galleries)
            bridge.DONE.connect(ft_widget.close)
            bridge.DONE.connect(self.setEnabled)
            bridge.DONE.connect(done)
            bridge.DONE.connect(bridge.deleteLater)
            thread.finished.connect(thread.deleteLater)
            thread.start()
            ft_widget.adjustSize()
            ft_widget.show()
            self.setEnabled(False)
        else:
            done()

    def initUI(self):
        self.center = QWidget()
        self.display = QStackedLayout()
        self.center.setLayout(self.display)
        # init the manga view variables
        self.manga_display()
        log_d("Create manga display: OK")
        # init the chapter view variables
        # self.chapter_display()
        self.m_l_view_index = self.display.addWidget(self.manga_list_main)
        self.m_t_view_index = self.display.addWidget(self.manga_table_view)
        # init toolbar
        self.init_toolbar()
        log_d("Create toolbar: OK")
        # init status bar
        self.init_stat_bar()
        log_d("Create statusbar: OK")

        self.system_tray = misc.SystemTray(QIcon(gui_constants.APP_ICO_PATH), self)
        gui_constants.SYSTEM_TRAY = self.system_tray
        tray_menu = QMenu(self)
        self.system_tray.setContextMenu(tray_menu)
        self.system_tray.setToolTip("Happypanda {}".format(gui_constants.vs))
        tray_quit = QAction("Quit", tray_menu)
        tray_menu.addAction(tray_quit)
        tray_quit.triggered.connect(self.close)
        self.system_tray.show()
        log_d("Create system tray: OK")

        # self.display.addWidget(self.chapter_main)

        self.setCentralWidget(self.center)
        self.setWindowTitle("Happypanda")
        self.setWindowIcon(QIcon(gui_constants.APP_ICO_PATH))

        props = settings.win_read(self, "AppWindow")
        if props.resize:
            x, y = props.resize
            self.resize(x, y)
        else:
            self.resize(gui_constants.MAIN_W, gui_constants.MAIN_H)
        posx, posy = props.pos
        self.move(posx, posy)
        self.show()
        log_d("Show window: OK")

        self.notification_bar = misc.NotificationOverlay(self)
        p = self.toolbar.pos()
        self.notification_bar.move(p.x(), p.y() + self.toolbar.height())
        self.notification_bar.resize(self.width())
        gui_constants.NOTIF_BAR = self.notification_bar
        log_d("Create notificationbar: OK")

        log_d("Window Create: OK")

    def _check_update(self):
        class upd_chk(QObject):
            UPDATE_CHECK = pyqtSignal(str)

            def __init__(self, **kwargs):
                super().__init__(**kwargs)

            def fetch_vs(self):
                import requests
                import time

                try:
                    log_d("Checking Update")
                    time.sleep(1.5)
                    r = requests.get(
                        "https://raw.githubusercontent.com/Pewpews/happypanda/master/VS.txt", verify="cacert.pem"
                    )
                    a = r.text
                    vs = a.strip()
                    self.UPDATE_CHECK.emit(vs)
                except:
                    log.exception("Checking Update: FAIL")
                    self.UPDATE_CHECK.emit("this is a very long text which is is sure to be over limit")

        def check_update(vs):
            log_i("Received version: {}\nCurrent version: {}".format(vs, gui_constants.vs))
            if vs != gui_constants.vs:
                if len(vs) < 10:
                    self.notification_bar.add_text(
                        "Version {} of Happypanda is".format(vs) + " available. Click here to update!", False
                    )
                    self.notification_bar.clicked.connect(
                        lambda: utils.open_web_link("https://github.com/Pewpews/happypanda/releases")
                    )
                    self.notification_bar.set_clickable(True)
                else:
                    self.notification_bar.add_text("An error occurred while checking for new version")

        self.update_instance = upd_chk()
        thread = QThread(self)
        self.update_instance.moveToThread(thread)
        thread.started.connect(self.update_instance.fetch_vs)
        self.update_instance.UPDATE_CHECK.connect(check_update)
        self.update_instance.UPDATE_CHECK.connect(self.update_instance.deleteLater)
        thread.finished.connect(thread.deleteLater)
        thread.start()

    def _web_metadata_picker(self, gallery, title_url_list, queue, parent=None):
        if not parent:
            parent = self
        text = "Which gallery do you want to extract metadata from?"
        s_gallery_popup = misc.SingleGalleryChoices(gallery, title_url_list, text, parent)
        s_gallery_popup.USER_CHOICE.connect(queue.put)

    def get_metadata(self, gal=None):
        thread = QThread(self)
        thread.setObjectName("App.get_metadata")
        fetch_instance = fetch.Fetch()
        if gal:
            galleries = [gal]
        else:
            if gui_constants.CONTINUE_AUTO_METADATA_FETCHER:
                galleries = [g for g in self.manga_list_view.gallery_model._data if not g.exed]
            else:
                galleries = self.manga_list_view.gallery_model._data
            if not galleries:
                self.notification_bar.add_text("Looks like we've already gone through all galleries!")
                return None
        fetch_instance.galleries = galleries

        self.notification_bar.begin_show()
        fetch_instance.moveToThread(thread)

        def done(status):
            self.notification_bar.end_show()
            fetch_instance.deleteLater()

        fetch_instance.GALLERY_PICKER.connect(self._web_metadata_picker)
        fetch_instance.GALLERY_EMITTER.connect(self.manga_list_view.replace_edit_gallery)
        fetch_instance.AUTO_METADATA_PROGRESS.connect(self.notification_bar.add_text)
        thread.started.connect(fetch_instance.auto_web_metadata)
        fetch_instance.FINISHED.connect(done)
        thread.finished.connect(thread.deleteLater)
        thread.start()

        # def style_tooltip(self):
        # 	palette = QToolTip.palette()
        # 	palette.setColor()

    def init_stat_bar(self):
        self.status_bar = self.statusBar()
        self.status_bar.setMaximumHeight(20)
        self.status_bar.setSizeGripEnabled(False)
        self.stat_info = QLabel()
        self.stat_info.setIndent(5)
        self.sort_main = QAction("Asc", self)
        sort_menu = QMenu()
        self.sort_main.setMenu(sort_menu)
        s_by_title = QAction("Title", sort_menu)
        s_by_artist = QAction("Artist", sort_menu)
        sort_menu.addAction(s_by_title)
        sort_menu.addAction(s_by_artist)
        self.status_bar.addPermanentWidget(self.stat_info)
        # self.status_bar.addAction(self.sort_main)
        self.temp_msg = QLabel()
        self.temp_timer = QTimer()

        self.manga_list_view.gallery_model.ROWCOUNT_CHANGE.connect(self.stat_row_info)
        self.manga_list_view.gallery_model.STATUSBAR_MSG.connect(self.stat_temp_msg)
        self.manga_list_view.STATUS_BAR_MSG.connect(self.stat_temp_msg)
        self.manga_table_view.STATUS_BAR_MSG.connect(self.stat_temp_msg)
        self.stat_row_info()

    def stat_temp_msg(self, msg):
        self.temp_timer.stop()
        self.temp_msg.setText(msg)
        self.status_bar.addWidget(self.temp_msg)
        self.temp_timer.timeout.connect(self.temp_msg.clear)
        self.temp_timer.setSingleShot(True)
        self.temp_timer.start(5000)

    def stat_row_info(self):
        r = self.manga_list_view.model().rowCount()
        t = self.manga_list_view.gallery_model._data_count
        self.stat_info.setText("Loaded {} of {} ".format(r, t))

    def manga_display(self):
        "initiates the manga view"
        # list view
        self.manga_list_main = QWidget()
        # self.manga_list_main.setContentsMargins(-10, -12, -10, -10)
        self.manga_list_main.setContentsMargins(10, -9, -10, -10)  # x, y, inverted_width, inverted_height
        self.manga_list_layout = QHBoxLayout()
        self.manga_list_main.setLayout(self.manga_list_layout)

        self.manga_list_view = gallery.MangaView(self)
        self.manga_list_view.clicked.connect(self.popup)
        self.manga_list_view.manga_delegate.POPUP.connect(self.popup)
        self.popup_window = self.manga_list_view.manga_delegate.popup_window
        self.manga_list_layout.addWidget(self.manga_list_view)

        # table view
        self.manga_table_main = QWidget()
        self.manga_table_layout = QVBoxLayout()
        self.manga_table_main.setLayout(self.manga_table_layout)

        self.manga_table_view = gallery.MangaTableView(self)
        self.manga_table_view.gallery_model = self.manga_list_view.gallery_model
        self.manga_table_view.sort_model = self.manga_list_view.sort_model
        self.manga_table_view.setModel(self.manga_table_view.sort_model)
        self.manga_table_view.sort_model.change_model(self.manga_table_view.gallery_model)
        self.manga_table_view.setColumnWidth(gui_constants.FAV, 20)
        self.manga_table_view.setColumnWidth(gui_constants.ARTIST, 200)
        self.manga_table_view.setColumnWidth(gui_constants.TITLE, 400)
        self.manga_table_view.setColumnWidth(gui_constants.TAGS, 300)
        self.manga_table_view.setColumnWidth(gui_constants.TYPE, 60)
        self.manga_table_view.setColumnWidth(gui_constants.CHAPTERS, 60)
        self.manga_table_view.setColumnWidth(gui_constants.LANGUAGE, 100)
        self.manga_table_view.setColumnWidth(gui_constants.LINK, 400)
        self.manga_table_layout.addWidget(self.manga_table_view)

    def search(self, srch_string):
        case_ins = srch_string.lower()
        if not gui_constants.ALLOW_SEARCH_REGEX:
            remove = "^$*+?{}\\|()[]"
            for x in remove:
                if x == "[" or x == "]":
                    continue
                else:
                    case_ins = case_ins.replace(x, ".")
        else:
            try:
                re.compile(case_ins)
            except re.error:
                return
        self.manga_list_view.sort_model.search(case_ins)

    def popup(self, index):
        if not self.popup_window.isVisible():
            m_x = QCursor.pos().x()
            m_y = QCursor.pos().y()
            d_w = QDesktopWidget().width()
            d_h = QDesktopWidget().height()
            p_w = gui_constants.POPUP_WIDTH
            p_h = gui_constants.POPUP_HEIGHT

            index_rect = self.manga_list_view.visualRect(index)
            index_point = self.manga_list_view.mapToGlobal(index_rect.topRight())
            # adjust so it doesn't go offscreen
            if d_w - m_x < p_w and d_h - m_y < p_h:  # bottom
                self.popup_window.move(m_x - p_w + 5, m_y - p_h)
            elif d_w - m_x > p_w and d_h - m_y < p_h:
                self.popup_window.move(m_x + 5, m_y - p_h)
            elif d_w - m_x < p_w:
                self.popup_window.move(m_x - p_w + 5, m_y + 5)
            else:
                self.popup_window.move(index_point)

            self.popup_window.set_gallery(index.data(Qt.UserRole + 1))
            self.popup_window.show()

    def favourite_display(self):
        "Switches to favourite display"
        if self.display.currentIndex() == self.m_l_view_index:
            self.manga_list_view.sort_model.fav_view()
        else:
            self.manga_table_view.sort_model.fav_view()

    def catalog_display(self):
        "Switches to catalog display"
        if self.display.currentIndex() == self.m_l_view_index:
            self.manga_list_view.sort_model.catalog_view()
        else:
            self.manga_table_view.sort_model.catalog_view()

    def settings(self):
        sett = settingsdialog.SettingsDialog(self)
        sett.scroll_speed_changed.connect(self.manga_list_view.updateGeometries)
        # sett.show()

    def init_toolbar(self):
        self.toolbar = QToolBar()
        self.toolbar.setFixedHeight(25)
        self.toolbar.setWindowTitle("Show")  # text for the contextmenu
        # self.toolbar.setStyleSheet("QToolBar {border:0px}") # make it user defined?
        self.toolbar.setMovable(False)
        self.toolbar.setFloatable(False)
        # self.toolbar.setIconSize(QSize(20,20))
        self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)

        spacer_start = QWidget()  # aligns the first actions properly
        spacer_start.setFixedSize(QSize(10, 1))
        self.toolbar.addWidget(spacer_start)

        favourite_view_icon = QIcon(gui_constants.STAR_BTN_PATH)
        favourite_view_action = QAction(favourite_view_icon, "Favorites", self)
        favourite_view_action.setToolTip("Show only favourite galleries")
        favourite_view_action.triggered.connect(self.favourite_display)  # need lambda to pass extra args
        self.toolbar.addAction(favourite_view_action)

        catalog_view_icon = QIcon(gui_constants.HOME_BTN_PATH)
        catalog_view_action = QAction(catalog_view_icon, "Library", self)
        catalog_view_action.setToolTip("Show all your galleries")
        # catalog_view_action.setText("Catalog")
        catalog_view_action.triggered.connect(self.catalog_display)  # need lambda to pass extra args
        self.toolbar.addAction(catalog_view_action)
        self.toolbar.addSeparator()

        gallery_menu = QMenu()
        gallery_action = QToolButton()
        gallery_action.setText("Gallery ")
        gallery_action.setPopupMode(QToolButton.InstantPopup)
        gallery_action.setToolTip("Contains various gallery related features")
        gallery_action.setMenu(gallery_menu)
        add_gallery_icon = QIcon(gui_constants.PLUS_PATH)
        gallery_action_add = QAction(add_gallery_icon, "Add gallery", self)
        gallery_action_add.triggered.connect(self.manga_list_view.SERIES_DIALOG.emit)
        gallery_action_add.setToolTip("Add a single gallery thoroughly")
        gallery_menu.addAction(gallery_action_add)
        add_more_action = QAction(add_gallery_icon, "Add galleries...", self)
        add_more_action.setStatusTip("Add galleries from different folders")
        add_more_action.triggered.connect(lambda: self.populate(True))
        gallery_menu.addAction(add_more_action)
        populate_action = QAction(add_gallery_icon, "Populate from folder...", self)
        populate_action.setStatusTip("Populates the DB with galleries from a single folder")
        populate_action.triggered.connect(self.populate)
        gallery_menu.addAction(populate_action)
        gallery_menu.addSeparator()
        metadata_action = QAction("Get metadata for all galleries", self)
        metadata_action.triggered.connect(self.get_metadata)
        gallery_menu.addAction(metadata_action)
        self.toolbar.addWidget(gallery_action)
        self.toolbar.addSeparator()

        misc_action = QToolButton()
        misc_action.setText("Misc ")
        misc_action_menu = QMenu()
        misc_action.setMenu(misc_action_menu)
        misc_action.setPopupMode(QToolButton.InstantPopup)
        misc_action.setToolTip("Contains misc. features")
        misc_action_random = QAction("Open random gallery", misc_action_menu)
        misc_action_random.triggered.connect(self.manga_list_view.open_random_gallery)
        misc_action_menu.addAction(misc_action_random)
        duplicate_check_simple = QAction("Simple duplicate finder", misc_action_menu)
        duplicate_check_simple.triggered.connect(lambda: self.manga_list_view.duplicate_check())
        misc_action_menu.addAction(duplicate_check_simple)
        self.toolbar.addWidget(misc_action)

        spacer_middle = QWidget()  # aligns buttons to the right
        spacer_middle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.toolbar.addWidget(spacer_middle)

        self.grid_toggle_g_icon = QIcon(gui_constants.GRID_PATH)
        self.grid_toggle_l_icon = QIcon(gui_constants.LIST_PATH)
        self.grid_toggle = QToolButton()
        if self.display.currentIndex() == self.m_l_view_index:
            self.grid_toggle.setIcon(self.grid_toggle_l_icon)
        else:
            self.grid_toggle.setIcon(self.grid_toggle_g_icon)
        self.grid_toggle.setObjectName("gridtoggle")
        self.grid_toggle.clicked.connect(self.toggle_view)
        self.toolbar.addWidget(self.grid_toggle)

        self.search_bar = misc.LineEdit()
        if gui_constants.SEARCH_AUTOCOMPLETE:
            completer = QCompleter(self)
            completer.setModel(self.manga_list_view.gallery_model)
            completer.setCaseSensitivity(Qt.CaseInsensitive)
            completer.setCompletionMode(QCompleter.PopupCompletion)
            completer.setCompletionRole(Qt.DisplayRole)
            completer.setCompletionColumn(gui_constants.TITLE)
            completer.setFilterMode(Qt.MatchContains)
            self.search_bar.setCompleter(completer)
        if gui_constants.SEARCH_ON_ENTER:
            self.search_bar.returnPressed.connect(lambda: self.search(self.search_bar.text()))
        else:
            self.search_bar.textChanged[str].connect(self.search)
        self.search_bar.setPlaceholderText("Search title, artist, namespace & tags")
        self.search_bar.setMinimumWidth(150)
        self.search_bar.setMaximumWidth(500)
        self.toolbar.addWidget(self.search_bar)
        self.toolbar.addSeparator()
        settings_icon = QIcon(gui_constants.SETTINGS_PATH)
        settings_action = QAction("Set&tings", self)
        settings_action.triggered.connect(self.settings)
        self.toolbar.addAction(settings_action)

        spacer_end = QWidget()  # aligns About action properly
        spacer_end.setFixedSize(QSize(10, 1))
        self.toolbar.addWidget(spacer_end)
        self.addToolBar(self.toolbar)

    def toggle_view(self):
        """
		Toggles the current display view
		"""
        if self.display.currentIndex() == self.m_l_view_index:
            self.display.setCurrentIndex(self.m_t_view_index)
            self.grid_toggle.setIcon(self.grid_toggle_g_icon)
        else:
            self.display.setCurrentIndex(self.m_l_view_index)
            self.grid_toggle.setIcon(self.grid_toggle_l_icon)

            # TODO: Improve this so that it adds to the gallery dialog,
            # so user can edit data before inserting (make it a choice)

    def populate(self, mixed=None):
        "Populates the database with gallery from local drive'"
        if mixed:
            gallery_view = misc.GalleryListView(self, True)
            gallery_view.SERIES.connect(self.gallery_populate)
            gallery_view.show()
        else:
            path = QFileDialog.getExistingDirectory(None, "Choose a folder containing your galleries")
            self.gallery_populate(path, True)

    def gallery_populate(self, path, validate=False):
        "Scans the given path for gallery to add into the DB"
        if len(path) is not 0:
            data_thread = QThread(self)
            data_thread.setObjectName("General gallery populate")
            loading = misc.Loading(self)
            if not loading.ON:
                misc.Loading.ON = True
                fetch_instance = fetch.Fetch()
                fetch_instance.series_path = path
                loading.show()

                def finished(status):
                    def hide_loading():
                        loading.hide()

                    if status:
                        if len(status) != 0:

                            def add_gallery(gallery_list):
                                def append_to_model(x):
                                    self.manga_list_view.gallery_model.insertRows(x, None, len(x))

                                class A(QObject):
                                    done = pyqtSignal()
                                    prog = pyqtSignal(int)

                                    def __init__(self, obj, parent=None):
                                        super().__init__(parent)
                                        self.obj = obj
                                        self.galleries = []

                                    def add_to_db(self):
                                        gui_constants.NOTIF_BAR.begin_show()
                                        gui_constants.NOTIF_BAR.add_text("Populating database...")
                                        for y, x in enumerate(self.obj):
                                            gui_constants.NOTIF_BAR.add_text(
                                                "Populating database {}/{}".format(y + 1, len(self.obj))
                                            )
                                            gallerydb.add_method_queue(gallerydb.GalleryDB.add_gallery_return, False, x)
                                            self.galleries.append(x)
                                            y += 1
                                            self.prog.emit(y)
                                        append_to_model(self.galleries)
                                        gui_constants.NOTIF_BAR.end_show()
                                        self.done.emit()

                                loading.progress.setMaximum(len(gallery_list))
                                a_instance = A(gallery_list)
                                thread = QThread(self)
                                thread.setObjectName("Database populate")

                                def loading_show():
                                    loading.setText("Populating database.\nPlease wait...")
                                    loading.show()

                                def loading_hide():
                                    loading.close()
                                    self.manga_list_view.gallery_model.ROWCOUNT_CHANGE.emit()

                                def del_later():
                                    try:
                                        a_instance.deleteLater()
                                    except NameError:
                                        pass

                                a_instance.moveToThread(thread)
                                a_instance.prog.connect(loading.progress.setValue)
                                thread.started.connect(loading_show)
                                thread.started.connect(a_instance.add_to_db)
                                a_instance.done.connect(loading_hide)
                                a_instance.done.connect(del_later)
                                thread.finished.connect(thread.deleteLater)
                                thread.start()

                            data_thread.quit
                            hide_loading()
                            log_i("Populating DB from gallery folder: OK")
                            if validate:
                                gallery_list = misc.GalleryListView(self)
                                gallery_list.SERIES.connect(add_gallery)
                                for ser in status:
                                    gallery_list.add_gallery(ser, os.path.split(ser.path)[1])
                                    # self.manga_list_view.gallery_model.populate_data()
                                gallery_list.show()
                            else:
                                add_gallery(status)
                            misc.Loading.ON = False
                        else:
                            log_d("No new gallery was found")
                            loading.setText("No new gallery found")
                            data_thread.quit
                            misc.Loading.ON = False

                    else:
                        log_e("Populating DB from gallery folder: Nothing was added!")
                        loading.setText("<font color=red>Nothing was added. Check happypanda_log for details..</font>")
                        loading.progress.setStyleSheet("background-color:red;")
                        data_thread.quit
                        QTimer.singleShot(10000, loading.close)

                def fetch_deleteLater():
                    try:
                        fetch_instance.deleteLater
                    except NameError:
                        pass

                def a_progress(prog):
                    loading.progress.setValue(prog)
                    loading.setText("Searching for galleries...")

                fetch_instance.moveToThread(data_thread)
                fetch_instance.DATA_COUNT.connect(loading.progress.setMaximum)
                fetch_instance.PROGRESS.connect(a_progress)
                data_thread.started.connect(fetch_instance.local)
                fetch_instance.FINISHED.connect(finished)
                fetch_instance.FINISHED.connect(fetch_deleteLater)
                data_thread.finished.connect(data_thread.deleteLater)
                data_thread.start()
                log_i("Populating DB from gallery folder")

    def resizeEvent(self, event):
        try:
            self.notification_bar.resize(event.size().width())
        except AttributeError:
            pass
        return super().resizeEvent(event)

    def closeEvent(self, event):
        # watchers
        try:
            self.watchers.stop_all()
        except AttributeError:
            pass

            # settings
        settings.set(self.manga_list_view.current_sort, "General", "current sort")
        settings.win_save(self, "AppWindow")

        # temp dir
        try:
            for root, dirs, files in os.walk("temp", topdown=False):
                for name in files:
                    os.remove(os.path.join(root, name))
                for name in dirs:
                    os.rmdir(os.path.join(root, name))
            log_d("Empty temp on exit: OK")
        except:
            log_d("Empty temp on exit: FAIL")

            # error
        err = sys.exc_info()
        if all(err):
            log_c("Last error before exit:\n{}\n{}\n{}".format(err[0], err[1], err[2]))
        else:
            log_d("Normal Exit App: OK")
        super().closeEvent(event)
        app = QApplication.instance()
        app.quit()
        sys.exit()
Пример #27
0
class _MainContainer(QWidget):

###############################################################################
# MainContainer SIGNALS
###############################################################################
    """
    newFileOpened(QString)
    allTabClosed()
    runFile(QString)
    addToProject(QString)
    showFileInExplorer(QString)
    recentTabsModified()
    currentEditorChanged(QString)
    fileOpened(QString)
    ---------migrationAnalyzed()
    findOcurrences(QString)
    ---------updateFileMetadata()
    editorKeyPressEvent(QEvent)
    locateFunction(QString, QString, bool) [functionName, filePath, isVariable]
    updateLocator(QString)
    beforeFileSaved(QString)
    fileSaved(QString)
    openPreferences()
    --------openProject(QString)
    ---------dontOpenStartPage()
    """
    newFileOpened = pyqtSignal(str)
    allTabClosed = pyqtSignal()
    runFile = pyqtSignal(str)
    addToProject = pyqtSignal(str)
    showFileInExplorer = pyqtSignal(str)
    recentTabsModified = pyqtSignal()
    currentEditorChanged = pyqtSignal(str)
    fileOpened = pyqtSignal(str)
    migrationAnalyzed = pyqtSignal()#-----------
    findOcurrences = pyqtSignal(str)
    updateFileMetadata = pyqtSignal()#-----------
    editorKeyPressEvent = pyqtSignal('QEvent*')
    locateFunction = pyqtSignal(str, str, bool)
    updateLocator = pyqtSignal(str)
    beforeFileSaved = pyqtSignal(str)
    fileSaved = pyqtSignal(str)
    openPreferences = pyqtSignal()
    openProject = pyqtSignal(str)#-----------
    dontOpenStartPage = pyqtSignal()#-----------
    closeDialog = pyqtSignal('QObject*')
    allTabsClosed = pyqtSignal()
    splitEditor = pyqtSignal('QWidget*', 'QWidget*', bool)
    closeSplit = pyqtSignal(QWidget)
    toRemovePreview = pyqtSignal()

###############################################################################

    def __init__(self, parent=None):
        super(_MainContainer, self).__init__(parent)
        self._parent = parent
        self._vbox = QVBoxLayout(self)
        self._vbox.setContentsMargins(0, 0, 0, 0)
        self._vbox.setSpacing(0)
        self.stack = QStackedLayout()
        self.stack.setStackingMode(QStackedLayout.StackAll)
        self._vbox.addLayout(self.stack)

        self.splitter = dynamic_splitter.DynamicSplitter()
        self.setAcceptDrops(True)
        # self._files_handler = files_handler.FilesHandler(self)
        self._add_file_folder = add_file_folder.AddFileFolderWidget(self)

        self.tdir = None

        #documentation browser
        self.docPage = None
        #Code Navigation
        self._locator = locator.GoToDefinition()
        self.__codeBack = []
        self.__codeForward = []
        self.__bookmarksFile = ''
        self.__bookmarksPos = -1
        self.__breakpointsFile = ''
        self.__breakpointsPos = -1
        self.__operations = {
            0: self._navigate_code_jumps,
            1: self._navigate_bookmarks,
            2: self._navigate_breakpoints}

        self.locateFunction.connect(self.locate_function)

        IDE.register_service('main_container', self)

        #Register signals connections
        connections = (
            {'target': 'menu_file',
             'signal_name': 'openFile',#(QString)
             'slot': self.open_file},
            {'target': 'explorer_container',
             'signal_name': 'goToDefinition',#(int)
             'slot': self.editor_go_to_line},
            {'target': 'explorer_container',
             'signal_name': 'pep8Activated',#(bool)
             'slot': self.reset_pep8_warnings},
            {'target': 'explorer_container',
             'signal_name': 'lintActivated',#(bool)
             'slot': self.reset_lint_warnings},
            )

        IDE.register_signals('main_container', connections)

        self.selector = main_selector.MainSelector(self)
        self._opening_dialog = False
        self.add_widget(self.selector)

        if settings.SHOW_START_PAGE:
            self.show_start_page()

        self.selector.changeCurrent[int].connect(self._change_current_stack)
        self.selector.removeWidget[int].connect(self._remove_item_from_stack)
        self.selector.ready.connect(self._selector_ready)
        self.selector.closePreviewer.connect(self._selector_Close)
        self.selector.animationCompleted.connect(self._selector_animation_completed)

        self.closeDialog.connect(self.remove_widget)
        self.stack.widgetRemoved[int].connect(lambda i:print("widgetRemoved._-", i))

    def install(self):
        ide = IDE.getInstance()
        ide.place_me_on("main_container", self, "central", top=True)

        self.combo_area = combo_editor.ComboEditor(original=True)
        self.combo_area.allFilesClosed.connect(self._files_closed)
        self.splitter.add_widget(self.combo_area)
        self.add_widget(self.splitter)

        self.current_widget = self.combo_area

        ui_tools.install_shortcuts(self, actions.ACTIONS, ide)

    def add_status_bar(self, status):
        self._vbox.addWidget(status)

    @property
    def combo_header_size(self):
        return self.combo_area.bar.height()

    def add_widget(self, widget):
        i = self.stack.addWidget(widget)
        #if not isinstance(widget, start_page.StartPage):
        self.tryMakeImagePreview(i)

    def remove_widget(self, widget):
        #self.toRemovePreview.emit(self.stack.widget(widget))
        self.stack.removeWidget(widget)

    def _close_dialog(self, widget):
        self.closeDialog.emit(widget)
        widget.finished[int].disconnect()#lambda i: self._close_dialog(widget))

    def show_dialog(self, widget):
        print("\n\nshow_dialog", self.isVisible())
        self._opening_dialog = True
        widget.finished[int].connect(lambda i: self._close_dialog(widget))
        widget.setVisible(True)
        self.show_selector()

    def show_selector(self):
        print("\n\nshow_selector::", self.selector, self.stack.currentWidget())
        if self.selector != self.stack.currentWidget():
            _dir = self.Successful_Tmp()
            if not _dir:
                print("failed!")
                return

            # temp_dir = os.path.join(QDir.tempPath(), "ninja-ide")
            # if not os.path.exists(temp_dir):
            #     os.mkdir(temp_dir)
            collected_data = []
            current = self.stack.currentIndex()
            for index in range(self.stack.count()):
                widget = self.stack.widget(index)
                if widget == self.selector:
                    continue
                closable = True
                if widget == self.splitter:
                    closable = False
                # path = os.path.join(temp_dir, "screen%s.png" % index)
                #ff = QFile(_dir, "screen%s.png" % index)
                path = _dir.absolutePath()+"/screen%s.png" % index
                pixmap = widget.grab()#widget.rect())
                pixmap.save(path)
                #path = path.replace("\\", '/')
                #print("path::", path, QFileInfo(path).exists())
                path = "file:///"+path
                if index == current:
                    self.selector.set_preview(index, path)#QUrl(path)
                    collected_data.insert(0, (index, path, closable))
                else:
                    collected_data.append((index, path, closable))
            self.selector.set_model(collected_data)
            print("self.selector.set_model()", collected_data)
            self.stack.setCurrentWidget(self.selector)
        else:
            print("\n\n_selector_Close()")
            self._selector_Close()

    def Successful_Tmp(self):# CheckTmpDir, StateTmpDir
        failed = lambda: not self.tdir or not self.tdir.isValid()
        if failed():# not successfully
            self.tdir = QTemporaryDir()
            if failed():
                QMessageBox.critical(self, "Unexpected Failurer", "The application has detected a problem trying to\nCreate or Access a Temporary File!.")
                return None
            else:
                self.tdir.setAutoRemove(True)

        d = QDir(self.tdir.path())
        if not d.exists("ninja-ide"):
            if not d.mkdir("ninja-ide"):
                self.tdir = None
        d.cd("ninja-ide")
        return d

    def tryMakeImagePreview(self, index):
        return
        d = self.Successful_Tmp()
        if d:
            self.makeImagePreview(d, index)

    def makeImagePreview(self, _dir, index):
        return
        path = _dir.absolutePath()+"/screen%s.png" % index
        widget = self.stack.widget(index)
        pixmap = widget.grab()#widget.rect()
        pixmap.save(path)

    def _selector_ready(self):
        self.stack.setCurrentWidget(self.selector)
        self.selector.GoTo_GridPreviews()

    def _selector_Close(self):
        self.stack.setCurrentWidget(self.splitter)

    def _selector_animation_completed(self):
        if self._opening_dialog:
            # We choose the last one with -2, -1 (for last one) +
            # -1 for the hidden selector widget which is in the stacked too.
            self.selector.open_item(self.stack.count() - 2)
        self._opening_dialog = False

    def _change_current_stack(self, index):
        self.stack.setCurrentIndex(index)

    def _remove_item_from_stack(self, index):
        #self.toRemovePreview.emit(index)
        widget = self.stack.takeAt(index)
        del widget

    def show_editor_area(self):
        self.stack.setCurrentWidget(self.splitter)

    def _files_closed(self):
        if settings.SHOW_START_PAGE:
            self.show_start_page()

    def change_visibility(self):
        """Show/Hide the Main Container area."""
        print("change_visibility11")
        if self.isVisible():
            self.hide()
        else:
            self.show()

    def expand_symbol_combo(self):
        self.stack.setCurrentWidget(self.splitter)
        self.current_widget.show_combo_symbol()

    def expand_file_combo(self):
        print("expand_file_combo")
        self.stack.setCurrentWidget(self.splitter)
        self.current_widget.show_combo_file()

    def locate_function(self, function, filePath, isVariable):
        """Move the cursor to the proper position in the navigate stack."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            self.__codeBack.append((editorWidget.file_path,
                                   editorWidget.getCursorPosition()))
            self.__codeForward = []
        self._locator.navigate_to(function, filePath, isVariable)

    def run_file(self, path):
        self.runFile.emit(path)

    def _add_to_project(self, path):
        self.addToProject.emit(path)

    def _show_file_in_explorer(self, path):
        self.showFileInExplorer.emit(path)

    def paste_history(self):
        """Paste the text from the copy/paste history."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            line, index = editorWidget.getCursorPosition()
            central = IDE.get_service('central_container')
            if central:
                editorWidget.insertAt(central.get_paste(), line, index)

    def copy_history(self):
        """Copy the selected text into the copy/paste history."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            copy = editorWidget.selectedText()
            central = IDE.get_service('central_container')
            if central:
                central.add_copy(copy)

    def import_from_everywhere(self):
        """Insert an import line from any place in the editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            dialog = from_import_dialog.FromImportDialog(editorWidget, self)
            dialog.show()

    def add_back_item_navigation(self):
        """Add an item to the back stack and reset the forward stack."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            self.__codeBack.append((editorWidget.file_path,
                                   editorWidget.getCursorPosition()))
            self.__codeForward = []

    def preview_in_browser(self):
        """Load the current html file in the default browser."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            if not editorWidget.file_path:
                self.save_file()
            ext = file_manager.get_file_extension(editorWidget.file_path)
            if ext in ('html', 'shpaml', 'handlebars', 'tpl'):
                webbrowser.open_new_tab(editorWidget.file_path)

    def add_bookmark_breakpoint(self):
        """Add a bookmark or breakpoint to the current file in the editor."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            if self.current_widget.bar.code_navigator.operation == 1:
                editorWidget.handle_bookmarks_breakpoints(
                    editorWidget.getCursorPosition()[0], Qt.ControlModifier)
            elif self.current_widget.bar.code_navigator.operation == 2:
                editorWidget.handle_bookmarks_breakpoints(
                    editorWidget.getCursorPosition()[0], Qt.NoModifier)

    def __navigate_with_keyboard(self, val):
        """Navigate between the positions in the jump history stack."""
        op = self.current_widget.bar.code_navigator.operation
        self.navigate_code_history(val, op)

    def navigate_code_history(self, val, op):
        """Navigate the code history."""
        self.__operations[op](val)

    def _navigate_code_jumps(self, val):
        """Navigate between the jump points."""
        node = None
        if not val and self.__codeBack:
            node = self.__codeBack.pop()
            editorWidget = self.get_current_editor()
            if editorWidget:
                self.__codeForward.append((editorWidget.file_path,
                                          editorWidget.getCursorPosition()))
        elif val and self.__codeForward:
            node = self.__codeForward.pop()
            editorWidget = self.get_current_editor()
            if editorWidget:
                self.__codeBack.append((editorWidget.file_path,
                                       editorWidget.getCursorPosition()))
        if node:
            filename = node[0]
            line, col = node[1]
            self.open_file(filename, line, col)

    def _navigate_breakpoints(self, val):
        """Navigate between the breakpoints."""
        #FIXME: put navigate breakpoints and bookmarks as one method.
        breakList = list(settings.BREAKPOINTS.keys())
        breakList.sort()
        if not breakList:
            return
        if self.__breakpointsFile not in breakList:
            self.__breakpointsFile = breakList[0]
        index = breakList.index(self.__breakpointsFile)
        breaks = settings.BREAKPOINTS.get(self.__breakpointsFile, [])
        lineNumber = 0
        #val == True: forward
        if val:
            if (len(breaks) - 1) > self.__breakpointsPos:
                self.__breakpointsPos += 1
                lineNumber = breaks[self.__breakpointsPos]
            elif len(breaks) > 0:
                if index < (len(breakList) - 1):
                    self.__breakpointsFile = breakList[index + 1]
                else:
                    self.__breakpointsFile = breakList[0]
                self.__breakpointsPos = 0
                lineNumber = settings.BREAKPOINTS[self.__breakpointsFile][0]
        else:
            if self.__breakpointsPos > 0:
                self.__breakpointsPos -= 1
                lineNumber = breaks[self.__breakpointsPos]
            elif len(breaks) > 0:
                self.__breakpointsFile = breakList[index - 1]
                breaks = settings.BREAKPOINTS[self.__breakpointsFile]
                self.__breakpointsPos = len(breaks) - 1
                lineNumber = breaks[self.__breakpointsPos]
        if file_manager.file_exists(self.__breakpointsFile):
            self.open_file(self.__breakpointsFile, lineNumber, None, True)
        else:
            settings.BREAKPOINTS.pop(self.__breakpointsFile)
            if settings.BREAKPOINTS:
                self._navigate_breakpoints(val)

    def _navigate_bookmarks(self, val):
        """Navigate between the bookmarks."""
        bookList = list(settings.BOOKMARKS.keys())
        bookList.sort()
        if not bookList:
            return
        if self.__bookmarksFile not in bookList:
            self.__bookmarksFile = bookList[0]
        index = bookList.index(self.__bookmarksFile)
        bookms = settings.BOOKMARKS.get(self.__bookmarksFile, [])
        lineNumber = 0
        #val == True: forward
        if val:
            if (len(bookms) - 1) > self.__bookmarksPos:
                self.__bookmarksPos += 1
                lineNumber = bookms[self.__bookmarksPos]
            elif len(bookms) > 0:
                if index < (len(bookList) - 1):
                    self.__bookmarksFile = bookList[index + 1]
                else:
                    self.__bookmarksFile = bookList[0]
                self.__bookmarksPos = 0
                lineNumber = settings.BOOKMARKS[self.__bookmarksFile][0]
        else:
            if self.__bookmarksPos > 0:
                self.__bookmarksPos -= 1
                lineNumber = bookms[self.__bookmarksPos]
            elif len(bookms) > 0:
                self.__bookmarksFile = bookList[index - 1]
                bookms = settings.BOOKMARKS[self.__bookmarksFile]
                self.__bookmarksPos = len(bookms) - 1
                lineNumber = bookms[self.__bookmarksPos]
        if file_manager.file_exists(self.__bookmarksFile):
            self.open_file(self.__bookmarksFile,
                           lineNumber, None, True)
        else:
            settings.BOOKMARKS.pop(self.__bookmarksFile)
            if settings.BOOKMARKS:
                self._navigate_bookmarks(val)

    def count_file_code_lines(self):
        """Count the lines of code in the current file."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            block_count = editorWidget.lines()
            blanks = re.findall('(^\n)|(^(\s+)?#)|(^( +)?($|\n))',
                                editorWidget.text(), re.M)
            blanks_count = len(blanks)
            resume = self.tr("Lines code: %s\n") % (block_count - blanks_count)
            resume += (self.tr("Blanks and commented lines: %s\n\n") %
                       blanks_count)
            resume += self.tr("Total lines: %s") % block_count
            msgBox = QMessageBox(QMessageBox.Information,
                                 self.tr("Summary of lines"), resume,
                                 QMessageBox.Ok, editorWidget)
            msgBox.exec_()

    def editor_cut(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.cut()

    def editor_copy(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.copy()

    def editor_paste(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.paste()

    def editor_upper(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.to_upper()

    def editor_lower(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.to_lower()

    def editor_title(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.to_title()

    def editor_go_to_definition(self):
        """Search the definition of the method or variable under the cursor.

        If more than one method or variable is found with the same name,
        shows a table with the results and let the user decide where to go."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.go_to_definition()

    def editor_redo(self):
        """Execute the redo action in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.redo()

    def editor_undo(self):
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.undo()

    def editor_indent_less(self):
        """Indent 1 position to the left for the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.indent_less()

    def editor_indent_more(self):
        """Indent 1 position to the right for the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.indent_more()

    def editor_insert_debugging_prints(self):
        """Insert a print statement in each selected line."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.insert_debugging_prints(editorWidget)

    def editor_insert_pdb(self):
        """Insert a pdb.set_trace() statement in tjhe current line."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.insert_pdb(editorWidget)

    def editor_comment(self):
        """Mark the current line or selection as a comment."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.comment(editorWidget)

    def editor_uncomment(self):
        """Uncomment the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.uncomment(editorWidget)

    def editor_insert_horizontal_line(self):
        """Insert an horizontal lines of comment symbols."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.insert_horizontal_line(editorWidget)

    def editor_insert_title_comment(self):
        """Insert a Title surrounded by comment symbols."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.insert_title_comment(editorWidget)

    def editor_remove_trailing_spaces(self):
        """Remove the trailing spaces in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.remove_trailing_spaces(editorWidget)

    def editor_replace_tabs_with_spaces(self):
        """Replace the Tabs with Spaces in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.replace_tabs_with_spaces(editorWidget)

    def editor_move_up(self):
        """Move the current line or selection one position up."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.move_up(editorWidget)

    def editor_move_down(self):
        """Move the current line or selection one position down."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.move_down(editorWidget)

    def editor_remove_line(self):
        """Remove the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.remove_line(editorWidget)

    def editor_duplicate(self):
        """Duplicate the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.duplicate(editorWidget)

    def editor_highlight_word(self):
        """Highlight the occurrences of the current word in the editor."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.highlight_selected_word()

    def editor_complete_declaration(self):
        """Do the opposite action that Complete Declaration expect."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.complete_declaration()

    def editor_go_to_line(self, line, select=False):#def editor_go_to_line(self, line):
        """Jump to the specified line in the current editor."""
        editorWidget = self.get_current_editor()
        print("\nluego en segundo lugar por aca")
        if editorWidget:
            editorWidget.jump_to_line(line)#select

    def editor_go_to_symbol_line(self, line, sym= "", select=False):
        """Jump to the specified line in the current editor."""
        editorWidget = self.get_current_editor()
        print("\nluego en segundo lugar por aca")
        if editorWidget:
            editorWidget.go_to_symbol(line, sym, select)#select

    def zoom_in_editor(self):
        """Increase the font size in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.zoom_in()

    def zoom_out_editor(self):
        """Decrease the font size in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.zoom_out()

    def recent_files_changed(self):
        self.recentTabsModified.emit()

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        # file_path = event.mimeData().urls()[0].toLocalFile()
        # paths = [item.toLocalFile() for item in event.mimeData().urls()]
        self.open_files_fromUrlList(event.mimeData().urls())
        # print("\n\n dropEvent", paths)
        # self.open_file(file_path)

    def setFocus(self):
        widget = self.get_current_widget()
        if widget:
            widget.setFocus()

    def current_editor_changed(self, filename):
        """Notify the new filename of the current editor."""
        if filename is None:
            filename = translations.TR_NEW_DOCUMENT
        self.currentEditorChanged.emit(filename)

    def show_split(self, orientation_vertical=False):
        #IDE.select_current(self.current_widget.currentWidget())
        self.current_widget.split_editor(orientation_vertical)

    def add_editor(self, fileName=None, ignore_checkers=False):
        print("filename::", fileName)
        ninjaide = IDE.getInstance()
        editable = ninjaide.get_or_create_editable(fileName)
        if editable.editor:
            self.current_widget.set_current(editable)
            print("\n\nreturn")
            return self.current_widget.currentWidget()
        else:
            editable.ignore_checkers = ignore_checkers

        editorWidget = self.create_editor_from_editable(editable)

        #add the tab
        keep_index = (self.splitter.count() > 1 and
                      self.combo_area.stacked.count() > 0)
        self.combo_area.add_editor(editable, keep_index)

        #emit a signal about the file open
        self.fileOpened.emit(fileName)
        if keep_index:
            self.current_widget.set_current(editable)

        self.stack.setCurrentWidget(self.splitter)
        return editorWidget

    def create_editor_from_editable(self, editable):
        editorWidget = editor.create_editor(editable)

        #Connect signals
        editable.fileSaved.connect(self._editor_tab_was_saved)
        editorWidget.openDropFile.connect(self.open_file)
        editorWidget.addBackItemNavigation.connect(self.add_back_item_navigation)
        editorWidget.locateFunction.connect(self._editor_locate_function)
        editorWidget.findOcurrences.connect(self._find_occurrences)
        #keyPressEventSignal for plugins
        editorWidget.keyPressSignal.connect(self._editor_keyPressEvent)

        return editorWidget

    def reset_pep8_warnings(self, value):
        pass
        #FIXME: check how we handle this
        #for i in range(self._tabMain.count()):
            #widget = self._tabMain.widget(i)
            #if type(widget) is editor.Editor:
                #if value:
                    #widget.syncDocErrorsSignal = True
                    #widget.pep8.check_style()
                #else:
                    #widget.hide_pep8_errors()

    def reset_lint_warnings(self, value):
        pass
        #FIXME: check how we handle this
        #for i in range(self._tabMain.count()):
            #widget = self._tabMain.widget(i)
            #if type(widget) is editor.Editor:
                #if value:
                    #widget.syncDocErrorsSignal = True
                    #widget.errors.check_errors()
                #else:
                    #widget.hide_lint_errors()

    def _find_occurrences(self, word):
        self.findOcurrences.emit(word)

    def _editor_keyPressEvent(self, event):
        self.editorKeyPressEvent.emit(event)

    def _editor_locate_function(self, function, filePath, isVariable):
        self.locateFunction.emit(function, filePath, isVariable)

    def _editor_tab_was_saved(self, editable=None):
        self.updateLocator.emit(editable.file_path)

    def get_current_widget(self):
        return self.current_widget.currentWidget()

    def get_current_editor(self):
        """Return the Actual Editor or None

        Return an instance of Editor if the Current Tab contains
        an Editor or None if it is not an instance of Editor"""
        widget = self.current_widget.currentWidget()
        if isinstance(widget, editor.Editor):
            return widget
        return None

    def reload_file(self, editorWidget=None):
        if editorWidget is None:
            editorWidget = self.get_current_editor()
            if editorWidget is not None:
                editorWidget.neditable.reload_file()

    def add_tab(self, widget, tabName, tabIndex=None):
        pass
        #return self.tabs.add_tab(widget, tabName, index=tabIndex)

    def open_image(self, fileName):
        try:
            if not self.is_open(fileName):
                viewer = image_viewer.ImageViewer(fileName)
                self.add_tab(viewer, file_manager.get_basename(fileName))
                viewer.ID = fileName
            else:
                self.move_to_open(fileName)
        except Exception as reason:
            logger.error('open_image: %s', reason)
            QMessageBox.information(self, self.tr("Incorrect File"),
                                    self.tr("The image couldn\'t be open"))

    def open_files_fromList(self, lst):
        for f in lst:
            self.open_file(f)

    def open_files_fromUrlList(self, lst):
        for f in lst:
            self.open_file(f.toLocalFile())

    def open_file(self, filename='', line=-1, col=0, ignore_checkers=False):
        logger.debug("will try to open %s" % filename)
        if not filename:
            logger.debug("has nofilename")
            if settings.WORKSPACE:
                directory = settings.WORKSPACE
            else:
                directory = os.path.expanduser("~")
                editorWidget = self.get_current_editor()
                ninjaide = IDE.getInstance()
                if ninjaide:
                    current_project = ninjaide.get_current_project()
                    if current_project is not None:
                        directory = current_project
                    elif editorWidget is not None and editorWidget.file_path:
                        directory = file_manager.get_folder(
                            editorWidget.file_path)
            extensions = ';;'.join(
                ['{}(*{})'.format(e.upper()[1:], e)
                 for e in settings.SUPPORTED_EXTENSIONS + ['.*', '']])
            fileNames = QFileDialog.getOpenFileNames(self,
                             self.tr("Open File"), directory, extensions)[0]#list()
        else:
            logger.debug("has filename")
            fileNames = [filename]
        if not fileNames:
            return

        print("\n\nopen_file")
        othersFileNames = []
        image_extensions = ('bmp', 'gif', 'jpeg', 'jpg', 'png')
        for filename in fileNames:
            print("nombre", filename)
            if QFileInfo(filename).isDir():
                othersFileNames.extend( QFileDialog.getOpenFileNames(None,
                    "Select files", filename, "Files (*.*)")[0] )
            elif file_manager.get_file_extension(filename) in image_extensions:
                logger.debug("will open as image")
                self.open_image(filename)
            elif file_manager.get_file_extension(filename).endswith('ui'):
                logger.debug("will load in ui editor")
                self.w = uic.loadUi(filename)
                self.w.show()
            else:
                logger.debug("will try to open: " + filename)
                self.__open_file(filename, line, col,
                                 ignore_checkers)

        for filename in othersFileNames:
            print("nombre", filename)
            if QFileInfo(filename).isDir():
                continue
            elif file_manager.get_file_extension(filename) in image_extensions:
                logger.debug("will open as image")
                self.open_image(filename)
            elif file_manager.get_file_extension(filename).endswith('ui'):
                logger.debug("will load in ui editor")
                self.w = uic.loadUi(filename)
                self.w.show()
            else:
                logger.debug("will try to open: " + filename)
                self.__open_file(filename, line, col,
                                 ignore_checkers)



    def __open_file(self, fileName='', line=-1, col=0, ignore_checkers=False):
        print("unio", fileName)
        try:
            editorWidget = self.add_editor(fileName,
                                           ignore_checkers=ignore_checkers)
            if line != -1:
                editorWidget.set_cursor_position(line, col)
            self.currentEditorChanged.emit(fileName)
        except file_manager.NinjaIOException as reason:
            QMessageBox.information(self,
                                    self.tr("The file couldn't be open"),
                                    str(reason))

    def is_open(self, filename):
        pass
        #return self.tabs.is_open(filename) != -1

    def move_to_open(self, filename):
        pass
        #FIXME: add in the current split?
        #if self.tabs.is_open(filename) != -1:
            #self.tabs.move_to_open(filename)
        #self.tabs.currentWidget().setFocus()
        #self.emit(SIGNAL("currentEditorChanged(QString)"), filename)

    def get_widget_for_id(self, filename):
        pass
        #widget = None
        #index = self.tabs.is_open(filename)
        #if index != -1:
            #widget = self.tabs.widget(index)
        #return widget

    def change_open_tab_id(self, idname, newId):
        """Search for the Tab with idname, and set the newId to that Tab."""
        pass
        #index = self.tabs.is_open(idname)
        #if index != -1:
            #widget = self.tabs.widget(index)
            #tabName = file_manager.get_basename(newId)
            #self.tabs.change_open_tab_name(index, tabName)
            #widget.ID = newId

    def close_deleted_file(self, idname):
        """Search for the Tab with id, and ask the user if should be closed."""
        pass
        #index = self.tabs.is_open(idname)
        #if index != -1:
            #result = QMessageBox.question(self, self.tr("Close Deleted File"),
                #self.tr("Are you sure you want to close the deleted file?\n"
                        #"The content will be completely deleted."),
                #buttons=QMessageBox.Yes | QMessageBox.No)
            #if result == QMessageBox.Yes:
                #self.tabs.removeTab(index)

    def save_file(self, editorWidget=None):
        #FIXME: check how we handle this
        if not editorWidget:
            editorWidget = self.get_current_editor()
        if not editorWidget:
            return False
        try:
            #editorWidget.just_saved = True
            if (editorWidget.nfile.is_new_file or
                    not editorWidget.nfile.has_write_permission()):
                return self.save_file_as()

            self.beforeFileSaved.emit(editorWidget.file_path)
            if settings.REMOVE_TRAILING_SPACES:
                helpers.remove_trailing_spaces(editorWidget)
            editorWidget.neditable.save_content()
            #file_manager.store_file_content(
                #fileName, content, addExtension=False)
            encoding = file_manager.get_file_encoding(editorWidget.text())
            editorWidget.encoding = encoding
            self.fileSaved.emit((self.tr("File Saved: %s") % editorWidget.file_path))
            return True
        except Exception as reason:
            logger.error('save_file: %s', reason)
            QMessageBox.information(self, self.tr("Save Error"),
                                    self.tr("The file couldn't be saved!"))
        return False

    def save_file_as(self):
        editorWidget = self.get_current_editor()
        if not editorWidget:
            return False
        try:
            filters = '(*.py);;(*.*)'
            if editorWidget.file_path:
                ext = file_manager.get_file_extension(editorWidget.file_path)
                if ext != 'py':
                    filters = '(*.%s);;(*.py);;(*.*)' % ext
            save_folder = self._get_save_folder(editorWidget.file_path)
            fileName = QFileDialog.getSaveFileName(
                self._parent, self.tr("Save File"), save_folder, filters)
            if not fileName:
                return False

            if settings.REMOVE_TRAILING_SPACES:
                helpers.remove_trailing_spaces(editorWidget)

            editorWidget.neditable.save_content(path=fileName)
            editorWidget.register_syntax(
                file_manager.get_file_extension(fileName))

            self.fileSaved.emit((self.tr("File Saved: %s") % fileName))
            self.currentEditorChanged.emit(fileName)
            return True
        except file_manager.NinjaFileExistsException as ex:
            QMessageBox.information(self, self.tr("File Already Exists"),
                                    (self.tr("Invalid Path: the file '%s' "
                                             " already exists.") %
                                    ex.filename))
        except Exception as reason:
            logger.error('save_file_as: %s', reason)
            QMessageBox.information(self, self.tr("Save Error"),
                                    self.tr("The file couldn't be saved!"))
        return False

    def _get_save_folder(self, fileName):
        """
        Returns the root directory of the 'Main Project' or the home folder
        """
        ninjaide = IDE.getInstance()
        current_project = ninjaide.get_current_project()
        if current_project:
            return current_project.path
        return os.path.expanduser("~")

    def save_project(self, projectFolder):
        pass
        #FIXME: check how we handle this
        #for i in range(self._tabMain.count()):
            #editorWidget = self._tabMain.widget(i)
            #if type(editorWidget) is editor.Editor and \
            #file_manager.belongs_to_folder(projectFolder,
                    #editorWidget.file_path):
                #reloaded = self._tabMain.check_for_external_modifications(
                    #editorWidget)
                #if not reloaded:
                    #self.save_file(editorWidget)
        #for i in range(self.tabsecondary.count()):
            #editorWidget = self.tabsecondary.widget(i)
            #if type(editorWidget) is editor.Editor and \
            #file_manager.belongs_to_folder(projectFolder,
                    #editorWidget.file_path):
                #reloaded = self.tabsecondary.check_for_external_modifications(
                    #editorWidget)
                #if not reloaded:
                    #self.save_file(editorWidget)

    def save_all(self):
        pass
        #FIXME: check how we handle this
        #for i in range(self._tabMain.count()):
            #editorWidget = self._tabMain.widget(i)
            #if type(editorWidget) is editor.Editor:
                #reloaded = self._tabMain.check_for_external_modifications(
                    #editorWidget)
                #if not reloaded:
                    #self.save_file(editorWidget)
        #for i in range(self.tabsecondary.count()):
            #editorWidget = self.tabsecondary.widget(i)
            #self.tabsecondary.check_for_external_modifications(editorWidget)
            #if type(editorWidget) is editor.Editor:
                #reloaded = self.tabsecondary.check_for_external_modifications(
                    #editorWidget)
                #if not reloaded:
                    #self.save_file(editorWidget)

    def call_editors_function(self, call_function, *arguments):
        pass
        #args = arguments[0]
        #kwargs = arguments[1]
        #for i in range(self.tabs.count()):
            #editorWidget = self.tabs.widget(i)
            #if isinstance(editorWidget, editor.Editor):
                #function = getattr(editorWidget, call_function)
                #function(*args, **kwargs)
        #TODO: add other splits

    def show_start_page(self):
        start = self.stack.widget(0)
        if isinstance(start, start_page.StartPage):
            self.stack.setCurrentIndex(0)
        else:
            startPage = start_page.StartPage(parent=self)
            startPage.openProject.connect(self.open_project)
            startPage.openPreferences.connect(self.openPreferences.emit)
            startPage.newFile.connect(self.add_editor)
            startPage.openFiles.connect(self.open_files_fromList)
            self.stack.insertWidget(0, startPage)
            self.stack.setCurrentIndex(0)

            self.tryMakeImagePreview(0)
            #"screen0.png"

    def show_python_doc(self):
        if sys.platform == 'win32':
            self.docPage = browser_widget.BrowserWidget(
                'http://docs.python.org/')
        else:
            process = runner.start_pydoc()
            self.docPage = browser_widget.BrowserWidget(process[1], process[0])
        self.add_tab(self.docPage, translations.TR_PYTHON_DOC)

    def show_report_bugs(self):
        webbrowser.open(resources.BUGS_PAGE)

    def show_plugins_doc(self):
        bugsPage = browser_widget.BrowserWidget(resources.PLUGINS_DOC, self)
        self.add_tab(bugsPage, translations.TR_HOW_TO_WRITE_PLUGINS)

    def editor_jump_to_line(self, lineno=None):
        """Jump to line *lineno* if it is not None
        otherwise ask to the user the line number to jump
        """
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.jump_to_line(lineno=lineno)

    def get_opened_documents(self):
        #return self.tabs.get_documents_data()
        return []

    def check_for_unsaved_files(self):
        pass
        #return self.tabs._check_unsaved_tabs()

    def get_unsaved_files(self):
        pass
        #return self.tabs.get_unsaved_files()

    def reset_editor_flags(self):
        pass
        #for i in range(self.tabs.count()):
            #widget = self.tabs.widget(i)
            #if isinstance(widget, editor.Editor):
                #widget.set_flags()

    def _specify_syntax(self, widget, syntaxLang):
        if isinstance(widget, editor.Editor):
            widget.restyle(syntaxLang)

    def apply_editor_theme(self, family, size):
        pass
        #for i in range(self.tabs.count()):
            #widget = self.tabs.widget(i)
            #if isinstance(widget, editor.Editor):
                #widget.restyle()
                #widget.set_font(family, size)

    def update_editor_margin_line(self):
        pass
        #for i in range(self.tabs.count()):
            #widget = self.tabs.widget(i)
            #if isinstance(widget, editor.Editor):
                #widget._update_margin_line()

    def open_project(self, path):
        print("open_project")
        self.openProject.emit(path)

    def close_python_doc(self):
        pass
        #close the python document server (if running)
        #if self.docPage:
            #index = self.tabs.indexOf(self.docPage)
            #self.tabs.removeTab(index)
            ##assign None to the browser
            #self.docPage = None

    def close_file(self):
        """Close the current tab in the current TabWidget."""
        self.current_widget.close_current_file()

    def create_file(self, base_path, project_path):
        self._add_file_folder.create_file(base_path, project_path)

    def create_folder(self, base_path, project_path):
        self._add_file_folder.create_folder(base_path, project_path)

    def change_tab(self):
        """Change the tab in the current TabWidget."""
        print("\nchange_tab")
        self.stack.setCurrentWidget(self.splitter)
        # self._files_handler.next_item()
        pass

    def change_tab_reverse(self):
        """Change the tab in the current TabWidget backwards."""
        print("\nchange_tab_reverse")
        self.stack.setCurrentWidget(self.splitter)
        # self._files_handler.previous_item()

    def toggle_tabs_and_spaces(self):
        """ Toggle Show/Hide Tabs and Spaces """

        settings.SHOW_TABS_AND_SPACES = not settings.SHOW_TABS_AND_SPACES
        qsettings = IDE.ninja_settings()
        qsettings.setValue('preferences/editor/showTabsAndSpaces',
                           settings.SHOW_TABS_AND_SPACES)

    def show_navigation_buttons(self):
        """Show Navigation menu."""
        self.stack.setCurrentWidget(self.splitter)
        self.combo_area.show_menu_navigation()

    def change_split_focus(self):
        pass
        #FIXME: check how we handle this
        #if self.actualTab == self._tabMain and self.tabsecondary.isVisible():
            #self.actualTab = self.tabsecondary
        #else:
            #self.actualTab = self._tabMain
        #widget = self.actualTab.currentWidget()
        #if widget is not None:
            #widget.setFocus()

    def shortcut_index(self, index):
        pass
        #self.tabs.setCurrentIndex(index)

    def print_file(self):
        """Call the print of ui_tool

        Call print of ui_tool depending on the focus of the application"""
        #TODO: Add funtionality for proyect tab and methods tab
        editorWidget = self.get_current_editor()
        if editorWidget is not None:
            fileName = "newDocument.pdf"
            if editorWidget.file_path:
                fileName = file_manager.get_basename(
                    editorWidget.file_path)
                fileName = fileName[:fileName.rfind('.')] + '.pdf'
            ui_tools.print_file(fileName, editorWidget.print_)

    def split_assistance(self):
        dialog = split_orientation.SplitOrientation(self)
        dialog.show()

    def close_split(self):
        if self.current_widget != self.combo_area:
            self.current_widget.bar.close_split()

    def split_vertically(self):
        self.show_split(False)

    def split_horizontally(self):
        self.show_split(True)

    def navigate_back(self):
        self.__navigate_with_keyboard(False)

    def navigate_forward(self):
        self.__navigate_with_keyboard(True)
Пример #28
0
class SettingsDialog(QWidget):
	"A settings dialog"
	scroll_speed_changed = pyqtSignal()
	def __init__(self, parent=None):
		super().__init__(parent, flags=Qt.Window)
		self.resize(700, 500)
		self.show()
		self.restore_values()
		self.initUI()

	def initUI(self):
		main_layout = QVBoxLayout()
		sub_layout = QHBoxLayout()
		# Left Panel
		left_panel = QListWidget()
		left_panel.setViewMode(left_panel.ListMode)
		#left_panel.setIconSize(QSize(40,40))
		left_panel.setTextElideMode(Qt.ElideRight)
		left_panel.setMaximumWidth(200)
		left_panel.itemClicked.connect(self.change)
		#web.setText('Web')
		self.application = QListWidgetItem()
		self.application.setText('Application')
		self.web = QListWidgetItem()
		self.web.setText('Web')
		self.visual = QListWidgetItem()
		self.visual.setText('Visual')
		self.advanced = QListWidgetItem()
		self.advanced.setText('Advanced')
		self.about = QListWidgetItem()
		self.about.setText('About')

		#main.setIcon(QIcon(os.path.join(gui_constants.static_dir, 'plus2.png')))
		left_panel.addItem(self.application)
		left_panel.addItem(self.web)
		left_panel.addItem(self.visual)
		left_panel.addItem(self.advanced)
		left_panel.addItem(self.about)
		left_panel.setMaximumWidth(100)

		# right panel
		self.right_panel = QStackedLayout()
		self.init_right_panel()

		# bottom
		bottom_layout = QHBoxLayout()
		ok_btn = QPushButton('Ok')
		ok_btn.clicked.connect(self.accept)
		cancel_btn = QPushButton('Cancel')
		cancel_btn.clicked.connect(self.close)
		info_lbl = QLabel()
		info_lbl.setText('<a href="https://github.com/Pewpews/happypanda">'+
				   'Visit GitHub Repo</a> | Options marked with * requires application restart.')
		info_lbl.setTextFormat(Qt.RichText)
		info_lbl.setTextInteractionFlags(Qt.TextBrowserInteraction)
		info_lbl.setOpenExternalLinks(True)
		self.spacer = QWidget()
		self.spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
		bottom_layout.addWidget(info_lbl, 0, Qt.AlignLeft)
		bottom_layout.addWidget(self.spacer)
		bottom_layout.addWidget(ok_btn, 0, Qt.AlignRight)
		bottom_layout.addWidget(cancel_btn, 0, Qt.AlignRight)

		sub_layout.addWidget(left_panel)
		sub_layout.addLayout(self.right_panel)
		main_layout.addLayout(sub_layout)
		main_layout.addLayout(bottom_layout)

		self.restore_options()

		self.setLayout(main_layout)
		self.setWindowTitle('Settings')


	def change(self, item):
		def curr_index(index):
			if index != self.right_panel.currentIndex():
				self.right_panel.setCurrentIndex(index)
		if item == self.application:
			curr_index(self.application_index)
		elif item == self.web:
			curr_index(self.web_index)
		elif item == self.visual:
			curr_index(self.visual_index)
		elif item == self.advanced:
			curr_index(self.advanced_index)
		elif item == self.about:
			curr_index(self.about_index)

	def restore_values(self):
		#Web
		self.exprops = settings.ExProperties()

		# Visual
		self.high_quality_thumbs = gui_constants.HIGH_QUALITY_THUMBS
		self.popup_width = gui_constants.POPUP_WIDTH
		self.popup_height = gui_constants.POPUP_HEIGHT
		self.style_sheet = gui_constants.user_stylesheet_path

		# Advanced
		self.scroll_speed = gui_constants.SCROLL_SPEED
		self.cache_size = gui_constants.THUMBNAIL_CACHE_SIZE
		self.prefetch_item_amnt = gui_constants.PREFETCH_ITEM_AMOUNT

	def restore_options(self):
		# App / Monitor / Misc
		self.enable_monitor.setChecked(gui_constants.ENABLE_MONITOR)
		self.look_new_gallery_startup.setChecked(gui_constants.LOOK_NEW_GALLERY_STARTUP)
		self.auto_add_new_galleries.setChecked(gui_constants.LOOK_NEW_GALLERY_AUTOADD)
		# App / Monitor / Folders
		for path in gui_constants.MONITOR_PATHS:
			self.add_folder_monitor(path)

		# Web / General
		if 'g.e-hentai' in gui_constants.DEFAULT_EHEN_URL:
			self.default_ehen_url.setChecked(True)
		else:
			self.exhentai_ehen_url.setChecked(True)
		
		self.replace_metadata.setChecked(gui_constants.REPLACE_METADATA)
		self.always_first_hit.setChecked(gui_constants.ALWAYS_CHOOSE_FIRST_HIT)
		self.web_time_offset.setValue(gui_constants.GLOBAL_EHEN_TIME)
		self.continue_a_metadata_fetcher.setChecked(gui_constants.CONTINUE_AUTO_METADATA_FETCHER)
		self.use_jpn_title.setChecked(gui_constants.USE_JPN_TITLE)

		# Web / Exhentai
		self.ipbid_edit.setText(self.exprops.ipb_id)
		self.ipbpass_edit.setText(self.exprops.ipb_pass)

		# Visual / Grid View / Tooltip
		self.grid_tooltip_group.setChecked(gui_constants.GRID_TOOLTIP)
		self.visual_grid_tooltip_title.setChecked(gui_constants.TOOLTIP_TITLE)
		self.visual_grid_tooltip_author.setChecked(gui_constants.TOOLTIP_AUTHOR)
		self.visual_grid_tooltip_chapters.setChecked(gui_constants.TOOLTIP_CHAPTERS)
		self.visual_grid_tooltip_status.setChecked(gui_constants.TOOLTIP_STATUS)
		self.visual_grid_tooltip_type.setChecked(gui_constants.TOOLTIP_TYPE)
		self.visual_grid_tooltip_lang.setChecked(gui_constants.TOOLTIP_LANG)
		self.visual_grid_tooltip_descr.setChecked(gui_constants.TOOLTIP_DESCR)
		self.visual_grid_tooltip_tags.setChecked(gui_constants.TOOLTIP_TAGS)
		self.visual_grid_tooltip_last_read.setChecked(gui_constants.TOOLTIP_LAST_READ)
		self.visual_grid_tooltip_times_read.setChecked(gui_constants.TOOLTIP_TIMES_READ)
		self.visual_grid_tooltip_pub_date.setChecked(gui_constants.TOOLTIP_PUB_DATE)
		self.visual_grid_tooltip_date_added.setChecked(gui_constants.TOOLTIP_DATE_ADDED)
		# Visual / Grid View / Gallery
		self.external_viewer_ico.setChecked(gui_constants.USE_EXTERNAL_PROG_ICO)
		self.gallery_type_ico.setChecked(gui_constants.DISPLAY_GALLERY_TYPE)
		if gui_constants.GALLERY_FONT_ELIDE:
			self.gallery_text_elide.setChecked(True)
		else:
			self.gallery_text_fit.setChecked(True)
		self.font_lbl.setText(gui_constants.GALLERY_FONT[0])
		self.font_size_lbl.setValue(gui_constants.GALLERY_FONT[1])

		def re_enforce(s):
			if s:
				self.search_on_enter.setChecked(True)
		self.search_allow_regex.clicked.connect(re_enforce)

		if gui_constants.SEARCH_ON_ENTER:
			self.search_on_enter.setChecked(True)
		else:
			self.search_every_keystroke.setChecked(True)
		# Visual / Grid View / Colors
		self.grid_label_color.setText(gui_constants.GRID_VIEW_LABEL_COLOR)
		self.grid_title_color.setText(gui_constants.GRID_VIEW_TITLE_COLOR)
		self.grid_artist_color.setText(gui_constants.GRID_VIEW_ARTIST_COLOR)

		# Advanced / Misc / External Viewer
		self.external_viewer_path.setText(gui_constants.EXTERNAL_VIEWER_PATH)

	def accept(self):
		set = settings.set

		# App / Monitor / misc
		gui_constants.ENABLE_MONITOR = self.enable_monitor.isChecked()
		set(gui_constants.ENABLE_MONITOR, 'Application', 'enable monitor')
		gui_constants.LOOK_NEW_GALLERY_STARTUP = self.look_new_gallery_startup.isChecked()
		set(gui_constants.LOOK_NEW_GALLERY_STARTUP, 'Application', 'look new gallery startup')
		gui_constants.LOOK_NEW_GALLERY_AUTOADD = self.auto_add_new_galleries.isChecked()
		set(gui_constants.LOOK_NEW_GALLERY_AUTOADD, 'Application', 'look new gallery autoadd')
		# App / Monitor / folders
		n = self.folders_layout.rowCount()
		paths = ''
		for x in range(n):
			item = self.folders_layout.takeAt(x+1)
			l_edit = item.widget()
			p = l_edit.text()
			if p:
				if x == n-1:
					paths += '{}'.format(p)
				else:
					paths += '{},'.format(p)
		set(paths, 'Application', 'monitor paths')
		gui_constants.MONITOR_PATHS = paths.split(',')

		# Web / General
		if self.default_ehen_url.isChecked():
			gui_constants.DEFAULT_EHEN_URL = 'http://g.e-hentai.org/'
		else:
			gui_constants.DEFAULT_EHEN_URL = 'http://exhentai.org/'
		set(gui_constants.DEFAULT_EHEN_URL, 'Web', 'default ehen url')

		gui_constants.REPLACE_METADATA = self.replace_metadata.isChecked()
		set(gui_constants.REPLACE_METADATA, 'Web', 'replace metadata')

		gui_constants.ALWAYS_CHOOSE_FIRST_HIT = self.always_first_hit.isChecked()
		set(gui_constants.ALWAYS_CHOOSE_FIRST_HIT, 'Web', 'always choose first hit')

		gui_constants.GLOBAL_EHEN_TIME = self.web_time_offset.value()
		set(gui_constants.GLOBAL_EHEN_TIME, 'Web', 'global ehen time offset')

		gui_constants.CONTINUE_AUTO_METADATA_FETCHER = self.continue_a_metadata_fetcher.isChecked()
		set(gui_constants.CONTINUE_AUTO_METADATA_FETCHER, 'Web', 'continue auto metadata fetcher')

		gui_constants.USE_JPN_TITLE = self.use_jpn_title.isChecked()
		set(gui_constants.USE_JPN_TITLE, 'Web', 'use jpn title')

		# Web / ExHentai
		self.exprops.ipb_id = self.ipbid_edit.text()
		self.exprops.ipb_pass = self.ipbpass_edit.text()

		# Visual / Grid View / Tooltip
		gui_constants.GRID_TOOLTIP = self.grid_tooltip_group.isChecked()
		set(gui_constants.GRID_TOOLTIP, 'Visual', 'grid tooltip')
		gui_constants.TOOLTIP_TITLE = self.visual_grid_tooltip_title.isChecked()
		set(gui_constants.TOOLTIP_TITLE, 'Visual', 'tooltip title')
		gui_constants.TOOLTIP_AUTHOR = self.visual_grid_tooltip_author.isChecked()
		set(gui_constants.TOOLTIP_AUTHOR, 'Visual', 'tooltip author')
		gui_constants.TOOLTIP_CHAPTERS = self.visual_grid_tooltip_chapters.isChecked()
		set(gui_constants.TOOLTIP_CHAPTERS, 'Visual', 'tooltip chapters')
		gui_constants.TOOLTIP_STATUS = self.visual_grid_tooltip_status.isChecked()
		set(gui_constants.TOOLTIP_STATUS, 'Visual', 'tooltip status')
		gui_constants.TOOLTIP_TYPE = self.visual_grid_tooltip_type.isChecked()
		set(gui_constants.TOOLTIP_TYPE, 'Visual', 'tooltip type')
		gui_constants.TOOLTIP_LANG = self.visual_grid_tooltip_lang.isChecked()
		set(gui_constants.TOOLTIP_LANG, 'Visual', 'tooltip lang')
		gui_constants.TOOLTIP_DESCR = self.visual_grid_tooltip_descr.isChecked()
		set(gui_constants.TOOLTIP_DESCR, 'Visual', 'tooltip descr')
		gui_constants.TOOLTIP_TAGS = self.visual_grid_tooltip_tags.isChecked()
		set(gui_constants.TOOLTIP_TAGS, 'Visual', 'tooltip tags')
		gui_constants.TOOLTIP_LAST_READ = self.visual_grid_tooltip_last_read.isChecked()
		set(gui_constants.TOOLTIP_LAST_READ, 'Visual', 'tooltip last read')
		gui_constants.TOOLTIP_TIMES_READ = self.visual_grid_tooltip_times_read.isChecked()
		set(gui_constants.TOOLTIP_TIMES_READ, 'Visual', 'tooltip times read')
		gui_constants.TOOLTIP_PUB_DATE = self.visual_grid_tooltip_pub_date.isChecked()
		set(gui_constants.TOOLTIP_PUB_DATE, 'Visual', 'tooltip pub date')
		gui_constants.TOOLTIP_DATE_ADDED = self.visual_grid_tooltip_date_added.isChecked()
		set(gui_constants.TOOLTIP_DATE_ADDED, 'Visual', 'tooltip date added')
		# Visual / Grid View / Gallery
		gui_constants.USE_EXTERNAL_PROG_ICO = self.external_viewer_ico.isChecked()
		set(gui_constants.USE_EXTERNAL_PROG_ICO, 'Visual', 'use external prog ico')
		gui_constants.DISPLAY_GALLERY_TYPE = self.gallery_type_ico.isChecked()
		set(gui_constants.DISPLAY_GALLERY_TYPE, 'Visual', 'display gallery type')
		if self.gallery_text_elide.isChecked():
			gui_constants.GALLERY_FONT_ELIDE = True
		else:
			gui_constants.GALLERY_FONT_ELIDE = False
		set(gui_constants.GALLERY_FONT_ELIDE, 'Visual', 'gallery font elide')
		gui_constants.GALLERY_FONT = (self.font_lbl.text(), self.font_size_lbl.value())
		set(gui_constants.GALLERY_FONT[0], 'Visual', 'gallery font family')
		set(gui_constants.GALLERY_FONT[1], 'Visual', 'gallery font size')
		# Visual / Grid View / Colors
		if self.color_checker(self.grid_title_color.text()):
			gui_constants.GRID_VIEW_TITLE_COLOR = self.grid_title_color.text()
			set(gui_constants.GRID_VIEW_TITLE_COLOR, 'Visual', 'grid view title color')
		if self.color_checker(self.grid_artist_color.text()):
			gui_constants.GRID_VIEW_ARTIST_COLOR = self.grid_artist_color.text()
			set(gui_constants.GRID_VIEW_ARTIST_COLOR, 'Visual', 'grid view artist color')
		if self.color_checker(self.grid_label_color.text()):
			gui_constants.GRID_VIEW_LABEL_COLOR = self.grid_label_color.text()
			set(gui_constants.GRID_VIEW_LABEL_COLOR, 'Visual', 'grid view label color')

		# Advanced / Misc
		# Advanced / Misc / Grid View
		gui_constants.SCROLL_SPEED = self.scroll_speed
		set(self.scroll_speed, 'Advanced', 'scroll speed')
		self.scroll_speed_changed.emit()
		gui_constants.THUMBNAIL_CACHE_SIZE = self.cache_size
		set(self.cache_size[1], 'Advanced', 'cache size')
		QPixmapCache.setCacheLimit(self.cache_size[0]*
							 self.cache_size[1])
		# Advanced / Misc / Search
		gui_constants.ALLOW_SEARCH_REGEX = self.search_allow_regex.isChecked()
		set(gui_constants.ALLOW_SEARCH_REGEX, 'Advanced', 'allow search regex')
		gui_constants.SEARCH_AUTOCOMPLETE = self.search_autocomplete.isChecked()
		set(gui_constants.SEARCH_AUTOCOMPLETE, 'Advanced', 'search autocomplete')
		if self.search_on_enter.isChecked():
			gui_constants.SEARCH_ON_ENTER = True
		else:
			gui_constants.SEARCH_ON_ENTER = False
		set(gui_constants.SEARCH_ON_ENTER, 'Advanced', 'search on enter')

		# Advanced / Misc / External Viewer
		if not self.external_viewer_path.text():
			gui_constants.USE_EXTERNAL_VIEWER = False
			set(False, 'Advanced', 'use external viewer')
		else:
			gui_constants.USE_EXTERNAL_VIEWER = True
			set(True, 'Advanced', 'use external viewer')
			gui_constants._REFRESH_EXTERNAL_VIEWER = True
		gui_constants.EXTERNAL_VIEWER_PATH = self.external_viewer_path.text()
		set(gui_constants.EXTERNAL_VIEWER_PATH,'Advanced', 'external viewer path')

		settings.save()
		self.close()

	def init_right_panel(self):

		#def title_def(title):
		#	title_lbl = QLabel(title)
		#	f = QFont()
		#	f.setPixelSize(16)
		#	title_lbl.setFont(f)
		#	return title_lbl

		# App
		application = QTabWidget()
		self.application_index = self.right_panel.addWidget(application)
		application_general = QWidget()
		application.addTab(application_general, 'General')
		application.setTabEnabled(0, False)

		# App / Monitor
		app_monitor_page = QScrollArea()
		app_monitor_page.setBackgroundRole(QPalette.Base)
		app_monitor_dummy = QWidget()
		app_monitor_page.setWidgetResizable(True)
		app_monitor_page.setWidget(app_monitor_dummy)
		application.addTab(app_monitor_page, 'Monitoring')
		application.setCurrentIndex(1)
		app_monitor_m_l = QVBoxLayout(app_monitor_dummy)
		# App / Monitor / misc
		app_monitor_misc_group = QGroupBox('General *', self)
		app_monitor_m_l.addWidget(app_monitor_misc_group)
		app_monitor_misc_m_l = QFormLayout(app_monitor_misc_group)
		monitor_info = QLabel('Directory monitoring will monitor the specified directories for any'+
						' gallery events. For example if you delete a gallery source in one of your'+
						' monitored directories the application will inform you about it, and ask if'+
						' you want to delete the gallery from the application as well.')
		monitor_info.setWordWrap(True)
		app_monitor_misc_m_l.addRow(monitor_info)
		self.enable_monitor = QCheckBox('Enable directory monitoring')
		app_monitor_misc_m_l.addRow(self.enable_monitor)
		self.look_new_gallery_startup = QGroupBox('Scan for new galleries on startup', self)
		app_monitor_misc_m_l.addRow(self.look_new_gallery_startup)
		self.look_new_gallery_startup.setCheckable(True)
		look_new_gallery_startup_m_l = QVBoxLayout(self.look_new_gallery_startup)
		self.auto_add_new_galleries = QCheckBox('Automatically add found galleries')
		look_new_gallery_startup_m_l.addWidget(self.auto_add_new_galleries)

		# App / Monitor / folders
		app_monitor_group = QGroupBox('Directories *', self)
		app_monitor_m_l.addWidget(app_monitor_group, 1)
		app_monitor_folders_m_l = QVBoxLayout(app_monitor_group)
		app_monitor_folders_add = QPushButton('+')
		app_monitor_folders_add.clicked.connect(self.add_folder_monitor)
		app_monitor_folders_add.setMaximumWidth(20)
		app_monitor_folders_add.setMaximumHeight(20)
		app_monitor_folders_m_l.addWidget(app_monitor_folders_add, 0, Qt.AlignRight)
		self.folders_layout = QFormLayout()
		app_monitor_folders_m_l.addLayout(self.folders_layout)

		# Web
		web = QTabWidget()
		self.web_index = self.right_panel.addWidget(web)
		web_general_page = QScrollArea()
		web_general_page.setBackgroundRole(QPalette.Base)
		web_general_page.setWidgetResizable(True)
		web.addTab(web_general_page, 'General')
		web_general_dummy = QWidget()
		web_general_page.setWidget(web_general_dummy)
		web_general_m_l = QVBoxLayout(web_general_dummy)
		metadata_fetcher_group = QGroupBox('Metadata', self)
		web_general_m_l.addWidget(metadata_fetcher_group)
		metadata_fetcher_m_l = QFormLayout(metadata_fetcher_group)
		self.default_ehen_url = QRadioButton('g.e-hentai.org', metadata_fetcher_group)
		self.exhentai_ehen_url = QRadioButton('exhentai.org', metadata_fetcher_group)
		ehen_url_l = QHBoxLayout()
		ehen_url_l.addWidget(self.default_ehen_url)
		ehen_url_l.addWidget(self.exhentai_ehen_url, 1)
		metadata_fetcher_m_l.addRow('Default URL:', ehen_url_l)
		self.continue_a_metadata_fetcher = QCheckBox('Continue from where auto metadata fetcher left off')
		metadata_fetcher_m_l.addRow(self.continue_a_metadata_fetcher)
		self.use_jpn_title = QCheckBox('Use japanese title')
		metadata_fetcher_m_l.addRow(self.use_jpn_title)
		time_offset_info = QLabel('To avoid getting banned, we need to impose a delay between our requests.'+
							' I have made it so you cannot set the delay lower than the recommended (I don\'t'+
							' want you to get banned, anon).\nSpecify the delay between requests in seconds.')
		time_offset_info.setWordWrap(True)
		self.web_time_offset = QSpinBox()
		self.web_time_offset.setMaximumWidth(40)
		self.web_time_offset.setMinimum(4)
		self.web_time_offset.setMaximum(99)
		metadata_fetcher_m_l.addRow(time_offset_info)
		metadata_fetcher_m_l.addRow('Requests delay in', self.web_time_offset)
		replace_metadata_info = QLabel('When fetching for metadata the new metadata will be appended'+
								 ' to the gallery by default. This means that new data will only be set if'+
								 ' the field was empty. There is however a special case for namespace & tags.'+
								 ' We go through all the new namespace & tags to only add those that'+
								 ' do not already exists.\n\nEnabling this option makes it so that a gallery\'s old data'+
								 ' are deleted and replaced with the new data.')
		replace_metadata_info.setWordWrap(True)
		self.replace_metadata = QCheckBox('Replace old metadata with new metadata')
		metadata_fetcher_m_l.addRow(replace_metadata_info)
		metadata_fetcher_m_l.addRow(self.replace_metadata)
		first_hit_info = QLabel('By default, you get to choose which gallery to extract metadata from when'+
						  ' there is more than one gallery found when searching.\n'+
						  'Enabling this option makes it choose the first hit, saving you from moving your mouse.')
		first_hit_info.setWordWrap(True)
		self.always_first_hit = QCheckBox('Always choose first hit')
		metadata_fetcher_m_l.addRow(first_hit_info)
		metadata_fetcher_m_l.addRow(self.always_first_hit)

		# Web / Exhentai
		exhentai_page = QWidget()
		web.addTab(exhentai_page, 'ExHentai')
		ipb_layout = QFormLayout()
		exhentai_page.setLayout(ipb_layout)
		self.ipbid_edit = QLineEdit()
		self.ipbpass_edit = QLineEdit()
		exh_tutorial = QLabel(gui_constants.EXHEN_COOKIE_TUTORIAL)
		exh_tutorial.setTextFormat(Qt.RichText)
		ipb_layout.addRow('IPB Member ID:', self.ipbid_edit)
		ipb_layout.addRow('IPB Pass Hash:', self.ipbpass_edit)
		ipb_layout.addRow(exh_tutorial)

		# Visual
		visual = QTabWidget()
		self.visual_index = self.right_panel.addWidget(visual)
		visual_general_page = QWidget()
		visual.addTab(visual_general_page, 'General')

		grid_view_general_page = QWidget()
		visual.addTab(grid_view_general_page, 'Grid View')
		grid_view_layout = QVBoxLayout()
		grid_view_layout.addWidget(QLabel('Options marked with * requires application restart'),
						   0, Qt.AlignTop)
		grid_view_general_page.setLayout(grid_view_layout)
		# grid view
		# grid view / tooltip
		self.grid_tooltip_group = QGroupBox('Tooltip', grid_view_general_page)
		self.grid_tooltip_group.setCheckable(True)
		grid_view_layout.addWidget(self.grid_tooltip_group, 0, Qt.AlignTop)
		grid_tooltip_layout = QFormLayout()
		self.grid_tooltip_group.setLayout(grid_tooltip_layout)
		grid_tooltip_layout.addRow(QLabel('Control what is'+
									' displayed in the tooltip'))
		grid_tooltips_hlayout = FlowLayout()
		grid_tooltip_layout.addRow(grid_tooltips_hlayout)
		self.visual_grid_tooltip_title = QCheckBox('Title')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_title)
		self.visual_grid_tooltip_author = QCheckBox('Author')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_author)
		self.visual_grid_tooltip_chapters = QCheckBox('Chapters')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_chapters)
		self.visual_grid_tooltip_status = QCheckBox('Status')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_status)
		self.visual_grid_tooltip_type = QCheckBox('Type')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_type)
		self.visual_grid_tooltip_lang = QCheckBox('Language')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_lang)
		self.visual_grid_tooltip_descr = QCheckBox('Description')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_descr)
		self.visual_grid_tooltip_tags = QCheckBox('Tags')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_tags)
		self.visual_grid_tooltip_last_read = QCheckBox('Last read')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_last_read)
		self.visual_grid_tooltip_times_read = QCheckBox('Times read')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_times_read)
		self.visual_grid_tooltip_pub_date = QCheckBox('Publication Date')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_pub_date)
		self.visual_grid_tooltip_date_added = QCheckBox('Date added')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_date_added)
		# grid view / gallery
		grid_gallery_group = QGroupBox('Gallery', grid_view_general_page)
		grid_view_layout.addWidget(grid_gallery_group, 0, Qt.AlignTop)
		grid_gallery_main_l = QFormLayout()
		grid_gallery_main_l.setFormAlignment(Qt.AlignLeft)
		grid_gallery_group.setLayout(grid_gallery_main_l)
		grid_gallery_display = FlowLayout()
		grid_gallery_main_l.addRow('Display on gallery:', grid_gallery_display)
		self.external_viewer_ico = QCheckBox('External Viewer')
		self.external_viewer_ico.setDisabled(True)
		grid_gallery_display.addWidget(self.external_viewer_ico)
		self.gallery_type_ico = QCheckBox('File Type')
		self.gallery_type_ico.setDisabled(True)
		grid_gallery_display.addWidget(self.gallery_type_ico)
		gallery_text_mode = QWidget()
		grid_gallery_main_l.addRow('Text Mode:', gallery_text_mode)
		gallery_text_mode_l = QHBoxLayout()
		gallery_text_mode.setLayout(gallery_text_mode_l)
		self.gallery_text_elide = QRadioButton('Elide text', gallery_text_mode)
		self.gallery_text_fit = QRadioButton('Fit text', gallery_text_mode)
		gallery_text_mode_l.addWidget(self.gallery_text_elide, 0, Qt.AlignLeft)
		gallery_text_mode_l.addWidget(self.gallery_text_fit, 0, Qt.AlignLeft)
		gallery_text_mode_l.addWidget(Spacer('h'), 1, Qt.AlignLeft)
		gallery_font = QHBoxLayout()
		grid_gallery_main_l.addRow('Font:*', gallery_font)
		self.font_lbl = QLabel()
		self.font_size_lbl = QSpinBox()
		self.font_size_lbl.setMaximum(100)
		self.font_size_lbl.setMinimum(1)
		self.font_size_lbl.setToolTip('Font size in pixels')
		choose_font = QPushButton('Choose font')
		choose_font.clicked.connect(self.choose_font)
		gallery_font.addWidget(self.font_lbl, 0, Qt.AlignLeft)
		gallery_font.addWidget(self.font_size_lbl, 0, Qt.AlignLeft)
		gallery_font.addWidget(choose_font, 0, Qt.AlignLeft)
		gallery_font.addWidget(Spacer('h'), 1, Qt.AlignLeft)
		# grid view / colors
		grid_colors_group = QGroupBox('Colors', grid_view_general_page)
		grid_view_layout.addWidget(grid_colors_group, 1, Qt.AlignTop)
		grid_colors_l = QFormLayout()
		grid_colors_group.setLayout(grid_colors_l)
		def color_lineedit():
			l = QLineEdit()
			l.setPlaceholderText('Hex colors. Eg.: #323232')
			l.setMaximumWidth(200)
			return l
		self.grid_label_color = color_lineedit()
		self.grid_title_color = color_lineedit()
		self.grid_artist_color = color_lineedit()
		grid_colors_l.addRow('Label color:', self.grid_label_color)
		grid_colors_l.addRow('Title color:', self.grid_title_color)
		grid_colors_l.addRow('Artist color:', self.grid_artist_color)

		style_page = QWidget()
		visual.addTab(style_page, 'Style')
		visual.setTabEnabled(0, False)
		visual.setTabEnabled(2, False)
		visual.setCurrentIndex(1)

		# Advanced
		advanced = QTabWidget()
		self.advanced_index = self.right_panel.addWidget(advanced)
		advanced_misc = QWidget()
		advanced.addTab(advanced_misc, 'Misc')
		advanced_misc_main_layout = QVBoxLayout()
		advanced_misc.setLayout(advanced_misc_main_layout)
		misc_controls_layout = QFormLayout()
		misc_controls_layout.addWidget(QLabel('Options marked with * requires application restart'))
		advanced_misc_main_layout.addLayout(misc_controls_layout)
		# Advanced / Misc / Grid View
		misc_gridview = QGroupBox('Grid View')
		misc_controls_layout.addWidget(misc_gridview)
		misc_gridview_layout = QFormLayout()
		misc_gridview.setLayout(misc_gridview_layout)
		# Advanced / Misc / Grid View / scroll speed
		scroll_speed_spin_box = QSpinBox()
		scroll_speed_spin_box.setFixedWidth(60)
		scroll_speed_spin_box.setToolTip('Control the speed when scrolling in'+
								   ' grid view. DEFAULT: 7')
		scroll_speed_spin_box.setValue(self.scroll_speed)
		def scroll_speed(v): self.scroll_speed = v
		scroll_speed_spin_box.valueChanged[int].connect(scroll_speed)
		misc_gridview_layout.addRow('Scroll speed:', scroll_speed_spin_box)
		# Advanced / Misc / Grid View / cache size
		cache_size_spin_box = QSpinBox()
		cache_size_spin_box.setFixedWidth(120)
		cache_size_spin_box.setMaximum(999999999)
		cache_size_spin_box.setToolTip('This will greatly improve the grid view.' +
								 ' Increase the value if you experience lag when scrolling'+
								 ' through galleries. DEFAULT: 200 MiB')
		def cache_size(c): self.cache_size = (self.cache_size[0], c)
		cache_size_spin_box.setValue(self.cache_size[1])
		cache_size_spin_box.valueChanged[int].connect(cache_size)
		misc_gridview_layout.addRow('Cache Size (MiB):', cache_size_spin_box)		
		# Advanced / Misc / Regex
		misc_search = QGroupBox('Search')
		misc_controls_layout.addWidget(misc_search)
		misc_search_layout = QFormLayout()
		misc_search.setLayout(misc_search_layout)
		search_allow_regex_l = QHBoxLayout()
		self.search_allow_regex = QCheckBox()
		self.search_allow_regex.setChecked(gui_constants.ALLOW_SEARCH_REGEX)
		self.search_allow_regex.adjustSize()
		self.search_allow_regex.setToolTip('A regex cheatsheet is located at About->Regex Cheatsheet')
		search_allow_regex_l.addWidget(self.search_allow_regex)
		search_allow_regex_l.addWidget(QLabel('A regex cheatsheet is located at About->Regex Cheatsheet'))
		search_allow_regex_l.addWidget(Spacer('h'))
		misc_search_layout.addRow('Regex:', search_allow_regex_l)
		# Advanced / Misc / Regex / autocomplete
		self.search_autocomplete = QCheckBox('*')
		self.search_autocomplete.setChecked(gui_constants.SEARCH_AUTOCOMPLETE)
		self.search_autocomplete.setToolTip('Turn autocomplete on/off')
		misc_search_layout.addRow('Autocomplete', self.search_autocomplete)
		# Advanced / Misc / Regex / search behaviour
		self.search_every_keystroke = QRadioButton('Search on every keystroke *', misc_search)
		misc_search_layout.addRow(self.search_every_keystroke)
		self.search_on_enter = QRadioButton('Search on enter-key *', misc_search)
		misc_search_layout.addRow(self.search_on_enter)
		# Advanced / Misc / External Viewer
		misc_external_viewer = QGroupBox('External Viewer')
		misc_controls_layout.addWidget(misc_external_viewer)
		misc_external_viewer_l = QFormLayout()
		misc_external_viewer.setLayout(misc_external_viewer_l)
		misc_external_viewer_l.addRow(QLabel(gui_constants.SUPPORTED_EXTERNAL_VIEWER_LBL))
		self.external_viewer_path = PathLineEdit(misc_external_viewer, False)
		self.external_viewer_path.setPlaceholderText('Right/Left-click to open folder explorer.'+
							  ' Leave empty to use default viewer')
		self.external_viewer_path.setToolTip('Right/Left-click to open folder explorer.'+
							  ' Leave empty to use default viewer')
		self.external_viewer_path.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
		misc_external_viewer_l.addRow('Path:', self.external_viewer_path)


		# Advanced / Database
		advanced_db_page = QWidget()
		advanced.addTab(advanced_db_page, 'Database')
		advanced.setTabEnabled(1, False)


		# About
		about = QTabWidget()
		self.about_index = self.right_panel.addWidget(about)
		about_happypanda_page = QWidget()
		about_troubleshoot_page = QWidget()
		about.addTab(about_happypanda_page, 'About Happypanda')
		about_layout = QVBoxLayout()
		about_happypanda_page.setLayout(about_layout)
		info_lbl = QLabel('<b>Author:</b> <a href=\'https://github.com/Pewpews\'>'+
					'Pewpews</a><br/>'+
					'Chat: <a href=\'https://gitter.im/Pewpews/happypanda\'>'+
					'Gitter chat</a><br/>'+
					'Email: [email protected]<br/>'+
					'<b>Current version {}</b><br/>'.format(gui_constants.vs)+
					'Happypanda was created using:<br/>'+
					'- Python 3.4<br/>'+
					'- The Qt5 Framework')
		info_lbl.setOpenExternalLinks(True)
		about_layout.addWidget(info_lbl, 0, Qt.AlignTop)
		gpl_lbl = QLabel(gui_constants.GPL)
		gpl_lbl.setOpenExternalLinks(True)
		gpl_lbl.setWordWrap(True)
		about_layout.addWidget(gpl_lbl, 0, Qt.AlignTop)
		about_layout.addWidget(Spacer('v'))
		# About / Tags
		about_tags_page = QWidget()
		about.addTab(about_tags_page, 'Tags')
		about.setTabEnabled(1, False)
		# list of tags/namespaces here

		# About / Troubleshooting
		about.addTab(about_troubleshoot_page, 'Troubleshooting Guide')
		troubleshoot_layout = QVBoxLayout()
		about_troubleshoot_page.setLayout(troubleshoot_layout)
		guide_lbl = QLabel(gui_constants.TROUBLE_GUIDE)
		guide_lbl.setTextFormat(Qt.RichText)
		guide_lbl.setOpenExternalLinks(True)
		troubleshoot_layout.addWidget(guide_lbl, 0, Qt.AlignTop)
		troubleshoot_layout.addWidget(Spacer('v'))
		# About / Regex Cheatsheet
		about_s_regex = QGroupBox('Regex')
		about.addTab(about_s_regex, 'Regex Cheatsheet')
		about_s_regex_l = QFormLayout()
		about_s_regex.setLayout(about_s_regex_l)
		about_s_regex_l.addRow('\\\\\\\\', QLabel('Match literally \\'))
		about_s_regex_l.addRow('.', QLabel('Match any single character'))
		about_s_regex_l.addRow('^', QLabel('Start of string'))
		about_s_regex_l.addRow('$', QLabel('End of string'))
		about_s_regex_l.addRow('\\d', QLabel('Match any decimal digit'))
		about_s_regex_l.addRow('\\D', QLabel('Match any non-digit character'))
		about_s_regex_l.addRow('\\s', QLabel('Match any whitespace character'))
		about_s_regex_l.addRow('\\S', QLabel('Match any non-whitespace character'))
		about_s_regex_l.addRow('\\w', QLabel('Match any alphanumeric character'))
		about_s_regex_l.addRow('\\W', QLabel('Match any non-alphanumeric character'))
		about_s_regex_l.addRow('*', QLabel('Repeat previous character zero or more times'))
		about_s_regex_l.addRow('+', QLabel('Repeat previous character one or more times'))
		about_s_regex_l.addRow('?', QLabel('Repeat previous character one or zero times'))
		about_s_regex_l.addRow('{m, n}', QLabel('Repeat previous character atleast <i>m</i> times but no more than <i>n</i> times'))
		about_s_regex_l.addRow('(...)', QLabel('Match everything enclosed'))
		about_s_regex_l.addRow('(a|b)', QLabel('Match either a or b'))
		about_s_regex_l.addRow('[abc]', QLabel('Match a single character of: a, b or c'))
		about_s_regex_l.addRow('[^abc]', QLabel('Match a character except: a, b or c'))
		about_s_regex_l.addRow('[a-z]', QLabel('Match a character in the range'))
		about_s_regex_l.addRow('[^a-z]', QLabel('Match a character not in the range'))
		# About / Search tutorial
		about_search_scroll = QScrollArea()
		about_search_scroll.setBackgroundRole(QPalette.Base)
		about_search_scroll.setWidgetResizable(True)
		about_search_tut = QWidget()
		about.addTab(about_search_scroll, 'Search Guide')
		about_search_tut_l = QVBoxLayout()
		about_search_tut.setLayout(about_search_tut_l)
		# General
		about_search_general = QGroupBox('General')
		about_search_tut_l.addWidget(about_search_general)
		about_search_general_l = QFormLayout()
		about_search_general.setLayout(about_search_general_l)
		about_search_general_l.addRow(QLabel(gui_constants.SEARCH_TUTORIAL_GENERAL))
		# Title & Author
		about_search_tit_aut = QGroupBox('Title and Author')
		about_search_tut_l.addWidget(about_search_tit_aut)
		about_search_tit_l = QFormLayout()
		about_search_tit_aut.setLayout(about_search_tit_l)
		about_search_tit_l.addRow(QLabel(gui_constants.SEARCH_TUTORIAL_TIT_AUT))
		# Namespace & Tags
		about_search_tags = QGroupBox('Namespace and Tags')
		about_search_tut_l.addWidget(about_search_tags)
		about_search_tags_l = QFormLayout()
		about_search_tags.setLayout(about_search_tags_l)
		about_search_tags_l.addRow(QLabel(gui_constants.SEARCH_TUTORIAL_TAGS))
		about_search_scroll.setWidget(about_search_tut)

	def add_folder_monitor(self, path=''):
		if not isinstance(path, str):
			path = ''
		l_edit = PathLineEdit()
		l_edit.setText(path)
		n = self.folders_layout.rowCount() + 1
		self.folders_layout.addRow('Dir {}'.format(n), l_edit)

	def color_checker(self, txt):
		allow = False
		if len(txt) == 7:
			if txt[0] == '#':
				allow = True
		return allow

	def choose_font(self):
		tup = QFontDialog.getFont(self)
		font = tup[0]
		if tup[1]:
			self.font_lbl.setText(font.family())
			self.font_size_lbl.setValue(font.pointSize())

	def reject(self):
		self.close()
Пример #29
0
class DataStatistics(QDialog):
    def __init__(self, parent=None):
        super(DataStatistics, self).__init__(parent)
        self.initData()
        self.initModule()
        self.setModule()
        self.funcLink()
        self.drawGraph()
        self.analyzeSingleMemo()

    def initModule(self):
        self.setWindowTitle(u'数据统计')
        self.setWindowIcon(QIcon(css.dataBtnPath))
        self.resize(500, 500)
        pg.setConfigOptions(foreground=QColor(113, 148, 116), antialias=True)

        self.btnframe = QFrame(self)
        self.mainframe = QFrame(self)
        self.btngroup = QButtonGroup(self.btnframe)
        self.stacklayout = QStackedLayout(self.mainframe)

        self.btn1 = QToolButton(self.btnframe)
        self.btn2 = QToolButton(self.btnframe)
        self.btngroup.addButton(self.btn1, 1)
        self.btngroup.addButton(self.btn2, 2)

        self.frame1 = QMainWindow()
        self.frame1_bar = QStatusBar()
        self.frame1.setStatusBar(self.frame1_bar)
        self.frame1_bar.showMessage(self.date + ':  ' +
                                    str(readFinishRate(self.date)[2] * 100) +
                                    '%')

        self.frame2 = QMainWindow()
        self.frame2_bar = QStatusBar()
        self.frame2.setStatusBar(self.frame2_bar)
        self.frame2_bar.showMessage("坚持,就是每一天很难,可一年一年越来越容易。")

        self.stacklayout.addWidget(self.frame1)
        self.stacklayout.addWidget(self.frame2)

    def setModule(self):
        self.btnframe.setGeometry(0, 0, self.width(), 35)
        self.btnframe.setStyleSheet("border-color: rgb(0, 0, 0);")
        self.btnframe.setFrameShape(QFrame.Panel)
        self.btnframe.setFrameShadow(QFrame.Raised)
        self.mainframe.setGeometry(0, 35, self.width(),
                                   self.height() - self.btnframe.height())

        self.btn1.setCheckable(True)
        self.btn1.setText("整体完成率")
        self.btn1.resize(100, 35)
        self.btn2.setCheckable(True)
        self.btn2.setText("单条完成情况")
        self.btn2.resize(100, 35)
        self.btn2.move(self.btn1.width(), 0)

    def funcLink(self):
        self.btn1.clicked.connect(self.showFrame1)
        self.btn2.clicked.connect(self.showFrame2)

    def initData(self):
        date = QDate.currentDate()
        self.date = date.toString(Qt.ISODate)
        self.statistics = readStatistics(css.statistics, self.date)

    def drawGraph(self):
        self.myplot = pg.PlotWidget(self.frame1, title='每日任务完成率')
        self.frame1.setCentralWidget(self.myplot)

        x = []
        for key in self.statistics.keys():
            x.append(key)
        points = []
        for key in x:
            points.append(readFinishRate(key)[2])

        tick_b = [list(zip(range(len(x)), x))]
        bottom = self.myplot.getAxis('bottom')
        bottom.setTicks(tick_b)

        self.myplot.setBackground((210, 240, 240))  # 背景色
        self.myplot.showGrid(y=True)

        pen = pg.mkPen({'color': (155, 200, 160), 'width': 4})  # 画笔设置
        self.myplot.plot(points[0:],
                         clear=True,
                         pen=pen,
                         symbol='o',
                         symbolBrush=QColor(113, 148, 116))

    def analyzeSingleMemo(self):
        #data extract
        data = read(css.userdata)
        self.content = []
        self.set_date = []
        self.if_done = []
        if data['memo_data']:
            for memo in data['memo_data']:
                self.content.append(memo['content'])
                self.set_date.append(memo['set_date'])
                self.if_done.append(memo['if_done'])
        #UI init
        self.ui = QWidget(self.frame2)
        self.option = QComboBox(self.ui)
        self.label0 = QLabel(self.ui)
        self.label1 = QLabel(self.ui)
        self.label2 = QLabel(self.ui)
        self.label3 = QLabel(self.ui)
        self.frame2.setCentralWidget(self.ui)
        #UI set
        self.option.setGeometry(10, 95, self.width() - 100, 40)
        self.option.setStyleSheet(css.combobox_style)
        self.option.addItems(self.content)
        self.option.currentIndexChanged.connect(self.getMemoMessage)

        self.label0.setGeometry(10, 5, self.width() - 100, 80)
        self.label1.setGeometry(10, 145, self.width() - 100, 80)
        self.label2.setGeometry(10, 235, self.width() - 100, 80)
        self.label3.setGeometry(10, 325, self.width() - 100, 80)
        self.label0.setStyleSheet(css.label_style)
        self.label1.setStyleSheet(css.label_style)
        self.label2.setStyleSheet(css.label_style)
        self.label3.setStyleSheet(css.label_style)
        self.label0.setText('选择需要查看的memo:')
        self.label1.setText('设立已 ' +
                            str(getDateDiffer(self.set_date[0], self.date)) +
                            ' 天')
        self.label2.setText('已完成 ' + str(len(self.if_done[0])) + ' 天')
        self.label3.setText('最大连续完成 ' + str(len(getLongest(self.if_done[0]))) +
                            ' 天')

    def getMemoMessage(self):
        self.label1.setText('设立已 ' + str(
            getDateDiffer(self.set_date[self.option.currentIndex()],
                          self.date)) + ' 天')
        self.label2.setText(
            '已完成 ' + str(len(self.if_done[self.option.currentIndex()])) + ' 天')
        self.label3.setText(
            '最大连续完成 ' +
            str(len(getLongest(self.if_done[self.option.currentIndex()]))) +
            ' 天')

    def showFrame1(self):
        if self.stacklayout.currentIndex() != 0:
            self.stacklayout.setCurrentIndex(0)

    def showFrame2(self):
        if self.stacklayout.currentIndex() != 1:
            self.stacklayout.setCurrentIndex(1)
Пример #30
0
class SettingsDialog(QWidget):
	"A settings dialog"
	scroll_speed_changed = pyqtSignal()
	init_gallery_rebuild = pyqtSignal(bool)
	init_gallery_eximport = pyqtSignal(object)
	def __init__(self, parent=None):
		super().__init__(parent, flags=Qt.Window)

		self.init_gallery_rebuild.connect(self.accept)

		self.parent_widget = parent
		self.setAttribute(Qt.WA_DeleteOnClose)
		self.resize(700, 500)
		self.restore_values()
		self.initUI()
		self.setWindowTitle('Settings')
		self.show()

	def initUI(self):
		main_layout = QVBoxLayout(self)
		sub_layout = QHBoxLayout()
		# Left Panel
		left_panel = QListWidget()
		left_panel.setViewMode(left_panel.ListMode)
		#left_panel.setIconSize(QSize(40,40))
		left_panel.setTextElideMode(Qt.ElideRight)
		left_panel.setMaximumWidth(200)
		left_panel.itemClicked.connect(self.change)
		#web.setText('Web')
		self.application = QListWidgetItem()
		self.application.setText('Application')
		self.web = QListWidgetItem()
		self.web.setText('Web')
		self.visual = QListWidgetItem()
		self.visual.setText('Visual')
		self.advanced = QListWidgetItem()
		self.advanced.setText('Advanced')
		self.about = QListWidgetItem()
		self.about.setText('About')

		#main.setIcon(QIcon(os.path.join(app_constants.static_dir, 'plus2.png')))
		left_panel.addItem(self.application)
		left_panel.addItem(self.web)
		left_panel.addItem(self.visual)
		left_panel.addItem(self.advanced)
		left_panel.addItem(self.about)
		left_panel.setMaximumWidth(100)

		# right panel
		self.right_panel = QStackedLayout()
		self.init_right_panel()

		# bottom
		bottom_layout = QHBoxLayout()
		ok_btn = QPushButton('Ok')
		ok_btn.clicked.connect(self.accept)
		cancel_btn = QPushButton('Cancel')
		cancel_btn.clicked.connect(self.close)
		info_lbl = QLabel()
		info_lbl.setText('<a href="https://github.com/Pewpews/happypanda">'+
				   'Visit GitHub Repo</a> | Options marked with * requires application restart.')
		info_lbl.setTextFormat(Qt.RichText)
		info_lbl.setTextInteractionFlags(Qt.TextBrowserInteraction)
		info_lbl.setOpenExternalLinks(True)
		self.spacer = QWidget()
		self.spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
		bottom_layout.addWidget(info_lbl, 0, Qt.AlignLeft)
		bottom_layout.addWidget(self.spacer)
		bottom_layout.addWidget(ok_btn, 0, Qt.AlignRight)
		bottom_layout.addWidget(cancel_btn, 0, Qt.AlignRight)

		sub_layout.addWidget(left_panel)
		sub_layout.addLayout(self.right_panel)
		main_layout.addLayout(sub_layout)
		main_layout.addLayout(bottom_layout)

		self.restore_options()


	def change(self, item):
		def curr_index(index):
			if index != self.right_panel.currentIndex():
				self.right_panel.setCurrentIndex(index)
		if item == self.application:
			curr_index(self.application_index)
		elif item == self.web:
			curr_index(self.web_index)
		elif item == self.visual:
			curr_index(self.visual_index)
		elif item == self.advanced:
			curr_index(self.advanced_index)
		elif item == self.about:
			curr_index(self.about_index)

	def restore_values(self):
		#Web
		self.exprops = settings.ExProperties()

		# Visual
		self.high_quality_thumbs = app_constants.HIGH_QUALITY_THUMBS
		self.popup_width = app_constants.POPUP_WIDTH
		self.popup_height = app_constants.POPUP_HEIGHT
		self.style_sheet = app_constants.user_stylesheet_path

		# Advanced
		self.scroll_speed = app_constants.SCROLL_SPEED
		self.cache_size = app_constants.THUMBNAIL_CACHE_SIZE
		self.prefetch_item_amnt = app_constants.PREFETCH_ITEM_AMOUNT

	def restore_options(self):

		# App / General
		self.subfolder_as_chapters.setChecked(app_constants.SUBFOLDER_AS_GALLERY)
		self.extract_gallery_before_opening.setChecked(app_constants.EXTRACT_CHAPTER_BEFORE_OPENING)
		self.open_galleries_sequentially.setChecked(app_constants.OPEN_GALLERIES_SEQUENTIALLY)
		self.scroll_to_new_gallery.setChecked(app_constants.SCROLL_TO_NEW_GALLERIES)
		self.move_imported_gs.setChecked(app_constants.MOVE_IMPORTED_GALLERIES)
		self.move_imported_def_path.setText(app_constants.IMPORTED_GALLERY_DEF_PATH)
		self.open_random_g_chapters.setChecked(app_constants.OPEN_RANDOM_GALLERY_CHAPTERS)
		self.rename_g_source_group.setChecked(app_constants.RENAME_GALLERY_SOURCE)
		self.path_to_unrar.setText(app_constants.unrar_tool_path)
		# App / General / External Viewer
		self.external_viewer_path.setText(app_constants.EXTERNAL_VIEWER_PATH)

		# App / Monitor / Misc
		self.enable_monitor.setChecked(app_constants.ENABLE_MONITOR)
		self.look_new_gallery_startup.setChecked(app_constants.LOOK_NEW_GALLERY_STARTUP)
		self.auto_add_new_galleries.setChecked(app_constants.LOOK_NEW_GALLERY_AUTOADD)
		# App / Monitor / Folders
		for path in app_constants.MONITOR_PATHS:
			self.add_folder_monitor(path)

		# App / Monitor / Ignore list
		for path in app_constants.IGNORE_PATHS:
			self.add_ignore_path(path)

		# Web / General
		if 'g.e-hentai' in app_constants.DEFAULT_EHEN_URL:
			self.default_ehen_url.setChecked(True)
		else:
			self.exhentai_ehen_url.setChecked(True)
		
		self.replace_metadata.setChecked(app_constants.REPLACE_METADATA)
		self.always_first_hit.setChecked(app_constants.ALWAYS_CHOOSE_FIRST_HIT)
		self.web_time_offset.setValue(app_constants.GLOBAL_EHEN_TIME)
		self.continue_a_metadata_fetcher.setChecked(app_constants.CONTINUE_AUTO_METADATA_FETCHER)
		self.use_jpn_title.setChecked(app_constants.USE_JPN_TITLE)
		self.use_gallery_link.setChecked(app_constants.USE_GALLERY_LINK)

		# Web / Download
		if app_constants.HEN_DOWNLOAD_TYPE == 0:
			self.archive_download.setChecked(True)
		else:
			self.torrent_download.setChecked(True)

		self.download_directory.setText(app_constants.DOWNLOAD_DIRECTORY)
		self.torrent_client.setText(app_constants.TORRENT_CLIENT)

		# Web / Exhentai
		self.ipbid_edit.setText(self.exprops.ipb_id)
		self.ipbpass_edit.setText(self.exprops.ipb_pass)

		# Visual / Grid View / Tooltip
		self.grid_tooltip_group.setChecked(app_constants.GRID_TOOLTIP)
		self.visual_grid_tooltip_title.setChecked(app_constants.TOOLTIP_TITLE)
		self.visual_grid_tooltip_author.setChecked(app_constants.TOOLTIP_AUTHOR)
		self.visual_grid_tooltip_chapters.setChecked(app_constants.TOOLTIP_CHAPTERS)
		self.visual_grid_tooltip_status.setChecked(app_constants.TOOLTIP_STATUS)
		self.visual_grid_tooltip_type.setChecked(app_constants.TOOLTIP_TYPE)
		self.visual_grid_tooltip_lang.setChecked(app_constants.TOOLTIP_LANG)
		self.visual_grid_tooltip_descr.setChecked(app_constants.TOOLTIP_DESCR)
		self.visual_grid_tooltip_tags.setChecked(app_constants.TOOLTIP_TAGS)
		self.visual_grid_tooltip_last_read.setChecked(app_constants.TOOLTIP_LAST_READ)
		self.visual_grid_tooltip_times_read.setChecked(app_constants.TOOLTIP_TIMES_READ)
		self.visual_grid_tooltip_pub_date.setChecked(app_constants.TOOLTIP_PUB_DATE)
		self.visual_grid_tooltip_date_added.setChecked(app_constants.TOOLTIP_DATE_ADDED)
		# Visual / Grid View / Gallery
		self.external_viewer_ico.setChecked(app_constants.USE_EXTERNAL_PROG_ICO)
		self.gallery_type_ico.setChecked(app_constants.DISPLAY_GALLERY_TYPE)
		if app_constants.GALLERY_FONT_ELIDE:
			self.gallery_text_elide.setChecked(True)
		else:
			self.gallery_text_fit.setChecked(True)
		self.font_lbl.setText(app_constants.GALLERY_FONT[0])
		self.font_size_lbl.setValue(app_constants.GALLERY_FONT[1])

		def re_enforce(s):
			if s:
				self.search_on_enter.setChecked(True)
		self.search_allow_regex.clicked.connect(re_enforce)

		if app_constants.SEARCH_ON_ENTER:
			self.search_on_enter.setChecked(True)
		else:
			self.search_every_keystroke.setChecked(True)
		# Visual / Grid View / Colors
		self.grid_label_color.setText(app_constants.GRID_VIEW_LABEL_COLOR)
		self.grid_title_color.setText(app_constants.GRID_VIEW_TITLE_COLOR)
		self.grid_artist_color.setText(app_constants.GRID_VIEW_ARTIST_COLOR)


		# Advanced / Gallery / Gallery Text Fixer
		self.g_data_regex_fix_edit.setText(app_constants.GALLERY_DATA_FIX_REGEX)
		self.g_data_replace_fix_edit.setText(app_constants.GALLERY_DATA_FIX_REPLACE)
		self.g_data_fixer_title.setChecked(app_constants.GALLERY_DATA_FIX_TITLE)
		self.g_data_fixer_artist.setChecked(app_constants.GALLERY_DATA_FIX_ARTIST)

		# About / DB Overview
		self.tags_treeview_on_start.setChecked(app_constants.TAGS_TREEVIEW_ON_START)

	def accept(self):
		set = settings.set

		# App / General / Gallery
		app_constants.SUBFOLDER_AS_GALLERY = self.subfolder_as_chapters.isChecked()
		set(app_constants.SUBFOLDER_AS_GALLERY, 'Application', 'subfolder as gallery')
		app_constants.EXTRACT_CHAPTER_BEFORE_OPENING = self.extract_gallery_before_opening.isChecked()
		set(app_constants.EXTRACT_CHAPTER_BEFORE_OPENING, 'Application', 'extract chapter before opening')
		app_constants.OPEN_GALLERIES_SEQUENTIALLY = self.open_galleries_sequentially.isChecked()
		set(app_constants.OPEN_GALLERIES_SEQUENTIALLY, 'Application', 'open galleries sequentially')
		app_constants.SCROLL_TO_NEW_GALLERIES = self.scroll_to_new_gallery.isChecked()
		set(app_constants.SCROLL_TO_NEW_GALLERIES, 'Application', 'scroll to new galleries')
		app_constants.MOVE_IMPORTED_GALLERIES = self.move_imported_gs.isChecked()
		set(app_constants.MOVE_IMPORTED_GALLERIES, 'Application', 'move imported galleries')
		if not self.move_imported_def_path.text() or os.path.exists(self.move_imported_def_path.text()):
			app_constants.IMPORTED_GALLERY_DEF_PATH = self.move_imported_def_path.text()
			set(app_constants.IMPORTED_GALLERY_DEF_PATH, 'Application', 'imported gallery def path')
		app_constants.OPEN_RANDOM_GALLERY_CHAPTERS = self.open_random_g_chapters.isChecked()
		set(app_constants.OPEN_RANDOM_GALLERY_CHAPTERS, 'Application', 'open random gallery chapters')
		app_constants.RENAME_GALLERY_SOURCE = self.rename_g_source_group.isChecked()
		set(app_constants.RENAME_GALLERY_SOURCE, 'Application', 'rename gallery source')
		app_constants.unrar_tool_path = self.path_to_unrar.text()
		set(app_constants.unrar_tool_path, 'Application', 'unrar tool path')
		# App / General / Search
		app_constants.ALLOW_SEARCH_REGEX = self.search_allow_regex.isChecked()
		set(app_constants.ALLOW_SEARCH_REGEX, 'Application', 'allow search regex')
		app_constants.SEARCH_AUTOCOMPLETE = self.search_autocomplete.isChecked()
		set(app_constants.SEARCH_AUTOCOMPLETE, 'Application', 'search autocomplete')
		if self.search_on_enter.isChecked():
			app_constants.SEARCH_ON_ENTER = True
		else:
			app_constants.SEARCH_ON_ENTER = False
		set(app_constants.SEARCH_ON_ENTER, 'Application', 'search on enter')
		# App / General / External Viewer
		if not self.external_viewer_path.text():
			app_constants.USE_EXTERNAL_VIEWER = False
			set(False, 'Application', 'use external viewer')
		else:
			app_constants.USE_EXTERNAL_VIEWER = True
			set(True, 'Application', 'use external viewer')
			app_constants._REFRESH_EXTERNAL_VIEWER = True
		app_constants.EXTERNAL_VIEWER_PATH = self.external_viewer_path.text()
		set(app_constants.EXTERNAL_VIEWER_PATH,'Application', 'external viewer path')
		# App / Monitor / misc
		app_constants.ENABLE_MONITOR = self.enable_monitor.isChecked()
		set(app_constants.ENABLE_MONITOR, 'Application', 'enable monitor')
		app_constants.LOOK_NEW_GALLERY_STARTUP = self.look_new_gallery_startup.isChecked()
		set(app_constants.LOOK_NEW_GALLERY_STARTUP, 'Application', 'look new gallery startup')
		app_constants.LOOK_NEW_GALLERY_AUTOADD = self.auto_add_new_galleries.isChecked()
		set(app_constants.LOOK_NEW_GALLERY_AUTOADD, 'Application', 'look new gallery autoadd')
		# App / Monitor / folders
		paths = []
		folder_p_widgets = self.take_all_layout_widgets(self.folders_layout)
		for x, l_edit in enumerate(folder_p_widgets):
			p = l_edit.text()
			if p:
				paths.append(p)

		set(paths, 'Application', 'monitor paths')
		app_constants.MONITOR_PATHS = paths
		# App / Monitor / ignore list
		paths = []
		ignore_p_widgets = self.take_all_layout_widgets(self.ignore_path_l)
		for x, l_edit in enumerate(ignore_p_widgets):
			p = l_edit.text()
			if p:
				paths.append(p)
		set(paths, 'Application', 'ignore paths')
		app_constants.IGNORE_PATHS = paths

		# Web / Downloader

		if self.archive_download.isChecked():
			app_constants.HEN_DOWNLOAD_TYPE = 0
		else:
			app_constants.HEN_DOWNLOAD_TYPE = 1
		set(app_constants.HEN_DOWNLOAD_TYPE, 'Web', 'hen download type')

		app_constants.DOWNLOAD_DIRECTORY = self.download_directory.text()
		set(app_constants.DOWNLOAD_DIRECTORY, 'Web', 'download directory')

		app_constants.TORRENT_CLIENT = self.torrent_client.text()
		set(app_constants.TORRENT_CLIENT, 'Web', 'torrent client')

		# Web / Metdata
		if self.default_ehen_url.isChecked():
			app_constants.DEFAULT_EHEN_URL = 'http://g.e-hentai.org/'
		else:
			app_constants.DEFAULT_EHEN_URL = 'http://exhentai.org/'
		set(app_constants.DEFAULT_EHEN_URL, 'Web', 'default ehen url')

		app_constants.REPLACE_METADATA = self.replace_metadata.isChecked()
		set(app_constants.REPLACE_METADATA, 'Web', 'replace metadata')

		app_constants.ALWAYS_CHOOSE_FIRST_HIT = self.always_first_hit.isChecked()
		set(app_constants.ALWAYS_CHOOSE_FIRST_HIT, 'Web', 'always choose first hit')

		app_constants.GLOBAL_EHEN_TIME = self.web_time_offset.value()
		set(app_constants.GLOBAL_EHEN_TIME, 'Web', 'global ehen time offset')

		app_constants.CONTINUE_AUTO_METADATA_FETCHER = self.continue_a_metadata_fetcher.isChecked()
		set(app_constants.CONTINUE_AUTO_METADATA_FETCHER, 'Web', 'continue auto metadata fetcher')

		app_constants.USE_JPN_TITLE = self.use_jpn_title.isChecked()
		set(app_constants.USE_JPN_TITLE, 'Web', 'use jpn title')

		app_constants.USE_GALLERY_LINK = self.use_gallery_link.isChecked()
		set(app_constants.USE_GALLERY_LINK, 'Web', 'use gallery link')

		# Web / ExHentai
		self.exprops.ipb_id = self.ipbid_edit.text()
		self.exprops.ipb_pass = self.ipbpass_edit.text()

		# Visual / Grid View / Tooltip
		app_constants.GRID_TOOLTIP = self.grid_tooltip_group.isChecked()
		set(app_constants.GRID_TOOLTIP, 'Visual', 'grid tooltip')
		app_constants.TOOLTIP_TITLE = self.visual_grid_tooltip_title.isChecked()
		set(app_constants.TOOLTIP_TITLE, 'Visual', 'tooltip title')
		app_constants.TOOLTIP_AUTHOR = self.visual_grid_tooltip_author.isChecked()
		set(app_constants.TOOLTIP_AUTHOR, 'Visual', 'tooltip author')
		app_constants.TOOLTIP_CHAPTERS = self.visual_grid_tooltip_chapters.isChecked()
		set(app_constants.TOOLTIP_CHAPTERS, 'Visual', 'tooltip chapters')
		app_constants.TOOLTIP_STATUS = self.visual_grid_tooltip_status.isChecked()
		set(app_constants.TOOLTIP_STATUS, 'Visual', 'tooltip status')
		app_constants.TOOLTIP_TYPE = self.visual_grid_tooltip_type.isChecked()
		set(app_constants.TOOLTIP_TYPE, 'Visual', 'tooltip type')
		app_constants.TOOLTIP_LANG = self.visual_grid_tooltip_lang.isChecked()
		set(app_constants.TOOLTIP_LANG, 'Visual', 'tooltip lang')
		app_constants.TOOLTIP_DESCR = self.visual_grid_tooltip_descr.isChecked()
		set(app_constants.TOOLTIP_DESCR, 'Visual', 'tooltip descr')
		app_constants.TOOLTIP_TAGS = self.visual_grid_tooltip_tags.isChecked()
		set(app_constants.TOOLTIP_TAGS, 'Visual', 'tooltip tags')
		app_constants.TOOLTIP_LAST_READ = self.visual_grid_tooltip_last_read.isChecked()
		set(app_constants.TOOLTIP_LAST_READ, 'Visual', 'tooltip last read')
		app_constants.TOOLTIP_TIMES_READ = self.visual_grid_tooltip_times_read.isChecked()
		set(app_constants.TOOLTIP_TIMES_READ, 'Visual', 'tooltip times read')
		app_constants.TOOLTIP_PUB_DATE = self.visual_grid_tooltip_pub_date.isChecked()
		set(app_constants.TOOLTIP_PUB_DATE, 'Visual', 'tooltip pub date')
		app_constants.TOOLTIP_DATE_ADDED = self.visual_grid_tooltip_date_added.isChecked()
		set(app_constants.TOOLTIP_DATE_ADDED, 'Visual', 'tooltip date added')
		# Visual / Grid View / Gallery
		app_constants.USE_EXTERNAL_PROG_ICO = self.external_viewer_ico.isChecked()
		set(app_constants.USE_EXTERNAL_PROG_ICO, 'Visual', 'use external prog ico')
		app_constants.DISPLAY_GALLERY_TYPE = self.gallery_type_ico.isChecked()
		set(app_constants.DISPLAY_GALLERY_TYPE, 'Visual', 'display gallery type')
		if self.gallery_text_elide.isChecked():
			app_constants.GALLERY_FONT_ELIDE = True
		else:
			app_constants.GALLERY_FONT_ELIDE = False
		set(app_constants.GALLERY_FONT_ELIDE, 'Visual', 'gallery font elide')
		app_constants.GALLERY_FONT = (self.font_lbl.text(), self.font_size_lbl.value())
		set(app_constants.GALLERY_FONT[0], 'Visual', 'gallery font family')
		set(app_constants.GALLERY_FONT[1], 'Visual', 'gallery font size')
		# Visual / Grid View / Colors
		if self.color_checker(self.grid_title_color.text()):
			app_constants.GRID_VIEW_TITLE_COLOR = self.grid_title_color.text()
			set(app_constants.GRID_VIEW_TITLE_COLOR, 'Visual', 'grid view title color')
		if self.color_checker(self.grid_artist_color.text()):
			app_constants.GRID_VIEW_ARTIST_COLOR = self.grid_artist_color.text()
			set(app_constants.GRID_VIEW_ARTIST_COLOR, 'Visual', 'grid view artist color')
		if self.color_checker(self.grid_label_color.text()):
			app_constants.GRID_VIEW_LABEL_COLOR = self.grid_label_color.text()
			set(app_constants.GRID_VIEW_LABEL_COLOR, 'Visual', 'grid view label color')

		# Advanced / Misc
		# Advanced / Misc / Grid View
		app_constants.SCROLL_SPEED = self.scroll_speed
		set(self.scroll_speed, 'Advanced', 'scroll speed')
		self.scroll_speed_changed.emit()
		app_constants.THUMBNAIL_CACHE_SIZE = self.cache_size
		set(self.cache_size[1], 'Advanced', 'cache size')
		QPixmapCache.setCacheLimit(self.cache_size[0]*
							 self.cache_size[1])


		# Advanced / General / Gallery Text Fixer
		app_constants.GALLERY_DATA_FIX_REGEX = self.g_data_regex_fix_edit.text()
		set(app_constants.GALLERY_DATA_FIX_REGEX, 'Advanced', 'gallery data fix regex')
		app_constants.GALLERY_DATA_FIX_TITLE = self.g_data_fixer_title.isChecked()
		set(app_constants.GALLERY_DATA_FIX_TITLE, 'Advanced', 'gallery data fix title')
		app_constants.GALLERY_DATA_FIX_ARTIST = self.g_data_fixer_artist.isChecked()
		set(app_constants.GALLERY_DATA_FIX_ARTIST, 'Advanced', 'gallery data fix artist')
		app_constants.GALLERY_DATA_FIX_REPLACE = self.g_data_replace_fix_edit.text()
		set(app_constants.GALLERY_DATA_FIX_REPLACE, 'Advanced', 'gallery data fix replace')

		# About / DB Overview
		app_constants.TAGS_TREEVIEW_ON_START = self.tags_treeview_on_start.isChecked()
		set(app_constants.TAGS_TREEVIEW_ON_START, 'Application', 'tags treeview on start')

		settings.save()
		self.close()

	def init_right_panel(self):

		#def title_def(title):
		#	title_lbl = QLabel(title)
		#	f = QFont()
		#	f.setPixelSize(16)
		#	title_lbl.setFont(f)
		#	return title_lbl

		def groupbox(name, layout, parent, add_in_layout=None):
			"""
			Makes a groupbox and a layout for you
			Returns groupbox and layout
			"""
			g = QGroupBox(name, parent)
			l = layout(g)
			if add_in_layout:
				if isinstance(add_in_layout, QFormLayout):
					add_in_layout.addRow(g)
				else:
					add_in_layout.addWidget(g)
			return g, l

		def option_lbl_checkbox(text, optiontext, parent=None):
			l = QLabel(text)
			c = QCheckBox(text, parent)
			return l, c

		def new_tab(name, parent, scroll=False):
			"""
			Creates a new tab.
			Returns new tab page widget and it's layout
			"""
			new_t = QWidget(parent)
			new_l = QFormLayout(new_t)
			if scroll:
				scr = QScrollArea(parent)
				scr.setBackgroundRole(QPalette.Base)
				scr.setWidget(new_t)
				scr.setWidgetResizable(True)
				parent.addTab(scr, name)
				return new_t, new_l
			else:
				parent.addTab(new_t, name)
			return new_t, new_l


		# App
		application = QTabWidget(self)
		self.application_index = self.right_panel.addWidget(application)
		application_general, app_general_m_l = new_tab('General', application, True)

		# App / General / gallery
		app_gallery_page, app_gallery_l = new_tab('Gallery', application, True)
		self.subfolder_as_chapters = QCheckBox("Subdirectiories should be treated as standalone galleries instead of chapters (applies in archives too)")
		self.subfolder_as_chapters.setToolTip("This option will enable creating standalone galleries for each subdirectiories found recursively when importing."+
										"\nDefault action is treating each subfolder found as chapters of a gallery.")
		extract_gallery_info = QLabel("Note: This option has no effect when turned off if path to viewer is not specified.")
		self.extract_gallery_before_opening = QCheckBox("Extract archive before opening (only turn off if your viewer supports it)")
		self.open_galleries_sequentially = QCheckBox("Open chapters sequentially (Note: has no effect if path to viewer is not specified)")
		subf_info = QLabel("Behaviour of 'Scan for new galleries on startup' option will be affected.")
		subf_info.setWordWrap(True)
		app_gallery_l.addRow('Note:', subf_info)
		app_gallery_l.addRow(self.subfolder_as_chapters)
		app_gallery_l.addRow(extract_gallery_info)
		app_gallery_l.addRow(self.extract_gallery_before_opening)
		app_gallery_l.addRow(self.open_galleries_sequentially)
		self.scroll_to_new_gallery = QCheckBox("Scroll to newly added gallery")
		self.scroll_to_new_gallery.setDisabled(True)
		app_gallery_l.addRow(self.scroll_to_new_gallery)
		self.move_imported_gs, move_imported_gs_l = groupbox('Move imported galleries',
													   QFormLayout, app_gallery_page)
		self.move_imported_gs.setCheckable(True)
		self.move_imported_gs.setToolTip("Move imported galleries to specified folder.")
		self.move_imported_def_path = PathLineEdit()
		move_imported_gs_l.addRow('Directory:', self.move_imported_def_path)
		app_gallery_l.addRow(self.move_imported_gs)
		self.rename_g_source_group, rename_g_source_l = groupbox('Rename gallery source',
													  QFormLayout, app_gallery_page)
		self.rename_g_source_group.setCheckable(True)
		self.rename_g_source_group.setDisabled(True)
		app_gallery_l.addRow(self.rename_g_source_group)
		rename_g_source_l.addRow(QLabel("Check what to include when renaming gallery source. (Same order)"))
		rename_g_source_flow_l = FlowLayout()
		rename_g_source_l.addRow(rename_g_source_flow_l)
		self.rename_artist = QCheckBox("Artist")
		self.rename_title = QCheckBox("Title")
		self.rename_lang = QCheckBox("Language")
		self.rename_title.setChecked(True)
		self.rename_title.setDisabled(True)
		rename_g_source_flow_l.addWidget(self.rename_artist)
		rename_g_source_flow_l.addWidget(self.rename_title)
		rename_g_source_flow_l.addWidget(self.rename_lang)
		random_gallery_opener, random_g_opener_l = groupbox('Random Gallery Opener', QFormLayout, app_gallery_page)
		app_gallery_l.addRow(random_gallery_opener)
		self.open_random_g_chapters = QCheckBox("Open random gallery chapters")
		random_g_opener_l.addRow(self.open_random_g_chapters)

		# App / General / Search
		app_search, app_search_layout = groupbox('Search', QFormLayout, application_general)
		app_general_m_l.addRow(app_search)
		search_allow_regex_l = QHBoxLayout()
		self.search_allow_regex = QCheckBox()
		self.search_allow_regex.setChecked(app_constants.ALLOW_SEARCH_REGEX)
		self.search_allow_regex.adjustSize()
		self.search_allow_regex.setToolTip('A regex cheatsheet is located at About->Regex Cheatsheet')
		search_allow_regex_l.addWidget(self.search_allow_regex)
		search_allow_regex_l.addWidget(QLabel('A regex cheatsheet is located at About->Regex Cheatsheet'))
		search_allow_regex_l.addWidget(Spacer('h'))
		app_search_layout.addRow('Regex:', search_allow_regex_l)
		# App / General / Search / autocomplete
		self.search_autocomplete = QCheckBox('*')
		self.search_autocomplete.setChecked(app_constants.SEARCH_AUTOCOMPLETE)
		self.search_autocomplete.setToolTip('Turn autocomplete on/off')
		app_search_layout.addRow('Autocomplete', self.search_autocomplete)
		# App / General / Search / search behaviour
		self.search_every_keystroke = QRadioButton('Search on every keystroke *', app_search)
		app_search_layout.addRow(self.search_every_keystroke)
		self.search_on_enter = QRadioButton('Search on return-key *', app_search)
		app_search_layout.addRow(self.search_on_enter)

		# App / General / External Viewer
		app_external_viewer, app_external_viewer_l = groupbox('External Viewer', QFormLayout, application_general, app_general_m_l)
		app_external_viewer_l.addRow(QLabel("Most image viewers should work. Incase it doesn't," +
									   " hit me up on email/github/gitter-chat to add support."))
		self.external_viewer_path = PathLineEdit(app_external_viewer, False, '')
		self.external_viewer_path.setPlaceholderText('Right/Left-click to open folder explorer.'+
							  ' Leave empty to use default viewer')
		self.external_viewer_path.setToolTip('Right/Left-click to open folder explorer.'+
							  ' Leave empty to use default viewer')
		self.external_viewer_path.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
		app_external_viewer_l.addRow('Path:', self.external_viewer_path)

		# App / General / Rar Support
		app_rar_group, app_rar_layout = groupbox('RAR Support *', QFormLayout, self)
		app_general_m_l.addRow(app_rar_group)
		rar_info = QLabel('Specify the path to the unrar tool to enable rar support.\n'+
					'Windows: "unrar.exe" should be in the "bin" directory if you installed from the'+
					' self-extracting archive provided on github.\nOSX: You can install this via HomeBrew.'+
					' Path should be something like: "/usr/local/bin/unrar".\nLinux: Should already be'+
					' installed. You can just type "unrar". If it\'s not installed, use your package manager: pacman -S unrar')
		rar_info.setWordWrap(True)
		app_rar_layout.addRow(rar_info)
		self.path_to_unrar = PathLineEdit(self, False, filters='')
		app_rar_layout.addRow('UnRAR tool path:', self.path_to_unrar)

		# App / Monitor
		app_monitor_page = QScrollArea()
		app_monitor_page.setBackgroundRole(QPalette.Base)
		app_monitor_dummy = QWidget()
		app_monitor_page.setWidgetResizable(True)
		app_monitor_page.setWidget(app_monitor_dummy)
		application.addTab(app_monitor_page, 'Monitoring')
		app_monitor_m_l = QVBoxLayout(app_monitor_dummy)
		# App / Monitor / misc
		app_monitor_misc_group = QGroupBox('General *', self)
		app_monitor_m_l.addWidget(app_monitor_misc_group)
		app_monitor_misc_m_l = QFormLayout(app_monitor_misc_group)
		monitor_info = QLabel('Directory monitoring will monitor the specified directories for any'+
						' filesystem events. For example if you delete a gallery source in one of your'+
						' monitored directories the application will inform you and ask if'+
						' you want to delete the gallery from the application as well.')
		monitor_info.setWordWrap(True)
		app_monitor_misc_m_l.addRow(monitor_info)
		self.enable_monitor = QCheckBox('Enable directory monitoring')
		app_monitor_misc_m_l.addRow(self.enable_monitor)
		self.look_new_gallery_startup = QGroupBox('Scan for new galleries on startup', self)
		app_monitor_misc_m_l.addRow(self.look_new_gallery_startup)
		self.look_new_gallery_startup.setCheckable(True)
		look_new_gallery_startup_m_l = QVBoxLayout(self.look_new_gallery_startup)
		self.auto_add_new_galleries = QCheckBox('Automatically add found galleries')
		look_new_gallery_startup_m_l.addWidget(self.auto_add_new_galleries)

		# App / Monitor / folders
		app_monitor_group = QGroupBox('Directories *', self)
		app_monitor_m_l.addWidget(app_monitor_group, 1)
		app_monitor_folders_m_l = QVBoxLayout(app_monitor_group)
		app_monitor_folders_add = QPushButton('+')
		app_monitor_folders_add.clicked.connect(self.add_folder_monitor)
		app_monitor_folders_add.setMaximumWidth(20)
		app_monitor_folders_add.setMaximumHeight(20)
		app_monitor_folders_m_l.addWidget(app_monitor_folders_add, 0, Qt.AlignRight)
		self.folders_layout = QFormLayout()
		app_monitor_folders_m_l.addLayout(self.folders_layout)

		# App / Ignore
		app_ignore, app_ignore_m_l = new_tab('Ignore', application, True)
		app_ignore_group, app_ignore_list_l = groupbox('List', QVBoxLayout, app_monitor_dummy)
		app_ignore_m_l.addRow(app_ignore_group)
		add_buttons_l = QHBoxLayout()
		app_ignore_add_a = QPushButton('Add archive')
		app_ignore_add_a.clicked.connect(lambda: self.add_ignore_path(dir=False))
		app_ignore_add_f = QPushButton('Add directory')
		app_ignore_add_f.clicked.connect(self.add_ignore_path)
		add_buttons_l.addWidget(app_ignore_add_a, 0, Qt.AlignRight)
		add_buttons_l.addWidget(app_ignore_add_f, 1, Qt.AlignRight)
		app_ignore_list_l.addLayout(add_buttons_l)
		self.ignore_path_l = QFormLayout()
		app_ignore_list_l.addLayout(self.ignore_path_l)

		# Web
		web = QTabWidget(self)
		self.web_index = self.right_panel.addWidget(web)

		# Web / Downloader
		web_downloader, web_downloader_l = new_tab('Downloader', web)
		hen_download_group, hen_download_group_l = groupbox('g.e-hentai/exhentai',
													  QFormLayout, web_downloader)
		web_downloader_l.addRow(hen_download_group)
		self.archive_download = QRadioButton('Archive', hen_download_group)
		self.torrent_download = QRadioButton('Torrent', hen_download_group)
		download_type_l = QHBoxLayout()
		download_type_l.addWidget(self.archive_download)
		download_type_l.addWidget(self.torrent_download, 1)
		hen_download_group_l.addRow('Download Type:', download_type_l)
		self.download_directory = PathLineEdit(web_downloader)
		web_downloader_l.addRow('Destination:', self.download_directory)
		self.torrent_client = PathLineEdit(web_downloader, False, '')
		web_downloader_l.addRow(QLabel("Leave empty to use default torrent client."+
								 "\nIt is NOT recommended to import a file while it's still downloading."))
		web_downloader_l.addRow('Torrent client:', self.torrent_client)

		# Web / Metadata
		web_metadata_page = QScrollArea()
		web_metadata_page.setBackgroundRole(QPalette.Base)
		web_metadata_page.setWidgetResizable(True)
		web.addTab(web_metadata_page, 'Metadata')
		web_metadata_dummy = QWidget()
		web_metadata_page.setWidget(web_metadata_dummy)
		web_metadata_m_l = QFormLayout(web_metadata_dummy)
		self.default_ehen_url = QRadioButton('g.e-hentai.org', web_metadata_page)
		self.exhentai_ehen_url = QRadioButton('exhentai.org', web_metadata_page)
		ehen_url_l = QHBoxLayout()
		ehen_url_l.addWidget(self.default_ehen_url)
		ehen_url_l.addWidget(self.exhentai_ehen_url, 1)
		web_metadata_m_l.addRow('Default URL:', ehen_url_l)
		self.continue_a_metadata_fetcher = QCheckBox('Continue from where auto metadata fetcher left off')
		web_metadata_m_l.addRow(self.continue_a_metadata_fetcher)
		self.use_jpn_title = QCheckBox('Use japanese title')
		self.use_jpn_title.setToolTip('Choose the japenese title over the english one')
		web_metadata_m_l.addRow(self.use_jpn_title)
		time_offset_info = QLabel('We need to impose a delay between our requests to avoid getting banned.'+
							' I have made it so you cannot set the delay lower than the recommended (I don\'t'+
							' want you to get banned, anon!).\nSpecify the delay between requests in seconds.')
		time_offset_info.setWordWrap(True)
		self.web_time_offset = QSpinBox()
		self.web_time_offset.setMaximumWidth(40)
		self.web_time_offset.setMinimum(4)
		self.web_time_offset.setMaximum(99)
		web_metadata_m_l.addRow(time_offset_info)
		web_metadata_m_l.addRow('Requests delay in seconds', self.web_time_offset)
		replace_metadata_info = QLabel('When fetching for metadata the new metadata will be appended'+
								 ' to the gallery by default. This means that new data will only be added if'+
								 ' the field was empty. There is however a special case for namespace & tags.'+
								 ' We go through all the new namespace & tags to only add those that'+
								 ' do not already exists.\n\nEnabling this option makes it so that a gallery\'s old data'+
								 ' are deleted and replaced with the new data.')
		replace_metadata_info.setWordWrap(True)
		self.replace_metadata = QCheckBox('Replace old metadata with new metadata')
		web_metadata_m_l.addRow(replace_metadata_info)
		web_metadata_m_l.addRow(self.replace_metadata)
		first_hit_info = QLabel('By default, you get to choose which gallery to extract metadata from when'+
						  ' there is more than one gallery found when searching.\n'+
						  'Enabling this option makes it choose the first hit, saving you from moving your mouse.')
		first_hit_info.setWordWrap(True)
		self.always_first_hit = QCheckBox('Always choose first hit')
		web_metadata_m_l.addRow(first_hit_info)
		web_metadata_m_l.addRow(self.always_first_hit)
		self.use_gallery_link = QCheckBox('Use current gallery link')
		self.use_gallery_link.setToolTip("Metadata will be fetched from the current gallery link"+
								   " if it's a valid ex/g.e gallery url")
		web_metadata_m_l.addRow(self.use_gallery_link)

		# Web / Exhentai
		exhentai_page = QWidget(self)
		web.addTab(exhentai_page, 'ExHentai')
		ipb_layout = QFormLayout()
		exhentai_page.setLayout(ipb_layout)
		self.ipbid_edit = QLineEdit()
		self.ipbpass_edit = QLineEdit()
		exh_tutorial = QLabel(app_constants.EXHEN_COOKIE_TUTORIAL)
		exh_tutorial.setTextFormat(Qt.RichText)
		ipb_layout.addRow('IPB Member ID:', self.ipbid_edit)
		ipb_layout.addRow('IPB Pass Hash:', self.ipbpass_edit)
		ipb_layout.addRow(exh_tutorial)

		# Visual
		visual = QTabWidget(self)
		self.visual_index = self.right_panel.addWidget(visual)
		visual_general_page = QWidget()
		visual.addTab(visual_general_page, 'General')

		grid_view_general_page = QWidget()
		visual.addTab(grid_view_general_page, 'Grid View')
		grid_view_layout = QVBoxLayout()
		grid_view_layout.addWidget(QLabel('Options marked with * requires application restart'),
						   0, Qt.AlignTop)
		grid_view_general_page.setLayout(grid_view_layout)
		# grid view
		# grid view / tooltip
		self.grid_tooltip_group = QGroupBox('Tooltip', grid_view_general_page)
		self.grid_tooltip_group.setCheckable(True)
		grid_view_layout.addWidget(self.grid_tooltip_group, 0, Qt.AlignTop)
		grid_tooltip_layout = QFormLayout()
		self.grid_tooltip_group.setLayout(grid_tooltip_layout)
		grid_tooltip_layout.addRow(QLabel('Control what is'+
									' displayed in the tooltip when hovering a gallery'))
		grid_tooltips_hlayout = FlowLayout()
		grid_tooltip_layout.addRow(grid_tooltips_hlayout)
		self.visual_grid_tooltip_title = QCheckBox('Title')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_title)
		self.visual_grid_tooltip_author = QCheckBox('Author')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_author)
		self.visual_grid_tooltip_chapters = QCheckBox('Chapters')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_chapters)
		self.visual_grid_tooltip_status = QCheckBox('Status')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_status)
		self.visual_grid_tooltip_type = QCheckBox('Type')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_type)
		self.visual_grid_tooltip_lang = QCheckBox('Language')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_lang)
		self.visual_grid_tooltip_descr = QCheckBox('Description')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_descr)
		self.visual_grid_tooltip_tags = QCheckBox('Tags')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_tags)
		self.visual_grid_tooltip_last_read = QCheckBox('Last read')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_last_read)
		self.visual_grid_tooltip_times_read = QCheckBox('Times read')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_times_read)
		self.visual_grid_tooltip_pub_date = QCheckBox('Publication Date')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_pub_date)
		self.visual_grid_tooltip_date_added = QCheckBox('Date added')
		grid_tooltips_hlayout.addWidget(self.visual_grid_tooltip_date_added)
		# grid view / gallery
		grid_gallery_group = QGroupBox('Gallery', grid_view_general_page)
		grid_view_layout.addWidget(grid_gallery_group, 0, Qt.AlignTop)
		grid_gallery_main_l = QFormLayout()
		grid_gallery_main_l.setFormAlignment(Qt.AlignLeft)
		grid_gallery_group.setLayout(grid_gallery_main_l)
		grid_gallery_display = FlowLayout()
		grid_gallery_main_l.addRow('Display icon on gallery:', grid_gallery_display)
		self.external_viewer_ico = QCheckBox('External Viewer')
		grid_gallery_display.addWidget(self.external_viewer_ico)
		self.gallery_type_ico = QCheckBox('File Type')
		grid_gallery_display.addWidget(self.gallery_type_ico)
		if sys.platform.startswith('darwin'):
			grid_gallery_group.setEnabled(False)
		gallery_text_mode = QWidget()
		grid_gallery_main_l.addRow('Text Mode:', gallery_text_mode)
		gallery_text_mode_l = QHBoxLayout()
		gallery_text_mode.setLayout(gallery_text_mode_l)
		self.gallery_text_elide = QRadioButton('Elide text', gallery_text_mode)
		self.gallery_text_fit = QRadioButton('Fit text', gallery_text_mode)
		gallery_text_mode_l.addWidget(self.gallery_text_elide, 0, Qt.AlignLeft)
		gallery_text_mode_l.addWidget(self.gallery_text_fit, 0, Qt.AlignLeft)
		gallery_text_mode_l.addWidget(Spacer('h'), 1, Qt.AlignLeft)
		gallery_font = QHBoxLayout()
		grid_gallery_main_l.addRow('Font:*', gallery_font)
		self.font_lbl = QLabel()
		self.font_size_lbl = QSpinBox()
		self.font_size_lbl.setMaximum(100)
		self.font_size_lbl.setMinimum(1)
		self.font_size_lbl.setToolTip('Font size in pixels')
		choose_font = QPushButton('Choose font')
		choose_font.clicked.connect(self.choose_font)
		gallery_font.addWidget(self.font_lbl, 0, Qt.AlignLeft)
		gallery_font.addWidget(self.font_size_lbl, 0, Qt.AlignLeft)
		gallery_font.addWidget(choose_font, 0, Qt.AlignLeft)
		gallery_font.addWidget(Spacer('h'), 1, Qt.AlignLeft)
		# grid view / colors
		grid_colors_group = QGroupBox('Colors', grid_view_general_page)
		grid_view_layout.addWidget(grid_colors_group, 1, Qt.AlignTop)
		grid_colors_l = QFormLayout()
		grid_colors_group.setLayout(grid_colors_l)
		def color_lineedit():
			l = QLineEdit()
			l.setPlaceholderText('Hex colors. Eg.: #323232')
			l.setMaximumWidth(200)
			return l
		self.grid_label_color = color_lineedit()
		self.grid_title_color = color_lineedit()
		self.grid_artist_color = color_lineedit()
		grid_colors_l.addRow('Label color:', self.grid_label_color)
		grid_colors_l.addRow('Title color:', self.grid_title_color)
		grid_colors_l.addRow('Artist color:', self.grid_artist_color)

		style_page = QWidget(self)
		visual.addTab(style_page, 'Style')
		visual.setTabEnabled(0, False)
		visual.setTabEnabled(2, False)
		visual.setCurrentIndex(1)

		# Advanced
		advanced = QTabWidget(self)
		self.advanced_index = self.right_panel.addWidget(advanced)
		advanced_misc_scroll = QScrollArea(self)
		advanced_misc_scroll.setBackgroundRole(QPalette.Base)
		advanced_misc_scroll.setWidgetResizable(True)
		advanced_misc = QWidget()
		advanced_misc_scroll.setWidget(advanced_misc)
		advanced.addTab(advanced_misc_scroll, 'Misc')
		advanced_misc_main_layout = QVBoxLayout()
		advanced_misc.setLayout(advanced_misc_main_layout)
		misc_controls_layout = QFormLayout()
		advanced_misc_main_layout.addLayout(misc_controls_layout)
		# Advanced / Misc / Grid View
		misc_gridview = QGroupBox('Grid View')
		misc_controls_layout.addWidget(misc_gridview)
		misc_gridview_layout = QFormLayout()
		misc_gridview.setLayout(misc_gridview_layout)
		# Advanced / Misc / Grid View / scroll speed
		scroll_speed_spin_box = QSpinBox()
		scroll_speed_spin_box.setFixedWidth(60)
		scroll_speed_spin_box.setToolTip('Control the speed when scrolling in'+
								   ' grid view. DEFAULT: 7')
		scroll_speed_spin_box.setValue(self.scroll_speed)
		def scroll_speed(v): self.scroll_speed = v
		scroll_speed_spin_box.valueChanged[int].connect(scroll_speed)
		misc_gridview_layout.addRow('Scroll speed:', scroll_speed_spin_box)
		# Advanced / Misc / Grid View / cache size
		cache_size_spin_box = QSpinBox()
		cache_size_spin_box.setFixedWidth(120)
		cache_size_spin_box.setMaximum(999999999)
		cache_size_spin_box.setToolTip('This can greatly reduce lags/freezes in the grid view.' +
								 ' Increase the value if you experience lag when scrolling'+
								 ' through galleries. DEFAULT: 200 MiB')
		def cache_size(c): self.cache_size = (self.cache_size[0], c)
		cache_size_spin_box.setValue(self.cache_size[1])
		cache_size_spin_box.valueChanged[int].connect(cache_size)
		misc_gridview_layout.addRow('Cache Size (MiB):', cache_size_spin_box)

		# Advanced / Gallery
		advanced_gallery, advanced_gallery_m_l = new_tab('Gallery', advanced)
		def rebuild_thumbs():
			confirm_msg = QMessageBox(QMessageBox.Question, '', 'Are you sure you want to regenerate your thumbnails.',
							 QMessageBox.Yes | QMessageBox.No, self)
			if confirm_msg.exec() == QMessageBox.Yes:
				clear_cache_confirm = QMessageBox(QMessageBox.Question, '',
									  'Do you want to delete all old thumbnails before regenerating?', QMessageBox.Yes | QMessageBox.No,
									  self)
				clear_cache = False
				if clear_cache_confirm.exec() == QMessageBox.Yes:
					clear_cache = True
				gallerydb.DatabaseEmitter.RUN = False
				def start_db_activity(): gallerydb.DatabaseEmitter.RUN = True
				app_popup = ApplicationPopup(self.parent_widget)
				app_popup.info_lbl.setText("Regenerating thumbnails...")
				app_popup.admin_db = gallerydb.AdminDB()
				app_popup.admin_db.moveToThread(app_constants.GENERAL_THREAD)
				app_popup.admin_db.DONE.connect(app_popup.admin_db.deleteLater)
				app_popup.admin_db.DONE.connect(start_db_activity)
				app_popup.admin_db.DATA_COUNT.connect(app_popup.prog.setMaximum)
				app_popup.admin_db.PROGRESS.connect(app_popup.prog.setValue)
				self.init_gallery_rebuild.connect(app_popup.admin_db.rebuild_thumbs)
				app_popup.adjustSize()
				self.init_gallery_rebuild.emit(clear_cache)
				app_popup.show()

		rebuild_thumbs_info = QLabel("Clears thumbnail cache and rebuilds it, which can take a while. Tip: Useful when changing thumbnail size.")
		rebuild_thumbs_btn = QPushButton('Regenerate Thumbnails')
		rebuild_thumbs_btn.adjustSize()
		rebuild_thumbs_btn.setFixedWidth(rebuild_thumbs_btn.width())
		rebuild_thumbs_btn.clicked.connect(rebuild_thumbs)
		advanced_gallery_m_l.addRow(rebuild_thumbs_info)
		advanced_gallery_m_l.addRow(rebuild_thumbs_btn)
		g_data_fixer_group, g_data_fixer_l =  groupbox('Gallery Renamer', QFormLayout, advanced_gallery)
		g_data_fixer_group.setEnabled(False)
		advanced_gallery_m_l.addRow(g_data_fixer_group)
		g_data_regex_fix_lbl = QLabel("Rename a gallery through regular expression."+
								" A regex cheatsheet is located at About -> Regex Cheatsheet.")
		g_data_regex_fix_lbl.setWordWrap(True)
		g_data_fixer_l.addRow(g_data_regex_fix_lbl)
		self.g_data_regex_fix_edit = QLineEdit()
		self.g_data_regex_fix_edit.setPlaceholderText("Valid regex")
		g_data_fixer_l.addRow('Regex:', self.g_data_regex_fix_edit)
		self.g_data_replace_fix_edit = QLineEdit()
		self.g_data_replace_fix_edit.setPlaceholderText("Leave empty to delete matches")
		g_data_fixer_l.addRow('Replace with:', self.g_data_replace_fix_edit)
		g_data_fixer_options = FlowLayout()
		g_data_fixer_l.addRow(g_data_fixer_options)
		self.g_data_fixer_title = QCheckBox("Title", g_data_fixer_group)
		self.g_data_fixer_artist = QCheckBox("Artist", g_data_fixer_group)
		g_data_fixer_options.addWidget(self.g_data_fixer_title)
		g_data_fixer_options.addWidget(self.g_data_fixer_artist)

		# Advanced / Database
		advanced_db_page, advanced_db_page_l = new_tab('Database', advanced)
		# Advanced / Database / Import/Export
		def init_export():
			confirm_msg = QMessageBox(QMessageBox.Question, '', 'Are you sure you want to export your database? This might take a long time.',
							 QMessageBox.Yes | QMessageBox.No, self)
			if confirm_msg.exec() == QMessageBox.Yes:
				app_popup = ApplicationPopup(self.parent_widget)
				app_popup.info_lbl.setText("Exporting database...")
				app_popup.export_instance = io_misc.ImportExport()
				app_popup.export_instance.moveToThread(app_constants.GENERAL_THREAD)
				app_popup.export_instance.finished.connect(app_popup.export_instance.deleteLater)
				app_popup.export_instance.finished.connect(app_popup.close)
				app_popup.export_instance.amount.connect(app_popup.prog.setMaximum)
				app_popup.export_instance.progress.connect(app_popup.prog.setValue)
				self.init_gallery_eximport.connect(app_popup.export_instance.export_data)
				self.init_gallery_eximport.emit(None)
				app_popup.adjustSize()
				app_popup.show()
				self.close()

		def init_import():
			path = QFileDialog.getOpenFileName(self,
									  'Choose happypanda database file', filter='*.hpdb')
			path = path[0]
			if len(path) != 0:
				app_popup = ApplicationPopup(self.parent_widget)
				app_popup.restart_info.hide()
				app_popup.info_lbl.setText("Importing database file...")
				app_popup.note_info.setText("Application requires a restart after importing")
				app_popup.import_instance = io_misc.ImportExport()
				app_popup.import_instance.moveToThread(app_constants.GENERAL_THREAD)
				app_popup.import_instance.finished.connect(app_popup.import_instance.deleteLater)
				app_popup.import_instance.finished.connect(app_popup.init_restart)
				app_popup.import_instance.amount.connect(app_popup.prog.setMaximum)
				app_popup.import_instance.imported_g.connect(app_popup.info_lbl.setText)
				app_popup.import_instance.progress.connect(app_popup.prog.setValue)
				self.init_gallery_eximport.connect(app_popup.import_instance.import_data)
				self.init_gallery_eximport.emit(path)
				app_popup.adjustSize()
				app_popup.show()
				self.close()

		advanced_impexp, advanced_impexp_l = groupbox('Import/Export', QFormLayout, advanced_db_page)
		advanced_db_page_l.addRow(advanced_impexp)
		self.export_format = QComboBox(advanced_db_page)
		#self.export_format.addItem('Text File', 0)
		self.export_format.addItem('HPDB', 1)
		self.export_format.adjustSize()
		self.export_format.setFixedWidth(self.export_format.width())
		advanced_impexp_l.addRow('Export Format:', self.export_format)
		self.export_path = PathLineEdit(advanced_impexp, filters='')
		advanced_impexp_l.addRow('Export Path:', self.export_path)
		import_btn = QPushButton('Import database')
		import_btn.clicked.connect(init_import)
		export_btn = QPushButton('Export database')
		export_btn.clicked.connect(init_export)
		ex_imp_btn_l = QHBoxLayout()
		ex_imp_btn_l.addWidget(import_btn)
		ex_imp_btn_l.addWidget(export_btn)
		advanced_impexp_l.addRow(ex_imp_btn_l)


		# About
		about = QTabWidget(self)
		self.about_index = self.right_panel.addWidget(about)
		about_happypanda_page, about_layout = new_tab("About Happypanda", about, False)
		info_lbl = QLabel(app_constants.ABOUT)
		info_lbl.setWordWrap(True)
		info_lbl.setOpenExternalLinks(True)
		about_layout.addWidget(info_lbl)
		about_layout.addWidget(Spacer('v'))
		open_hp_folder = QPushButton('Open Happypanda Directory')
		open_hp_folder.clicked.connect(self.open_hp_folder)
		open_hp_folder.adjustSize()
		open_hp_folder.setFixedWidth(open_hp_folder.width())
		about_layout.addWidget(open_hp_folder)

		# About / DB Overview
		about_db_overview, about_db_overview_m_l = new_tab('DB Overview', about)
		about_stats_tab_widget = misc_db.DBOverview(self.parent_widget)
		about_db_overview_options = QHBoxLayout()
		self.tags_treeview_on_start = QCheckBox('Start with application', about_db_overview)
		make_window_btn = QPushButton('Open in window', about_db_overview)
		make_window_btn.adjustSize()
		make_window_btn.setFixedWidth(make_window_btn.width())
		about_db_overview_options.addWidget(self.tags_treeview_on_start)
		about_db_overview_options.addWidget(make_window_btn)
		def mk_btn_false():
			try:
				make_window_btn.setDisabled(False)
			except RuntimeError:
				pass
		def make_tags_treeview_window():
			self.parent_widget.tags_treeview = misc_db.DBOverview(self.parent_widget, True)
			self.parent_widget.tags_treeview.about_to_close.connect(mk_btn_false)
			make_window_btn.setDisabled(True)
			self.parent_widget.tags_treeview.show()
		if self.parent_widget.tags_treeview:
			self.parent_widget.tags_treeview.about_to_close.connect(mk_btn_false)
			make_window_btn.setDisabled(True)
		make_window_btn.clicked.connect(make_tags_treeview_window)
		about_db_overview_m_l.addRow(about_db_overview_options)
		about_db_overview_m_l.addRow(about_stats_tab_widget)

		# About / Troubleshooting
		about_troubleshoot_page = QWidget()
		about.addTab(about_troubleshoot_page, 'Bug Reporting')
		troubleshoot_layout = QVBoxLayout()
		about_troubleshoot_page.setLayout(troubleshoot_layout)
		guide_lbl = QLabel(app_constants.TROUBLE_GUIDE)
		guide_lbl.setTextFormat(Qt.RichText)
		guide_lbl.setOpenExternalLinks(True)
		guide_lbl.setWordWrap(True)
		troubleshoot_layout.addWidget(guide_lbl, 0, Qt.AlignTop)
		troubleshoot_layout.addWidget(Spacer('v'))

		# About / Search tutorial
		about_search_tut, about_search_tut_l = new_tab("Search Guide", about, True)
		g_search_lbl = QLabel(app_constants.SEARCH_TUTORIAL_TAGS)
		g_search_lbl.setWordWrap(True)
		about_search_tut_l.addRow(g_search_lbl)

		# About / Regex Cheatsheet
		about_s_regex, about_s_regex_l = new_tab("Regex Cheatsheet", about, True)
		reg_info = QLabel(app_constants.REGEXCHEAT)
		reg_info.setWordWrap(True)
		about_s_regex_l.addRow(reg_info)

	def add_folder_monitor(self, path=''):
		if not isinstance(path, str):
			path = ''
		l_edit = PathLineEdit()
		l_edit.setText(path)
		n = self.folders_layout.rowCount() + 1
		self.folders_layout.addRow('{}'.format(n), l_edit)

	def add_ignore_path(self, path='', dir=True):
		if not isinstance(path, str):
			path = ''
		l_edit = PathLineEdit(dir=dir)
		l_edit.setText(path)
		n = self.ignore_path_l.rowCount() + 1
		self.ignore_path_l.addRow('{}'.format(n), l_edit)

	def color_checker(self, txt):
		allow = False
		if len(txt) == 7:
			if txt[0] == '#':
				allow = True
		return allow

	def take_all_layout_widgets(self, l):
		n = l.rowCount()
		items = []
		for x in range(n):
			item = l.takeAt(x+1)
			items.append(item.widget())
		return items


	def choose_font(self):
		tup = QFontDialog.getFont(self)
		font = tup[0]
		if tup[1]:
			self.font_lbl.setText(font.family())
			self.font_size_lbl.setValue(font.pointSize())

	def open_hp_folder(self):
		if os.name == 'posix':
			utils.open_path(app_constants.posix_program_dir)
		else:
			utils.open_path(os.getcwd())

	def reject(self):
		self.close()
Пример #31
0
class AbstractTemplateWidget(QFrame):

    """
    TemplateWidget is used in reports and options tab.
    So it needs several common methods and common layout.
    But behavior is different. it should be defined in children classes.
    """

    def __init__(self, main_window, items):
        super().__init__()

        self.items = items
        self.visible_items = []
        self.layout = QStackedLayout()
        self.menu_layout = QVBoxLayout()
        self.templates_layout = QStackedLayout()
        self.showEvent = self._get_show_event(main_window)
        self.menu_wrapper = QVBoxLayout()

        try:
            self.ACTION_BTN_ICON
        except AttributeError:
            self.ACTION_BTN_ICON = ""

        self.setLayout(self.layout)

        self.layout.addWidget(self._get_static_widgets())

    def _get_static_widgets(self):
        """
        Create layout that does not depend on content.
        """

        hbox = QHBoxLayout()
        self.menu_wrapper.addWidget(utils.get_scrollable(self.menu_layout))
        hbox.addLayout(self.menu_wrapper, stretch=30)
        hbox.addLayout(self.templates_layout, stretch=70)
        widget = QWidget()
        widget.setLayout(hbox)
        widget.setGraphicsEffect(utils.get_shadow())
        return widget

    def _iterate_items(self):
        """
        Filter items if they has no values.
        """
        pass

    def hideEvent(self, event):
        """
        Clear menu and templates.
        """

        utils.clear_layout(self.menu_layout)
        utils.clear_layout(self.templates_layout)

    def _get_show_event(self, main_window):
        """
        Update templates list and re-select them.
        """

        def show_event(event):
            utils.clear_layout(self.menu_layout)
            utils.clear_layout(self.templates_layout)

            self.visible_items = self._iterate_items()
            self._show_menu()
            self._show_templates()
            if not self.layout.currentIndex():
                main_window.communication.action_button_toggle.emit(
                    bool(self.visible_items), self.ACTION_BTN_ICON, self.action_btn_function
                )

        return show_event

    def _show_menu(self):
        """
        Update menu on showEvent.
        """

        for i, item in enumerate(self.visible_items):
            b = QRadioButton(self._get_button_name(item))
            b.setChecked(i == 0)
            b.clicked.connect(functools.partial(self.templates_layout.setCurrentIndex, i))
            b.setObjectName("menu_button")
            self.menu_layout.addWidget(b)

        if not self.visible_items:
            self.menu_layout.addStretch()
            l = QLabel("Чтобы создать отчет\nначните заполнять данные")
            l.setAlignment(Qt.AlignCenter)
            self.menu_layout.addWidget(l)

        self.menu_layout.addStretch()

    def _show_templates(self):
        """
        Update templates on shoeEvent.
        """

        cols = 3
        templates = template_module.Template.get_all()

        for j, item in enumerate(self.visible_items):
            if not templates[item.id]:
                l = QLabel("Нет шаблонов для данного объекта\nУправлять шаблонами можно на вкладке настроек")
                l.setAlignment(Qt.AlignCenter)
                self.templates_layout.addWidget(l)
                continue
            layouts = [QVBoxLayout() for _ in range(cols)]
            for i, each in enumerate(templates[item.id]):
                b = QRadioButton(each.name)
                b.setChecked(item.template == each)
                b.clicked.connect(functools.partial(self._template_clicked, j, each))
                b.mouseDoubleClickEvent = functools.partial(self.open_template_edit_widget, j, each)
                layouts[i % cols].addWidget(b)

            wrapper = QHBoxLayout()
            for each in layouts:
                each.addStretch()
                wrapper.addLayout(each, stretch=int(100 / cols))
            self.templates_layout.addWidget(utils.get_scrollable(wrapper))

    def _template_selected(self, index, template):

        """
        Change menu item name.
        Add template for the item.
        """

        self.visible_items[index].template = template
        buttons = self.findChildren(QRadioButton, name="menu_button")
        buttons[index].setText(self._get_button_name(self.visible_items[index]))
        for i in range(len(self.visible_items)):
            ind = (i + index) % len(self.visible_items)
            if not self.visible_items[ind].template:
                self.templates_layout.setCurrentIndex(ind)
                buttons[ind].setChecked(True)
                buttons[index].setChecked(False)
                return

    def _get_button_name(self, item):
        pass

    def _double_click(self, index, template, event):
        pass

    def _template_clicked(self, index, template):
        pass

    def action_btn_function(self, event):
        pass

    def open_template_edit_widget(self, index, template, event):
        pass
Пример #32
0
class Ui_MainWindow(object):
    def setupUi(self, MainWindow, username=None, userid=1,
                host='192.168.2.171', splash=None):
        self.username = username
        self.userid = userid
        self.host = host
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1280, 768)
        MainWindow.setStyleSheet("background-color: rgb(255, 255, 255);\n")

        self.popupEnabled = False

        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.horizontalLayout = QHBoxLayout(self.centralwidget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setSpacing(0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.sideBar = QFrame(self.centralwidget)
        sizePolicy = QSizePolicy(
            QSizePolicy.Fixed,
            QSizePolicy.MinimumExpanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(100)
        sizePolicy.setHeightForWidth(
            self.sideBar.sizePolicy().hasHeightForWidth())
        self.sideBar.setSizePolicy(sizePolicy)
        self.sideBar.setMinimumSize(QSize(300, 768))
        self.sideBar.setStyleSheet(
            "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, "
            "y2:1, stop:0 rgb(0, 115, 119), "
            "stop:1 rgb(4, 147, 131));"
            )
        self.sideBar.setFrameShape(QFrame.StyledPanel)
        self.sideBar.setFrameShadow(QFrame.Raised)
        self.sideBar.setLineWidth(0)
        self.sideBar.setObjectName("sideBar")
        self.verticalLayout = QVBoxLayout(self.sideBar)
        self.verticalLayout.setContentsMargins(0, -1, 0, -1)
        self.verticalLayout.setObjectName("verticalLayout")
        self.label = QLabel(self.sideBar)
        self.label.setStyleSheet("background-color: rgba(255, 255, 255, 0);")
        self.label.setText("")
        self.label.setPixmap(QPixmap("images/logo.png"))
        self.label.setObjectName("label")
        self.verticalLayout.addWidget(self.label)
        self.buttonsLayout = QVBoxLayout()
        self.buttonsLayout.setContentsMargins(-1, 20, -1, 10)
        self.buttonsLayout.setSpacing(0)
        self.buttonsLayout.setObjectName("buttonsLayout")
        self.SimulationButton = HoverButton(self.sideBar)
        self.SimulationButton.setSelected(True)
        self.SimulationButton.setMinimumSize(QSize(0, 50))
        font = QFont()
        font.setFamily("Tahoma")
        font.setPointSize(16)
        self.SimulationButton.setFont(font)
        self.SimulationButton.setCursor(
            QCursor(Qt.PointingHandCursor))
        self.SimulationButton.setObjectName("SimulationButton")
        self.buttonsLayout.addWidget(self.SimulationButton)
        self.HistoryButton = HoverButton(self.sideBar)
        self.HistoryButton.setMinimumSize(QSize(0, 50))
        font = QFont()
        font.setFamily("Tahoma")
        font.setPointSize(16)
        self.HistoryButton.setFont(font)
        self.HistoryButton.setCursor(
            QCursor(Qt.PointingHandCursor))
        self.HistoryButton.setObjectName("HistoryButton")
        self.buttonsLayout.addWidget(self.HistoryButton)
        # self.SettingsButton = HoverButton(self.sideBar)
        # self.SettingsButton.setMinimumSize(QSize(0, 50))
        # font = QFont()
        # font.setFamily("Tahoma")
        # font.setPointSize(16)
        # self.SettingsButton.setFont(font)
        # self.SettingsButton.setCursor(
        #     QCursor(Qt.PointingHandCursor))
        # self.SettingsButton.setObjectName("SettingsButton")
        # self.buttonsLayout.addWidget(self.SettingsButton)
        self.verticalLayout.addLayout(self.buttonsLayout)
        spacerItem = QSpacerItem(
            20, 40, QSizePolicy.Minimum,
            QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItem)
        self.horizontalLayout.addWidget(self.sideBar)
        self.VScrollArea = QScrollArea(self.centralwidget)
        self.VScrollArea.setWidgetResizable(True)
        self.VScrollArea.setObjectName("VScrollArea")
        sizePolicy = QSizePolicy(
            QSizePolicy.Expanding,
            QSizePolicy.MinimumExpanding)
        self.VScrollArea.setSizePolicy(sizePolicy)
        self.VScrollArea.setMinimumSize(978, 0)
        self.MainWidget = QWidget(self.VScrollArea)
        # self.MainWidget.setGeometry(QRect(0, 0, 976, 766))
        self.MainWidget.setObjectName("MainWidget")
        self.StackedLayout = QStackedLayout(self.MainWidget)
        self.SimulationWidget = QWidget(self.MainWidget)
        self.SimulationUI = SimulationPage()
        self.SimulationUI.setupUi(
            self.SimulationWidget, username, userid, host)
        self.StackedLayout.addWidget(self.SimulationWidget)
        if splash is not None:
            splash.showMessage('Adding final touches...',
                               alignment=Qt.AlignHCenter, color=Qt.white)
        self.HistoryWidget = QWidget(self.MainWidget)
        self.HistoryUI = HistoryPage()
        self.HistoryUI.setupUi(self.HistoryWidget, username, userid, host)
        self.StackedLayout.addWidget(self.HistoryWidget)
        self.PopupWidget = QWidget(self.MainWidget)
        self.PopupUI = SimulationPage()
        self.PopupUI.setupUi(self.PopupWidget, simid=0)
        self.StackedLayout.addWidget(self.PopupWidget)
        self.VScrollArea.setWidget(self.MainWidget)
        self.horizontalLayout.addWidget(self.VScrollArea)
        MainWindow.setCentralWidget(self.centralwidget)

        # EVENTS
        self.SimulationButton.clicked.connect(self.onSimulationButton)
        self.HistoryButton.clicked.connect(self.onHistoryButton)
        self.HistoryUI.table.cellClicked.connect(self.onHistoryPageLoad)
        self.PopupUI.closeButton.clicked.connect(self.onHistoryPageClose)
        self.SimulationUI.CreateNewButton.clicked.connect(self.onNewSimulation)
        # self.SettingsButton.clicked.connect(self.onSettingsButton)

        self.retranslateUi(MainWindow)
        QMetaObject.connectSlotsByName(MainWindow)

    def onSimulationButton(self):
        if self.StackedLayout.currentIndex() != 0:
            QApplication.setOverrideCursor(
                QCursor(Qt.WaitCursor))
            # if self.StackedLayout.currentIndex() == 1:
            #     self.HistoryUI.thread.terminate()
            #     self.HistoryUI.thread.wait()
            self.SimulationButton.setSelected(True)
            self.HistoryButton.setSelected(False)
            self.StackedLayout.setCurrentIndex(0)
            QApplication.restoreOverrideCursor()
        # self.SettingsButton.setSelected(False)

    def onNewSimulation(self):
        username = self.SimulationUI.username
        userid = self.SimulationUI.userid
        host = self.SimulationUI.host

        QApplication.setOverrideCursor(
            QCursor(Qt.WaitCursor))
        self.SimulationUI.thread.quit()
        self.SimulationUI.thread.wait()
        self.SimulationUI.Cutplans.thread.quit()
        self.SimulationUI.Cutplans.thread.wait()
        self.SimulationUI = SimulationPage()
        self.SimulationUI.setupUi(
            self.SimulationWidget, username, userid, host)
        self.SimulationUI.CreateNewButton.clicked.connect(self.onNewSimulation)
        QApplication.restoreOverrideCursor()

    def onHistoryButton(self):
        self.SimulationButton.setSelected(False)
        self.HistoryButton.setSelected(True)
        if self.StackedLayout.currentIndex() == 0 and \
           self.SimulationUI.simrunning:
            msgBox = QMessageBox()
            msgBox.setWindowTitle("Simulation running...")
            msgBox.setText("Do you still want to leave the page?")
            msgBox.setStandardButtons(
                QMessageBox.Yes | QMessageBox.No)
            msgBox.setDefaultButton(QMessageBox.No)
            msgBox.setIcon(QMessageBox.Warning)
            self.HistoryButton.setSelected(True)
            r = msgBox.exec_()

            if r == QMessageBox.No:
                self.HistoryButton.setSelected(False)
                if self.StackedLayout.currentIndex() == 0:
                    self.SimulationButton.setSelected(True)
                return

        QApplication.setOverrideCursor(
            QCursor(Qt.WaitCursor))
        # if self.StackedLayout.currentIndex() == 1:
        #     self.HistoryUI.thread.terminate()
        #     self.HistoryUI.thread.wait()
        if self.popupEnabled:
            self.StackedLayout.setCurrentIndex(2)
        else:
            self.StackedLayout.setCurrentIndex(1)
        QApplication.restoreOverrideCursor()
        # self.SettingsButton.setSelected(False)

    def setUserID(self, name):
        self.username = name

    def LoadConfig(self):
        config = ConfigParser()
        config.read('config.ini')
        self.MainWidget.username = config['GENERAL']['username']
        self.MainWidget.userid = config['GENERAL']['userid']
        self.MainWidget.host = config['CONNECTION']['host']

    def retranslateUi(self, MainWindow):
        _translate = QCoreApplication.translate
        MainWindow.setWindowTitle(_translate(
            "MainWindow",
            "SeqSim — Sequal Simulator"))
        self.SimulationButton.setText(_translate("MainWindow", "Simulation"))
        self.HistoryButton.setText(_translate("MainWindow", "History"))
        # self.SettingsButton.setText(_translate("MainWindow", "Settings"))

    def onHistoryPageLoad(self, r, c):
        self.PopupUI.simid = self.HistoryUI.loader.data['SimID'][r]
        self.PopupUI.setupReadOnly()
        self.popupEnabled = True
        self.StackedLayout.setCurrentIndex(2)

    def onHistoryPageClose(self):
        self.popupEnabled = False
        self.PopupUI.Cutplans.thread.quit()
        self.PopupUI.Cutplans.thread.wait()
        self.PopupUI.Cutplans.thread.started.disconnect()
        self.PopupUI.Cutplans.threadconnected = False
        self.StackedLayout.setCurrentIndex(1)
Пример #33
0
class ComboEditor(QWidget):
    # Signals
    closeSplit = pyqtSignal('PyQt_PyObject')
    splitEditor = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject', Qt.Orientation)
    allFilesClosed = pyqtSignal()
    about_to_close_combo_editor = pyqtSignal()
    fileClosed = pyqtSignal("PyQt_PyObject")

    def __init__(self, original=False):
        super(ComboEditor, self).__init__(None)
        self.__original = original
        self.__undocked = []
        self._symbols_index = []
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)

        self.bar = ActionBar(main_combo=original)
        vbox.addWidget(self.bar)

        # Info bar
        # self.info_bar = InfoBar(self)
        # self.info_bar.setVisible(False)
        # vbox.addWidget(self.info_bar)

        self.stacked = QStackedLayout()
        vbox.addLayout(self.stacked)

        self._main_container = IDE.get_service('main_container')

        if not self.__original:
            self._main_container.fileOpened['QString'].connect(
                self._file_opened_by_main)

        self.bar.combo_files.showComboSelector.connect(
            self._main_container.show_files_handler)
        self.bar.combo_files.hideComboSelector.connect(
            self._main_container.hide_files_handler)
        self.bar.change_current['PyQt_PyObject',
                                int].connect(self._set_current)
        self.bar.splitEditor[bool].connect(self.split_editor)
        self.bar.runFile['QString'].connect(self._run_file)
        self.bar.closeSplit.connect(lambda: self.closeSplit.emit(self))
        self.bar.addToProject['QString'].connect(self._add_to_project)
        self.bar.showFileInExplorer['QString'].connect(
            self._show_file_in_explorer)
        self.bar.goToSymbol[int].connect(self._go_to_symbol)
        self.bar.undockEditor.connect(self.undock_editor)
        self.bar.reopenTab['QString'].connect(
            lambda path: self._main_container.open_file(path))
        self.bar.closeImageViewer.connect(self._close_image)
        self.bar.code_navigator.previousPressed.connect(self._navigate_code)
        self.bar.code_navigator.nextPressed.connect(self._navigate_code)
        # self.connect(self.bar, SIGNAL("recentTabsModified()"),
        #             lambda: self._main_container.recent_files_changed())
        # self.connect(self.bar.code_navigator.btnPrevious,
        #                SIGNAL("clicked()"),
        #             lambda: self._navigate_code(False))
        # self.connect(self.bar.code_navigator.btnNext, SIGNAL("clicked()"),
        #             lambda: self._navigate_code(True))

    def _navigate_code(self, operation, forward=True):
        self._main_container.navigate_code_history(operation, forward)

    #    op = self.bar.code_navigator.operation
    #    self._main_container.navigate_code_history(val, op)

    def current_editor(self):
        return self.stacked.currentWidget()

    def setFocus(self):
        super(ComboEditor, self).setFocus()
        self.current_editor().setFocus()
        self._editor_with_focus()

    def _file_opened_by_main(self, path):
        index = self.stacked.currentIndex()
        ninjaide = IDE.get_service('ide')
        editable = ninjaide.get_or_create_editable(path)
        self.add_editor(editable)
        self.bar.set_current_by_index(index)
        if index == -1:
            self.bar.set_current_by_index(0)

    def add_image_viewer(self, viewer):
        """Add Image Viewer widget to the UI area"""

        self.stacked.addWidget(viewer)
        viewer.scaleFactorChanged.connect(
            self.bar.image_viewer_controls.update_scale_label)
        viewer.imageSizeChanged.connect(
            self.bar.image_viewer_controls.update_size_label)
        self.bar.add_item(viewer.display_name(), None)
        viewer.create_scene()
        if not self.bar.isVisible():
            self.bar.setVisible(True)

    def add_editor(self, neditable, keep_index=False):
        """Add Editor Widget to the UI area."""
        if neditable.editor:
            if self.__original:
                editor = neditable.editor
            else:
                # editor = neditable.editor.clone()
                editor = self._main_container.create_editor_from_editable(
                    neditable)
                neditable.editor.link(editor)

            current_index = self.stacked.currentIndex()
            new_index = self.stacked.addWidget(editor)
            self.stacked.setCurrentIndex(new_index)
            self.bar.add_item(neditable.display_name, neditable)
            # Bar is not visible because all the files have been closed,
            # so if a new file is opened, show the bar
            if not self.bar.isVisible():
                self.bar.setVisible(True)
            if keep_index:
                self.bar.set_current_by_index(current_index)

            # Connections
            neditable.fileClosing.connect(self._close_file)
            neditable.fileSaved.connect(self._update_symbols)
            editor.editorFocusObtained.connect(self._editor_with_focus)
            editor.modificationChanged.connect(self._editor_modified)
            editor.cursor_position_changed[int, int].connect(
                self._update_cursor_position)
            editor.current_line_changed[int].connect(self._set_current_symbol)
            if neditable._swap_file.dirty:
                self._editor_modified(True, sender=editor)
            neditable.checkersUpdated.connect(self._show_notification_icon)
            # Connect file system signals only in the original
            if self.__original:
                neditable.askForSaveFileClosing.connect(self._ask_for_save)
                neditable.fileChanged.connect(self._file_has_been_modified)
            # Load Symbols
            self._load_symbols(neditable)

    def show_combo_file(self):
        self.bar.combo.showPopup()

    def show_combo_symbol(self):
        self.bar.symbols_combo.showPopup()

    def show_combo_set_language(self):
        self.bar.set_language_combo.showPopup()

    def unlink_editors(self):
        for index in range(self.stacked.count()):
            widget = self.stacked.widget(index)
            # widget.setDocument(QsciDocument())

    def clone(self):
        combo = ComboEditor()
        for neditable in self.bar.get_editables():
            combo.add_editor(neditable)
        return combo

    def split_editor(self, orientation):
        new_combo = self.clone()
        self.splitEditor.emit(self, new_combo, orientation)

    def undock_editor(self):
        new_combo = ComboEditor()
        for neditable in self.bar.get_editables():
            new_combo.add_editor(neditable)
        self.__undocked.append(new_combo)
        new_combo.setWindowTitle("NINJA-IDE")
        editor = self.current_editor()
        new_combo.set_current(editor.neditable)
        new_combo.resize(700, 500)
        new_combo.about_to_close_combo_editor.connect(self._remove_undock)
        new_combo.show()

    def _remove_undock(self):
        widget = self.sender()
        self.__undocked.remove(widget)

    def close_current_file(self):
        self.bar.about_to_close_file()

    def _close_image(self, index):
        layout_item = self.stacked.takeAt(index)
        layout_item.widget().deleteLater()
        if self.stacked.isEmpty():
            self.bar.hide()
            self.allFilesClosed.emit()

    def _close_file(self, neditable):
        index = self.bar.close_file(neditable)
        layoutItem = self.stacked.takeAt(index)
        # neditable.editor.completer.cc.unload_module()
        self.fileClosed.emit(neditable.nfile)
        layoutItem.widget().deleteLater()

        if self.stacked.isEmpty():
            self.bar.hide()
            self.allFilesClosed.emit()
            tree_symbols = IDE.get_service("symbols_explorer")
            if tree_symbols is not None:
                tree_symbols.clear()

    def _editor_with_focus(self):
        self._main_container.combo_area = self
        editor = self.current_editor()
        if editor is not None:
            self._main_container.current_editor_changed(
                editor.neditable.file_path)
            self._load_symbols(editor.neditable)
            editor.neditable.update_checkers_display()

    def _ask_for_save(self, neditable):
        val = QMessageBox.No
        fileName = neditable.nfile.file_name
        val = QMessageBox.question(
            self, (self.tr('The file %s was not saved') % fileName),
            self.tr("Do you want to save before closing?"),
            QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
        if val == QMessageBox.No:
            neditable.nfile.close(force_close=True)
        elif val == QMessageBox.Yes:
            neditable.ignore_checkers = True
            self._main_container.save_file(neditable.editor)
            neditable.nfile.close()

    @pyqtSlot("PyQt_PyObject")
    def _recovery(self, neditable):
        print("lalalal")

    def _file_has_been_modified(self, neditable):
        index = self.bar.combo_files.findData(neditable)
        self.stacked.setCurrentIndex(index)
        self.bar.combo_files.setCurrentIndex(index)

        msg_box = QMessageBox(self)
        msg_box.setIcon(QMessageBox.Information)
        msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        msg_box.setDefaultButton(QMessageBox.Yes)
        msg_box.setWindowTitle(translations.TR_FILE_HAS_BEEN_MODIFIED)
        msg_box.setText(translations.TR_FILE_MODIFIED_OUTSIDE %
                        neditable.display_name)

        result = msg_box.exec_()
        if result == QMessageBox.Yes:
            neditable.reload_file()
        return

    def _run_file(self, path):
        self._main_container.run_file(path)

    def _add_to_project(self, path):
        self._main_container._add_to_project(path)

    def _show_file_in_explorer(self, path):
        '''Connected to ActionBar's showFileInExplorer(QString)
        signal, forwards the file path on to the main container.'''

        self._main_container._show_file_in_explorer(path)

    def set_current(self, neditable):
        if neditable:
            self.bar.set_current_file(neditable)

    def _set_current(self, neditable, index):
        self.stacked.setCurrentIndex(index)
        if neditable:
            self.bar.image_viewer_controls.setVisible(False)
            self.bar.code_navigator.setVisible(True)
            self.bar.symbols_combo.setVisible(True)
            self.bar.lbl_position.setVisible(True)

            editor = self.current_editor()
            self._update_cursor_position(ignore_sender=True)
            editor.setFocus()
            self._main_container.current_editor_changed(neditable.file_path)
            self._load_symbols(neditable)
            # self._show_file_in_explorer(neditable.file_path)
            neditable.update_checkers_display()
        else:
            self.bar.combo_files.setCurrentIndex(index)
            viewer_widget = self.stacked.widget(index)
            self._main_container.current_editor_changed(
                viewer_widget.image_filename)
            self.bar.image_viewer_controls.setVisible(True)
            self.bar.code_navigator.setVisible(False)
            self.bar.symbols_combo.setVisible(False)
            self.bar.lbl_position.setVisible(False)

    def widget(self, index):
        return self.stacked.widget(index)

    def count(self):
        """Return the number of editors opened."""
        return self.stacked.count()

    def _update_cursor_position(self, line=0, col=0, ignore_sender=False):
        obj = self.sender()
        editor = self.current_editor()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            line += 1
            self.bar.update_line_col(line, col)

    def _set_current_symbol(self, line, ignore_sender=False):
        obj = self.sender()
        editor = self.current_editor()
        # Check if it's current to avoid signals from other splits.
        if ignore_sender or editor == obj:
            index = bisect.bisect(self._symbols_index, line)
            if (index >= len(self._symbols_index)
                    or self._symbols_index[index] > (line + 1)):
                index -= 1
            self.bar.set_current_symbol(index)

    def _editor_modified(self, value, sender=None):
        if sender is None:
            sender = self.sender()
        neditable = sender.neditable
        if value:
            text = "\u2022 %s" % neditable.display_name
            self.bar.update_item_text(neditable, text)
        else:
            self.bar.update_item_text(neditable, neditable.display_name)

    def _go_to_symbol(self, index):
        line = self._symbols_index[index]
        editor = self.current_editor()
        editor.go_to_line(line, center=True)
        editor.setFocus()

    def _update_symbols(self, neditable):
        editor = self.current_editor()
        # Check if it's current to avoid signals from other splits.
        if editor.neditable == neditable:
            self._load_symbols(neditable)

    def _update_combo_info(self, neditable):
        self.bar.update_item_text(neditable, neditable.display_name)
        self._main_container.current_editor_changed(neditable.file_path)

    def _load_symbols(self, neditable):
        # Get symbols handler by language
        symbols_handler = handlers.get_symbols_handler(neditable.language())
        if symbols_handler is None:
            return
        source = neditable.editor.text
        source = source.encode(neditable.editor.encoding)
        symbols, symbols_simplified = symbols_handler.obtain_symbols(
            source, simple=True)
        self._symbols_index = sorted(symbols_simplified.keys())
        symbols_simplified = sorted(list(symbols_simplified.items()),
                                    key=lambda x: x[0])
        self.bar.add_symbols(symbols_simplified)
        line, _ = neditable.editor.cursor_position
        self._set_current_symbol(line, True)
        tree_symbols = IDE.get_service('symbols_explorer')
        if tree_symbols is not None:
            tree_symbols.update_symbols_tree(symbols, neditable.file_path)

    def _show_notification_icon(self, neditable):
        checkers = neditable.sorted_checkers
        icon = QIcon()
        for items in checkers:
            checker, color, _ = items
            if checker.checks:
                if isinstance(checker.checker_icon, int):
                    icon = self.style().standardIcon(checker.checker_icon)
                elif isinstance(checker.checker_icon, str):
                    icon = QIcon(checker.checker_icon)
                # FIXME: sucks
                else:
                    icon = QIcon(checker.checker_icon)
                break
        self.bar.update_item_icon(neditable, icon)

    def show_menu_navigation(self):
        self.bar.code_navigator.show_menu_navigation()

    def closeEvent(self, event):
        self.about_to_close_combo_editor.emit()
        # self.emit(SIGNAL("aboutToCloseComboEditor()"))
        super(ComboEditor, self).closeEvent(event)

    def reject(self):
        if not self.__original:
            super(ComboEditor, self).reject()
Пример #34
0
class DeviceManagementWidget(WidgetBase):
    # noinspection PyArgumentList,PyUnresolvedReferences
    def __init__(
        self,
        parent: typing.Optional[QWidget],
        on_connection_request: ConnectionRequestCallback,
        on_disconnection_request: DisconnectionRequestCallback,
    ):
        super(DeviceManagementWidget, self).__init__(parent)
        self.setAttribute(
            Qt.WA_DeleteOnClose)  # This is required to stop background timers!

        self._port_discoverer = PortDiscoverer()
        self._port_mapping: typing.Dict[str:str] = {}

        self._port_combo = QComboBox(self)
        self._port_combo.setEditable(True)
        self._port_combo.setInsertPolicy(QComboBox.NoInsert)
        self._port_combo.setSizeAdjustPolicy(QComboBox.AdjustToContents)
        self._port_combo.setFont(get_monospace_font())
        self._port_combo.lineEdit().returnPressed.connect(
            self._on_confirmation)

        self._connect_button = make_button(self,
                                           "Connect",
                                           "disconnected",
                                           on_clicked=self._on_confirmation)
        self._connect_button.setEnabled(
            False)  # Empty by default, therefore disabled

        self._port_combo.currentTextChanged.connect(
            lambda: self._connect_button.setEnabled(
                bool(self._port_combo.currentText().strip())))

        self._status_text = QLabel(self)
        self._status_text.setText(_STATUS_WHEN_NOT_CONNECTED)
        self._status_text.setWordWrap(True)

        self._device_info_widget = LittleBobbyTablesWidget(self)

        combo_completer = QCompleter()
        combo_completer.setCaseSensitivity(Qt.CaseInsensitive)
        combo_completer.setModel(self._port_combo.model())
        self._port_combo.setCompleter(combo_completer)

        self._update_timer = QTimer(self)
        self._update_timer.timeout.connect(self._update_ports)
        self._update_timer.start(2000)

        self._connection_progress_bar = QProgressBar(self)
        self._connection_progress_bar.setMinimum(0)
        self._connection_progress_bar.setMaximum(100)

        self._connection_established = False
        self._last_task: typing.Optional[asyncio.Task] = None

        self._connection_request_callback: ConnectionRequestCallback = (
            on_connection_request)
        self._disconnection_request_callback: DisconnectionRequestCallback = (
            on_disconnection_request)

        # Layout
        self._overlay = QStackedLayout(self)
        self._init_overlay_widgets()
        self.setLayout(self._overlay)

        # Initialization
        self._update_ports()

    def on_connection_loss(self, reason: str):
        """
        This method should be invoked when the connection becomes lost.
        It will cause the widget to change its state accordingly.
        :param reason: Human-readable description of the reason in one line.
        """
        if self._connection_established:
            self._switch_state_disconnected()
            self._status_text.setText(
                f'Connection lost: {reason.strip() or "Unknown reason"}')

    def on_connection_initialization_progress_report(self,
                                                     stage_description: str,
                                                     progress: float):
        """
        This method should be periodically invoked while connection is being initialized.
        :param stage_description: Human-readable short string displaying what is currently being done.
                                  E.g. "Opening port"
        :param progress:          A float in [0, 1] that displays how much of the work has been completed so far,
                                  where 0 - nothing, 1 - all done.
        """
        if self._overlay.currentIndex() != 1:
            raise RuntimeError(
                "Invalid usage: this method can only be invoked when connection initialization is "
                "in progress. Currently it is not.")

        # noinspection PyTypeChecker
        if not (0.0 <= progress <= 1.0):
            _logger.error(
                f"Connection progress estimate falls outside of [0, 1]: {progress}"
            )

        stage_description = stage_description.strip()
        if stage_description[-1] in string.ascii_letters:
            stage_description += "..."

        self._connection_progress_bar.setValue(int(progress * 100))
        self._connection_progress_bar.setFormat(stage_description)
        self._connection_progress_bar.setAlignment(Qt.AlignCenter)

    # noinspection PyArgumentList,PyUnresolvedReferences
    def _init_overlay_widgets(self):
        # Main widget
        operational = WidgetBase(self)

        operational_layout_top = QHBoxLayout()
        operational_layout_top.addWidget(QLabel("Port:"))
        operational_layout_top.addWidget(self._port_combo, stretch=1)
        operational_layout_top.addWidget(self._connect_button)

        operational_layout_bottom = QHBoxLayout()
        operational_layout_bottom.addWidget(self._status_text)

        operational_layout = QVBoxLayout()
        operational_layout.addLayout(operational_layout_top)
        operational_layout.addLayout(operational_layout_bottom)
        operational_layout.addWidget(self._device_info_widget, 1)

        operational.setLayout(operational_layout)
        self._overlay.addWidget(operational)

        # Progress widget - shown while connecting/disconnecting
        progress = WidgetBase(self)
        progress_layout = QVBoxLayout()
        progress_layout.addStretch(1)
        progress_layout.addWidget(self._connection_progress_bar)
        progress_layout.addStretch(1)
        progress.setLayout(progress_layout)
        self._overlay.addWidget(progress)

    def _update_ports(self):
        if self._connection_established:
            return

        # noinspection PyBroadException
        try:
            ports = self._port_discoverer.get_ports()
        except Exception as ex:
            _logger.exception("Could not list ports")
            self.flash(f"Could not list ports: {ex}", duration=10)
            ports = []

        self._port_mapping = self._port_discoverer.display_ports(
            ports, self._port_combo)

    def _switch_state_connected(self, device_info: BasicDeviceInfo):
        self._connection_established = True
        self._overlay.setCurrentIndex(0)

        self._port_combo.setEnabled(False)

        self._connect_button.setEnabled(True)
        self._connect_button.setText("Disconnect")
        self._connect_button.setIcon(get_icon("connected"))

        self._status_text.setText("Connected")
        self._device_info_widget.set(device_info)

    def _switch_state_disconnected(self):
        self._connection_established = False
        self._overlay.setCurrentIndex(0)

        self._port_combo.setEnabled(True)

        self._connect_button.setEnabled(True)
        self._connect_button.setText("Connect")
        self._connect_button.setIcon(get_icon("disconnected"))

        self._device_info_widget.clear()
        self._status_text.setText(_STATUS_WHEN_NOT_CONNECTED)

        self._update_ports()

    async def _do_connect(self):
        _logger.info("Connection initialization task spawned")
        try:
            selected_port = self._port_mapping[str(
                self._port_combo.currentText()).strip()]
        except KeyError:
            selected_port = str(self._port_combo.currentText()).strip()

        # Activate the progress view and initialize it
        self._overlay.setCurrentIndex(1)
        self._connection_progress_bar.setValue(0)
        self._connection_progress_bar.setFormat("Requesting connection...")

        # noinspection PyBroadException
        try:
            device_info: BasicDeviceInfo = await self._connection_request_callback(
                selected_port)
        except Exception as ex:
            show_error(
                "Could not connect",
                f"Connection via the port {selected_port} could not be established.",
                f"Reason: {str(ex)}",
                parent=self,
            )
            self._switch_state_disconnected()
        else:
            assert device_info is not None
            self._switch_state_connected(device_info)

    async def _do_disconnect(self):
        _logger.info("Connection termination task spawned")

        # Activate the progress view and initialize it
        self._overlay.setCurrentIndex(1)
        self._connection_progress_bar.setValue(100)
        self._connection_progress_bar.setFormat(
            "Disconnecting, please wait...")

        # noinspection PyBroadException
        try:
            await self._disconnection_request_callback()
        except Exception as ex:
            _logger.exception("Disconnect request failed")
            self.flash(f"Disconnection problem: {ex}", duration=10)

        self._switch_state_disconnected()

    def _on_confirmation(self):
        # Deactivate the controls in order to prevent accidental double-entry
        self._port_combo.setEnabled(False)
        self._connect_button.setEnabled(False)

        if (self._last_task is not None) and not self._last_task.done():
            show_error(
                "I'm sorry Dave, I'm afraid I can't do that",
                "Cannot connect/disconnect while another connection/disconnection operation is still running",
                f"Pending future: {self._last_task}",
                self,
            )
        else:
            if not self._connection_established:
                self._last_task = asyncio.get_event_loop().create_task(
                    self._do_connect())
            else:
                self._last_task = asyncio.get_event_loop().create_task(
                    self._do_disconnect())
Пример #35
0
class _MainContainer(QWidget):

    ###############################################################################
    # MainContainer SIGNALS
    ###############################################################################
    """
    newFileOpened(QString)
    allTabClosed()
    runFile(QString)
    addToProject(QString)
    showFileInExplorer(QString)
    recentTabsModified()
    currentEditorChanged(QString)
    fileOpened(QString)
    ---------migrationAnalyzed()
    findOcurrences(QString)
    ---------updateFileMetadata()
    editorKeyPressEvent(QEvent)
    locateFunction(QString, QString, bool) [functionName, filePath, isVariable]
    updateLocator(QString)
    beforeFileSaved(QString)
    fileSaved(QString)
    openPreferences()
    --------openProject(QString)
    ---------dontOpenStartPage()
    """

    ###############################################################################

    fileOpened = pyqtSignal('QString')
    updateLocator = pyqtSignal('QString')
    currentEditorChanged = pyqtSignal('QString')
    beforeFileSaved = pyqtSignal('QString')
    fileSaved = pyqtSignal('QString')

    def __init__(self, parent=None):
        super(_MainContainer, self).__init__(parent)
        self.setContentsMargins(0, 0, 0, 0)
        self._parent = parent
        self._vbox = QVBoxLayout(self)
        self._vbox.setContentsMargins(0, 0, 0, 0)
        self._vbox.setSpacing(0)
        self.stack = QStackedLayout()
        self.stack.setStackingMode(QStackedLayout.StackAll)
        self._vbox.addLayout(self.stack)
        self.splitter = dynamic_splitter.DynamicSplitter()
        self.setAcceptDrops(True)
        # self._files_handler = files_handler.FilesHandler(self)
        self._add_file_folder = add_file_folder.AddFileFolderWidget(self)

        # documentation browser
        self.docPage = None
        # Code Navigation
        # self._locator = locator.GoToDefinition()
        self.__codeBack = []
        self.__codeForward = []
        self.__bookmarksFile = ''
        self.__bookmarksPos = -1
        self.__breakpointsFile = ''
        self.__breakpointsPos = -1
        self.__operations = {
            0: self._navigate_code_jumps,
            1: self._navigate_bookmarks,
            2: self._navigate_breakpoints
        }

        # self.locateFunction['QString',
        #                    'QString',
        #                    bool].connect(self.locate_function)

        IDE.register_service('main_container', self)

        # Register signals connections
        connections = ({
            'target': 'main_container',
            'signal_name': 'updateLocator',
            'slot': self._explore_file_code
        }, {
            'target': 'filesystem',
            'signal_name': 'projectOpened',
            'slot': self._explore_code
        }, {
            'target': 'projects_explorer',
            'signal_name': 'updateLocator',
            'slot': self._explore_code
        })
        """
        {'target': 'menu_file',
            'signal_name': 'openFile(QString)',
            'slot': self.open_file},
        {'target': 'explorer_container',
            'signal_name': 'goToDefinition(int)',
            'slot': self.editor_go_to_line},
        {'target': 'explorer_container',
            'signal_name': 'pep8Activated(bool)',
            'slot': self.reset_pep8_warnings},
        {'target': 'explorer_container',
            'signal_name': 'lintActivated(bool)',
            'slot': self.reset_lint_warnings},
        {'target': 'filesystem',
            'signal_name': 'projectOpened',
            'slot': self._explore_code},
        {'target': 'main_container',
            'signal_name': 'updateLocator(QString)',
            'slot': self._explore_file_code},
        )
        """

        IDE.register_signals('main_container', connections)

        self.selector = main_selector.MainSelector(self)
        self._opening_dialog = False
        self.add_widget(self.selector)

        if settings.SHOW_START_PAGE:
            self.show_start_page()

        self.selector.changeCurrent[int].connect(self._change_current_stack)
        # self.selector.removeWidget[int].connect(self._remove_item_from_stack)
        # self.selector.ready.connect(self._selector_ready)
        self.selector.animationCompleted.connect(
            self._selector_animation_completed)
        # self.closeDialog['PyQt_PyObject'].connect(self.remove_widget)

    def install(self):
        ide = IDE.get_service('ide')
        ide.place_me_on("main_container", self, "central", top=True)

        self.combo_area = combo_editor.ComboEditor(original=True)
        self.combo_area.allFilesClosed.connect(self._files_closed)
        # self.combo_area.allFilesClosed.connect(self._files_closed)
        self.splitter.add_widget(self.combo_area)
        self.add_widget(self.splitter)

        self.current_widget = self.combo_area
        # Code Locator
        self._code_locator = locator_widget.LocatorWidget(ide)

        ui_tools.install_shortcuts(self, actions.ACTIONS, ide)

    def show_locator(self):
        """Show the locator widget"""

        if not self._code_locator.isVisible():
            self._code_locator.show()

    def _explore_code(self):
        """ Update locator metadata for the current projects """

        self._code_locator.explore_code()

    def _explore_file_code(self, path):
        """ Update locator metadata for the file in path """

        self._code_locator.explore_file_code(path)

    def add_status_bar(self, status):
        self._vbox.addWidget(status)

    @property
    def combo_header_size(self):
        return self.combo_area.bar.height()

    def add_widget(self, widget):
        self.stack.addWidget(widget)

    def remove_widget(self, widget):
        self.stack.removeWidget(widget)

    def _close_dialog(self, widget):
        self.emit(SIGNAL("closeDialog(PyQt_PyObject)"), widget)
        self.disconnect(widget, SIGNAL("finished(int)"),
                        lambda: self._close_dialog(widget))

    def show_dialog(self, widget):
        self._opening_dialog = True
        # self.connect(widget, SIGNAL("finished(int)"),
        #             lambda: self._close_dialog(widget))
        self.setVisible(True)
        self.stack.addWidget(widget)
        self.show_selector()

    def show_selector(self):
        if self.selector != self.stack.currentWidget():
            temp_dir = os.path.join(QDir.tempPath(), "ninja-ide")
            if not os.path.exists(temp_dir):
                os.mkdir(temp_dir)
            collected_data = []
            current = self.stack.currentIndex()
            for index in range(self.stack.count()):
                widget = self.stack.widget(index)
                if widget == self.selector:
                    continue
                pixmap = QWidget.grab(widget, widget.rect())
                path = os.path.join(temp_dir, "screen%s.png" % index)
                pixmap.save(path)
                collected_data.append((index, path))
            self.selector.set_model(collected_data)
            self._selector_ready()
        """
        if self.selector != self.stack.currentWidget():
            temp_dir = os.path.join(QDir.tempPath(), "ninja-ide")
            if not os.path.exists(temp_dir):
                os.mkdir(temp_dir)
            collected_data = []
            current = self.stack.currentIndex()
            for index in range(self.stack.count()):
                widget = self.stack.widget(index)
                if widget == self.selector:
                    continue
                closable = True
                if widget == self.splitter:
                    closable = False
                pixmap = QWidget.grab(widget, widget.rect())
                path = os.path.join(temp_dir, "screen%s.png" % index)
                pixmap.save(path)
                if index == current:
                    self.selector.set_preview(index, path)
                    collected_data.insert(0, (index, path, closable))
                else:
                    collected_data.append((index, path, closable))
            self.selector.set_model(collected_data)
        else:
            self.selector.close_selector()
        """

    def _selector_ready(self):
        print(self.stack.currentWidget())
        self.stack.setCurrentWidget(self.selector)
        print(self.stack.currentWidget())
        self.selector.start_animation()

    def _selector_animation_completed(self):
        if self._opening_dialog:
            # We choose the last one with -2, -1 (for last one) +
            # -1 for the hidden selector widget which is in the stacked too.
            self.selector.open_item(self.stack.count() - 2)
        self._opening_dialog = False

    def _change_current_stack(self, index):
        self.stack.setCurrentIndex(index)

    def _remove_item_from_stack(self, index):
        widget = self.stack.takeAt(index)
        del widget

    def show_editor_area(self):
        self.stack.setCurrentWidget(self.splitter)

    def _files_closed(self):
        if settings.SHOW_START_PAGE:
            self.show_start_page()

    def change_visibility(self):
        """Show/Hide the Main Container area."""
        if self.isVisible():
            self.hide()
        else:
            self.show()

    def expand_symbol_combo(self):
        self.stack.setCurrentWidget(self.splitter)
        self.current_widget.show_combo_symbol()

    def expand_file_combo(self):
        self.stack.setCurrentWidget(self.splitter)
        self.current_widget.show_combo_file()

    def locate_function(self, function, filePath, isVariable):
        """Move the cursor to the proper position in the navigate stack."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            self.__codeBack.append(
                (editorWidget.file_path, editorWidget.getCursorPosition()))
            self.__codeForward = []
        self._locator.navigate_to(function, filePath, isVariable)

    def run_file(self, path):
        self.emit(SIGNAL("runFile(QString)"), path)

    def _add_to_project(self, path):
        self.emit(SIGNAL("addToProject(QString)"), path)

    def _show_file_in_explorer(self, path):
        self.emit(SIGNAL("showFileInExplorer(QString)"), path)

    def paste_history(self):
        """Paste the text from the copy/paste history."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            line, index = editorWidget.getCursorPosition()
            central = IDE.get_service('central_container')
            if central:
                editorWidget.insertAt(central.get_paste(), line, index)

    def copy_history(self):
        """Copy the selected text into the copy/paste history."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            copy = editorWidget.selectedText()
            central = IDE.get_service('central_container')
            if central:
                central.add_copy(copy)

    def import_from_everywhere(self):
        """Insert an import line from any place in the editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            dialog = from_import_dialog.FromImportDialog(editorWidget, self)
            dialog.show()

    def add_back_item_navigation(self):
        """Add an item to the back stack and reset the forward stack."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            self.__codeBack.append(
                (editorWidget.file_path, editorWidget.cursor_position))
            self.__codeForward = []

    def preview_in_browser(self):
        """Load the current html file in the default browser."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            if not editorWidget.file_path:
                self.save_file()
            ext = file_manager.get_file_extension(editorWidget.file_path)
            if ext in ('html', 'shpaml', 'handlebars', 'tpl'):
                webbrowser.open_new_tab(editorWidget.file_path)

    def add_bookmark_breakpoint(self):
        """Add a bookmark or breakpoint to the current file in the editor."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            if self.current_widget.bar.code_navigator.operation == 1:
                editorWidget.handle_bookmarks_breakpoints(
                    editorWidget.getCursorPosition()[0], Qt.ControlModifier)
            elif self.current_widget.bar.code_navigator.operation == 2:
                editorWidget.handle_bookmarks_breakpoints(
                    editorWidget.getCursorPosition()[0], Qt.NoModifier)

    def __navigate_with_keyboard(self, val):
        """Navigate between the positions in the jump history stack."""
        op = self.current_widget.bar.code_navigator.operation
        self.navigate_code_history(val, op)

    def navigate_code_history(self, val, op):
        """Navigate the code history."""
        self.__operations[op](val)

    def _navigate_code_jumps(self, val):
        """Navigate between the jump points."""
        node = None
        if not val and self.__codeBack:
            node = self.__codeBack.pop()
            editorWidget = self.get_current_editor()
            if editorWidget:
                self.__codeForward.append(
                    (editorWidget.file_path, editorWidget.getCursorPosition()))
        elif val and self.__codeForward:
            node = self.__codeForward.pop()
            editorWidget = self.get_current_editor()
            if editorWidget:
                self.__codeBack.append(
                    (editorWidget.file_path, editorWidget.getCursorPosition()))
        if node:
            filename = node[0]
            line, col = node[1]
            self.open_file(filename, line, col)

    def _navigate_breakpoints(self, val):
        """Navigate between the breakpoints."""
        # FIXME: put navigate breakpoints and bookmarks as one method.
        breakList = list(settings.BREAKPOINTS.keys())
        breakList.sort()
        if not breakList:
            return
        if self.__breakpointsFile not in breakList:
            self.__breakpointsFile = breakList[0]
        index = breakList.index(self.__breakpointsFile)
        breaks = settings.BREAKPOINTS.get(self.__breakpointsFile, [])
        lineNumber = 0
        # val == True: forward
        if val:
            if (len(breaks) - 1) > self.__breakpointsPos:
                self.__breakpointsPos += 1
                lineNumber = breaks[self.__breakpointsPos]
            elif len(breaks) > 0:
                if index < (len(breakList) - 1):
                    self.__breakpointsFile = breakList[index + 1]
                else:
                    self.__breakpointsFile = breakList[0]
                self.__breakpointsPos = 0
                lineNumber = settings.BREAKPOINTS[self.__breakpointsFile][0]
        else:
            if self.__breakpointsPos > 0:
                self.__breakpointsPos -= 1
                lineNumber = breaks[self.__breakpointsPos]
            elif len(breaks) > 0:
                self.__breakpointsFile = breakList[index - 1]
                breaks = settings.BREAKPOINTS[self.__breakpointsFile]
                self.__breakpointsPos = len(breaks) - 1
                lineNumber = breaks[self.__breakpointsPos]
        if file_manager.file_exists(self.__breakpointsFile):
            self.open_file(self.__breakpointsFile, lineNumber, None, True)
        else:
            settings.BREAKPOINTS.pop(self.__breakpointsFile)
            if settings.BREAKPOINTS:
                self._navigate_breakpoints(val)

    def _navigate_bookmarks(self, val):
        """Navigate between the bookmarks."""
        bookList = list(settings.BOOKMARKS.keys())
        bookList.sort()
        if not bookList:
            return
        if self.__bookmarksFile not in bookList:
            self.__bookmarksFile = bookList[0]
        index = bookList.index(self.__bookmarksFile)
        bookms = settings.BOOKMARKS.get(self.__bookmarksFile, [])
        lineNumber = 0
        # val == True: forward
        if val:
            if (len(bookms) - 1) > self.__bookmarksPos:
                self.__bookmarksPos += 1
                lineNumber = bookms[self.__bookmarksPos]
            elif len(bookms) > 0:
                if index < (len(bookList) - 1):
                    self.__bookmarksFile = bookList[index + 1]
                else:
                    self.__bookmarksFile = bookList[0]
                self.__bookmarksPos = 0
                lineNumber = settings.BOOKMARKS[self.__bookmarksFile][0]
        else:
            if self.__bookmarksPos > 0:
                self.__bookmarksPos -= 1
                lineNumber = bookms[self.__bookmarksPos]
            elif len(bookms) > 0:
                self.__bookmarksFile = bookList[index - 1]
                bookms = settings.BOOKMARKS[self.__bookmarksFile]
                self.__bookmarksPos = len(bookms) - 1
                lineNumber = bookms[self.__bookmarksPos]
        if file_manager.file_exists(self.__bookmarksFile):
            self.open_file(self.__bookmarksFile, lineNumber, None, True)
        else:
            # settings.BOOKMARKS.pop(self.__bookmarksFile)
            if settings.BOOKMARKS:
                self._navigate_bookmarks(val)

    def count_file_code_lines(self):
        """Count the lines of code in the current file."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            block_count = editorWidget.lines()
            blanks = re.findall('(^\n)|(^(\s+)?#)|(^( +)?($|\n))',
                                editorWidget.text(), re.M)
            blanks_count = len(blanks)
            resume = self.tr("Lines code: %s\n") % (block_count - blanks_count)
            resume += (self.tr("Blanks and commented lines: %s\n\n") %
                       blanks_count)
            resume += self.tr("Total lines: %s") % blockdget
            msgBox.exec_()

            msgBox = QMessageBox(QMessageBox.Information,
                                 self.tr("Summary of lines"), resume,
                                 QMessageBox.Ok, editorWidget)

    def editor_cut(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.cut()

    def editor_copy(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.copy()

    def editor_paste(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.paste()

    def editor_upper(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.to_upper()

    def editor_lower(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.to_lower()

    def editor_title(self):
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.to_title()

    def editor_go_to_definition(self):
        """Search the definition of the method or variable under the cursor.

        If more than one method or variable is found with the same name,
        shows a table with the results and let the user decide where to go."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.go_to_definition()

    def editor_redo(self):
        """Execute the redo action in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.redo()

    def editor_undo(self):
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.undo()

    def editor_indent_less(self):
        """Indent 1 position to the left for the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.indent_less()

    def editor_indent_more(self):
        """Indent 1 position to the right for the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.indent_more()

    def editor_insert_debugging_prints(self):
        """Insert a print statement in each selected line."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.insert_debugging_prints(editorWidget)

    def editor_insert_pdb(self):
        """Insert a pdb.set_trace() statement in tjhe current line."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.insert_pdb(editorWidget)

    def editor_comment(self):
        """Mark the current line or selection as a comment."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.comment_or_uncomment(editorWidget)

    def editor_uncomment(self):
        """Uncomment the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.uncomment(editorWidget)

    def editor_insert_horizontal_line(self):
        """Insert an horizontal lines of comment symbols."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.insert_horizontal_line(editorWidget)

    def editor_insert_title_comment(self):
        """Insert a Title surrounded by comment symbols."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.insert_title_comment(editorWidget)

    def editor_remove_trailing_spaces(self):
        """Remove the trailing spaces in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.remove_trailing_spaces(editorWidget)

    def editor_replace_tabs_with_spaces(self):
        """Replace the Tabs with Spaces in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            helpers.replace_tabs_with_spaces(editorWidget)

    def editor_move_up(self):
        """Move the current line or selection one position up."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.move_up(editorWidget)

    def editor_move_down(self):
        """Move the current line or selection one position down."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.move_down(editorWidget)

    def editor_remove_line(self):
        """Remove the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.remove_line(editorWidget)

    def editor_duplicate(self):
        """Duplicate the current line or selection."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            helpers.duplicate(editorWidget)

    def editor_highlight_word(self):
        """Highlight the occurrences of the current word in the editor."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.highlight_selected_word()

    def editor_complete_declaration(self):
        """Do the opposite action that Complete Declaration expect."""
        editorWidget = self.get_current_editor()
        if editorWidget and editorWidget.hasFocus():
            editorWidget.complete_declaration()

    def editor_go_to_line(self, line):
        """ Jump to the specified line in the current editor. """

        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.go_to_line(line)
            editorWidget.setFocus()

    def zoom_in_editor(self):
        """Increase the font size in the current editor."""

        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.zoom(1.0)

    def zoom_out_editor(self):
        """Decrease the font size in the current editor."""
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.zoom(-1.0)

    def reset_zoom(self):
        editor_widget = self.get_current_editor()
        if editor_widget is not None:
            editor_widget.reset_zoom()

    def recent_files_changed(self):
        self.emit(SIGNAL("recentTabsModified()"))

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        file_path = event.mimeData().urls()[0].toLocalFile()
        self.open_file(file_path)

    def setFocus(self):
        widget = self.get_current_widget()
        if widget:
            widget.setFocus()

    def current_editor_changed(self, filename):
        """Notify the new filename of the current editor."""
        if filename is None:
            filename = translations.TR_NEW_DOCUMENT
        self.currentEditorChanged.emit(filename)

    def show_split(self, orientation_vertical=False):
        # IDE.select_current(self.current_widget.currentWidget())
        self.current_widget.split_editor(orientation_vertical)

    def add_editor(self, fileName=None, ignore_checkers=False):
        ninjaide = IDE.get_service('ide')
        editable = ninjaide.get_or_create_editable(fileName)
        if editable.editor:
            self.current_widget.set_current(editable)
            return self.current_widget.currentWidget()
        else:
            editable.ignore_checkers = ignore_checkers

        editorWidget = self.create_editor_from_editable(editable)

        # add the tab
        keep_index = (self.splitter.count() > 1
                      and self.combo_area.stacked.count() > 0)
        self.combo_area.add_editor(editable, keep_index)

        # emit a signal about the file open
        self.fileOpened.emit(fileName)

        if not keep_index:
            self.current_widget.set_current(editable)

        self.stack.setCurrentWidget(self.splitter)

        editorWidget.setFocus()

        return editorWidget

    def create_editor_from_editable(self, editable):
        neditor = editor.create_editor(editable)

        # Connect signals
        neditor.zoomChanged[int].connect(self._show_zoom_indicator)
        neditor.destroyed.connect(self._editor_destroyed)
        editable.fileSaved.connect(self._editor_tab_was_saved)
        neditor.addBackItemNavigation.connect(self.add_back_item_navigation)
        # self.connect(editable, SIGNAL("fileSaved(PyQt_PyObject)"),
        #             self._editor_tab_was_saved)
        # editorWidget.font_changed.connect(self.show_zoom_indicator)
        # self.connect(editorWidget, SIGNAL("openDropFile(QString)"),
        #             self.open_file)
        # self.connect(editorWidget, SIGNAL("addBackItemNavigation()"),
        #             self.add_back_item_navigation)
        # self.connect(editorWidget,
        #             SIGNAL("locateFunction(QString, QString, bool)"),
        #             self._editor_locate_function)
        # self.connect(editorWidget, SIGNAL("findOcurrences(QString)"),
        #             self._find_occurrences)
        # keyPressEventSignal for plugins
        # self.connect(editorWidget, SIGNAL("keyPressEvent(QEvent)"),
        #             self._editor_keyPressEvent)

        return neditor

    def _editor_destroyed(self):
        ui_tools.FadingIndicator.editor_destroyed()

    def _show_zoom_indicator(self, text):
        neditor = self.get_current_editor()
        ui_tools.FadingIndicator.show_text(neditor,
                                           "Zoom: {}%".format(str(text)))

    def reset_pep8_warnings(self, value):
        pass
        # FIXME: check how we handle this
        # for i in range(self._tabMain.count()):
        # widget = self._tabMain.widget(i)
        # if type(widget) is editor.Editor:
        # if value:
        # widget.syncDocErrorsSignal = True
        # widget.pep8.check_style()
        # else:
        # widget.hide_pep8_errors()

    def reset_lint_warnings(self, value):
        pass
        #FIXME: check how we handle this
        # for i in range(self._tabMain.count()):
        #widget = self._tabMain.widget(i)
        #if type(widget) is editor.Editor:
        #if value:
        #widget.syncDocErrorsSignal = True
        #widget.errors.check_errors()
        #else:
        #widget.hide_lint_errors()

    def show_zoom_indicator(self, text):
        ui_tools.FadingIndicator.show_text(self, "Zoom: {0}%".format(text))

    def _find_occurrences(self, word):
        self.emit(SIGNAL("findOcurrences(QString)"), word)

    def _editor_keyPressEvent(self, event):
        self.emit(SIGNAL("editorKeyPressEvent(QEvent)"), event)

    def _editor_locate_function(self, function, filePath, isVariable):
        self.emit(SIGNAL("locateFunction(QString, QString, bool)"), function,
                  filePath, isVariable)

    def _editor_tab_was_saved(self, editable=None):
        self.updateLocator.emit(editable.file_path)
        # self.emit(SIGNAL("updateLocator(QString)"), editable.file_path)

    def get_current_widget(self):
        return self.current_widget.currentWidget()

    def get_current_editor(self):
        """Return the Actual Editor or None

        Return an instance of Editor if the Current Tab contains
        an Editor or None if it is not an instance of Editor"""
        widget = self.current_widget.currentWidget()
        if isinstance(widget, editor.NEditor):
            return widget
        return None

    def reload_file(self, editorWidget=None):
        if editorWidget is None:
            editorWidget = self.get_current_editor()
            editorWidget.neditable.reload_file()

    def open_image(self, fileName):
        try:
            if not self.is_open(fileName):
                viewer = image_viewer.ImageViewer(fileName)
                # self.add_tab(viewer, file_manager.get_basename(fileName))
                # viewer.ID = fileName
            else:
                self.move_to_open(fileName)
        except Exception as reason:
            logger.error('open_image: %s', reason)
            QMessageBox.information(self, self.tr("Incorrect File"),
                                    self.tr("The image couldn\'t be open"))

    def open_file(self, filename='', line=-1, col=0, ignore_checkers=False):
        logger.debug("will try to open %s" % filename)
        if not filename:
            logger.debug("has nofilename")
            if settings.WORKSPACE:
                directory = settings.WORKSPACE
            else:
                directory = os.path.expanduser("~")
                editorWidget = self.get_current_editor()
                ninjaide = IDE.get_service('ide')
                if ninjaide:
                    current_project = ninjaide.get_current_project()
                    if current_project is not None:
                        directory = current_project
                    elif editorWidget is not None and editorWidget.file_path:
                        directory = file_manager.get_folder(
                            editorWidget.file_path)
            extensions = ';;'.join([
                '{}(*{})'.format(e.upper()[1:], e)
                for e in settings.SUPPORTED_EXTENSIONS + ['.*', '']
            ])
            fileNames = QFileDialog.getOpenFileNames(self,
                                                     self.tr("Open File"),
                                                     directory, extensions)[0]
        else:
            logger.debug("has filename")
            fileNames = [filename]
        if not fileNames:
            return

        for filename in fileNames:
            image_extensions = ('bmp', 'gif', 'jpeg', 'jpg', 'png')
            if file_manager.get_file_extension(filename) in image_extensions:
                logger.debug("will open as image")
                self.open_image(filename)
            elif file_manager.get_file_extension(filename).endswith('ui'):
                logger.debug("will load in ui editor")
                self.w = uic.loadUi(filename)
                self.w.show()
            else:
                logger.debug("will try to open: " + filename)
                self.__open_file(filename, line, col, ignore_checkers)

    def __open_file(self, fileName='', line=-1, col=0, ignore_checkers=False):
        try:
            editorWidget = self.add_editor(fileName,
                                           ignore_checkers=ignore_checkers)
            if line != -1:
                editorWidget.go_to_line(line, col)
            self.currentEditorChanged.emit(fileName)
        except file_manager.NinjaIOException as reason:
            QMessageBox.information(self, self.tr("The file couldn't be open"),
                                    str(reason))

    def is_open(self, filename):
        pass
        #return self.tabs.is_open(filename) != -1

    def move_to_open(self, filename):
        pass
        #FIXME: add in the current split?
        #if self.tabs.is_open(filename) != -1:
        #self.tabs.move_to_open(filename)
        #self.tabs.currentWidget().setFocus()
        #self.emit(SIGNAL("currentEditorChanged(QString)"), filename)

    def get_widget_for_id(self, filename):
        pass
        #widget = None
        #index = self.tabs.is_open(filename)
        #if index != -1:
        #widget = self.tabs.widget(index)
        #return widget

    def change_open_tab_id(self, idname, newId):
        """Search for the Tab with idname, and set the newId to that Tab."""
        pass
        #index = self.tabs.is_open(idname)
        #if index != -1:
        #widget = self.tabs.widget(index)
        #tabName = file_manager.get_basename(newId)
        #self.tabs.change_open_tab_name(index, tabName)
        #widget.ID = newId

    def close_deleted_file(self, idname):
        """Search for the Tab with id, and ask the user if should be closed."""
        pass
        #index = self.tabs.is_open(idname)
        #if index != -1:
        #result = QMessageBox.question(self, self.tr("Close Deleted File"),
        #self.tr("Are you sure you want to close the deleted file?\n"
        #"The content will be completely deleted."),
        #buttons=QMessageBox.Yes | QMessageBox.No)
        #if result == QMessageBox.Yes:
        #self.tabs.removeTab(index)

    def save_file(self, editorWidget=None):
        # FIXME: check how we handle this
        if not editorWidget:
            editorWidget = self.get_current_editor()
        if editorWidget is None:
            return False
        # Ok, we have an editor instance
        # Save to file only if editor really was modified
        if editorWidget.is_modified:
            try:
                if (editorWidget.nfile.is_new_file
                        or not editorWidget.nfile.has_write_permission()):
                    return self.save_file_as()

                self.beforeFileSaved.emit(editorWidget.file_path)

                if settings.REMOVE_TRAILING_SPACES:
                    helpers.remove_trailing_spaces(editorWidget)
                # New line at end
                # FIXME: from settings
                helpers.insert_block_at_end(editorWidget)
                # Save convent
                editorWidget.neditable.save_content()
                encoding = file_manager.get_file_encoding(editorWidget.text)
                editorWidget.encoding = encoding

                self.fileSaved.emit(
                    self.tr("File Saved: {}".format(editorWidget.file_path)))

                return True
            except Exception as reason:
                logger.error('save_file: %s', reason)
                QMessageBox.information(self, self.tr("Save Error"),
                                        self.tr("The file couldn't be saved!"))
            return False

    def save_file_as(self):
        editorWidget = self.get_current_editor()
        if not editorWidget:
            return False
        try:
            filters = '(*.py);;(*.*)'
            if editorWidget.file_path:  # existing file
                ext = file_manager.get_file_extension(editorWidget.file_path)
                if ext != 'py':
                    filters = '(*.%s);;(*.py);;(*.*)' % ext
            save_folder = self._get_save_folder(editorWidget.file_path)
            fileName = QFileDialog.getSaveFileName(self._parent,
                                                   self.tr("Save File"),
                                                   save_folder, filters)[0]
            if not fileName:
                return False

            if settings.REMOVE_TRAILING_SPACES:
                helpers.remove_trailing_spaces(editorWidget)

            ext = file_manager.get_file_extension(fileName)
            if not ext:
                fileName = '%s.%s' % (
                    fileName,
                    'py',
                )

            editorWidget.neditable.save_content(path=fileName)
            # editorWidget.register_syntax(
            #     file_manager.get_file_extension(fileName))

            self.fileSaved.emit(self.tr("File Saved: {}".format(fileName)))

            self.currentEditorChanged.emit(fileName)

            return True
        except file_manager.NinjaFileExistsException as ex:
            QMessageBox.information(
                self, self.tr("File Already Exists"),
                (self.tr("Invalid Path: the file '%s' "
                         " already exists.") % ex.filename))
        except Exception as reason:
            logger.error('save_file_as: %s', reason)
            QMessageBox.information(self, self.tr("Save Error"),
                                    self.tr("The file couldn't be saved!"))
        return False

    def _get_save_folder(self, fileName):
        """
        Returns the root directory of the 'Main Project' or the home folder
        """
        ninjaide = IDE.get_service('ide')
        current_project = ninjaide.get_current_project()
        if current_project:
            return current_project.path
        return os.path.expanduser("~")

    def save_project(self, projectFolder):
        pass
        #FIXME: check how we handle this
        #for i in range(self._tabMain.count()):
        #editorWidget = self._tabMain.widget(i)
        #if type(editorWidget) is editor.Editor and \
        #file_manager.belongs_to_folder(projectFolder,
        #editorWidget.file_path):
        #reloaded = self._tabMain.check_for_external_modifications(
        #editorWidget)
        #if not reloaded:
        #self.save_file(editorWidget)
        #for i in range(self.tabsecondary.count()):
        #editorWidget = self.tabsecondary.widget(i)
        #if type(editorWidget) is editor.Editor and \
        #file_manager.belongs_to_folder(projectFolder,
        #editorWidget.file_path):
        #reloaded = self.tabsecondary.check_for_external_modifications(
        #editorWidget)
        #if not reloaded:
        #self.save_file(editorWidget)

    def save_all(self):
        pass
        #FIXME: check how we handle this
        #for i in range(self._tabMain.count()):
        #editorWidget = self._tabMain.widget(i)
        #if type(editorWidget) is editor.Editor:
        #reloaded = self._tabMain.check_for_external_modifications(
        #editorWidget)
        #if not reloaded:
        #self.save_file(editorWidget)
        #for i in range(self.tabsecondary.count()):
        #editorWidget = self.tabsecondary.widget(i)
        #self.tabsecondary.check_for_external_modifications(editorWidget)
        #if type(editorWidget) is editor.Editor:
        #reloaded = self.tabsecondary.check_for_external_modifications(
        #editorWidget)
        #if not reloaded:
        #self.save_file(editorWidget)

    def call_editors_function(self, call_function, *arguments):
        pass
        #args = arguments[0]
        #kwargs = arguments[1]
        #for i in range(self.tabs.count()):
        #editorWidget = self.tabs.widget(i)
        #if isinstance(editorWidget, editor.Editor):
        #function = getattr(editorWidget, call_function)
        #function(*args, **kwargs)
        #TODO: add other splits

    def show_start_page(self):
        start = self.stack.widget(0)
        if isinstance(start, start_page.StartPage):
            self.stack.setCurrentIndex(0)
        else:
            startPage = start_page.StartPage(parent=self)
            # self.connect(startPage, SIGNAL("openProject(QString)"),
            #             self.open_project)
            # self.connect(startPage, SIGNAL("openPreferences()"),
            #             lambda: self.emit(SIGNAL("openPreferences()")))
            # Connections
            startPage.newFile.connect(self.add_editor)
            self.stack.insertWidget(0, startPage)
            self.stack.setCurrentIndex(0)

    def show_python_doc(self):
        if sys.platform == 'win32':
            self.docPage = browser_widget.BrowserWidget(
                'http://docs.python.org/')
        else:
            process = runner.start_pydoc()
            self.docPage = browser_widget.BrowserWidget(process[1], process[0])
        self.add_tab(self.docPage, translations.TR_PYTHON_DOC)

    def show_report_bugs(self):
        webbrowser.open(resources.BUGS_PAGE)

    def show_plugins_doc(self):
        bugsPage = browser_widget.BrowserWidget(resources.PLUGINS_DOC, self)
        self.add_tab(bugsPage, translations.TR_HOW_TO_WRITE_PLUGINS)

    def editor_jump_to_line(self, lineno=None):
        """Jump to line *lineno* if it is not None
        otherwise ask to the user the line number to jump
        """
        editorWidget = self.get_current_editor()
        if editorWidget:
            editorWidget.jump_to_line(lineno=lineno)

    def get_opened_documents(self):
        #return self.tabs.get_documents_data()
        return []

    def check_for_unsaved_files(self):
        pass
        #return self.tabs._check_unsaved_tabs()

    def get_unsaved_files(self):
        pass
        #return self.tabs.get_unsaved_files()

    def reset_editor_flags(self):
        pass
        #for i in range(self.tabs.count()):
        #widget = self.tabs.widget(i)
        #if isinstance(widget, editor.Editor):
        #widget.set_flags()

    def _specify_syntax(self, widget, syntaxLang):
        if isinstance(widget, editor.Editor):
            widget.restyle(syntaxLang)

    def apply_editor_theme(self, family, size):
        pass
        #for i in range(self.tabs.count()):
        #widget = self.tabs.widget(i)
        #if isinstance(widget, editor.Editor):
        #widget.restyle()
        #widget.set_font(family, size)

    def update_editor_margin_line(self):
        pass
        #for i in range(self.tabs.count()):
        #widget = self.tabs.widget(i)
        #if isinstance(widget, editor.Editor):
        #widget._update_margin_line()

    def open_project(self, path):
        self.emit(SIGNAL("openProject(QString)"), path)

    def close_python_doc(self):
        pass
        # close the python document server (if running)
        # if self.docPage:
        #    index = self.tabs.indexOf(self.docPage)
        #    self.tabs.removeTab(index)
        #    assign None to the browser
        #    self.docPage = None

    def close_file(self):
        self.current_widget.close_current_file()

    def create_file(self, base_path, project_path):
        self._add_file_folder.create_file(base_path, project_path)

    def create_folder(self, base_path, project_path):
        self._add_file_folder.create_folder(base_path, project_path)

    def change_tab(self):
        """Change the tab in the current TabWidget."""
        self.stack.setCurrentWidget(self.splitter)
        # self._files_handler.next_item()

    def change_tab_reverse(self):
        """Change the tab in the current TabWidget backwards."""
        self.stack.setCurrentWidget(self.splitter)
        # self._files_handler.previous_item()

    def toggle_tabs_and_spaces(self):
        """Toggle Show/Hide Tabs and Spaces"""

        settings.SHOW_TABS_AND_SPACES = not settings.SHOW_TABS_AND_SPACES
        qsettings = IDE.ninja_settings()
        qsettings.setValue('preferences/editor/show_tabs_and_spaces',
                           settings.SHOW_TABS_AND_SPACES)
        neditor = self.get_current_editor()
        if neditor is not None:
            neditor.show_whitespaces = settings.SHOW_TABS_AND_SPACES

    def show_navigation_buttons(self):
        """Show Navigation menu."""
        self.stack.setCurrentWidget(self.splitter)
        self.combo_area.show_menu_navigation()

    def change_split_focus(self):
        pass
        #FIXME: check how we handle this
        #if self.actualTab == self._tabMain and self.tabsecondary.isVisible():
        #self.actualTab = self.tabsecondary
        #else:
        #self.actualTab = self._tabMain
        #widget = self.actualTab.currentWidget()
        #if widget is not None:
        #widget.setFocus()

    def shortcut_index(self, index):
        pass
        #self.tabs.setCurrentIndex(index)

    def print_file(self):
        """Call the print of ui_tool

        Call print of ui_tool depending on the focus of the application"""
        #TODO: Add funtionality for proyect tab and methods tab
        editorWidget = self.get_current_editor()
        if editorWidget is not None:
            fileName = "newDocument.pdf"
            if editorWidget.file_path:
                fileName = file_manager.get_basename(editorWidget.file_path)
                fileName = fileName[:fileName.rfind('.')] + '.pdf'
            ui_tools.print_file(fileName, editorWidget.print_)

    def split_assistance(self):
        dialog = split_orientation.SplitOrientation(self)
        dialog.show()

    # def close_split(self):
    #    if self.current_widget != self.combo_area:
    #        self.current_widget.bar.close_split()

    # def split_vertically(self):
    #    self.show_split(False)

    # def split_horizontally(self):
    #    self.show_split(True)

    def navigate_back(self):
        self.__navigate_with_keyboard(False)

    def navigate_forward(self):
        self.__navigate_with_keyboard(True)
Пример #36
0
class Blur(Plugin):
    def __init__(self, parent = None):
        
        super(Blur, self).__init__()
        
        self.setObjectName('blur') # should be plugin name
        
        # declare all parameter widgets below
        vbox1 = QVBoxLayout()
        vbox1.setSpacing(2)
        hbox1 = QHBoxLayout()
        hbox1.setSpacing(2)
            
        labels = ['box', 'Gaussian', 'Median', 'Bilateral']
        groupBox, self.bgrpBlurMethod = radio_filler('Blur Method', labels, 
                                buttons_per_row = 2, tool_tips = None)
        self.bgrpBlurMethod.buttonClicked.connect(self.radio_handler)
        
        self.stackedLayout = QStackedLayout()
        self.boxPage      = QWidget()
        self.gaussianPage = QWidget()
        self.medianPage   = QWidget()
        self.bilateralPage   = QWidget()
        
        gridLayout = QGridLayout()
        gridLayout.setSpacing(2)
        self.dblBoxKSize = QDoubleSpinBox()
        self.dblBoxKSize.setObjectName('dblBoxKSize')
        self.dblBoxKSize.setValue(5)
        self.dblBoxKSize.setMinimum(1)
        self.dblBoxKSize.setSingleStep(2)
        tt = '''blurring kernel size'''
        self.dblBoxKSize.setToolTip(tt)
        gridLayout.addWidget(QLabel('ksize'))
        gridLayout.addWidget(self.dblBoxKSize)
        self.boxPage.setLayout(gridLayout)
        
        gridLayout = QGridLayout()
        gridLayout.setSpacing(2)
        self.dblGaussianKSize = QDoubleSpinBox()
        self.dblGaussianKSize.setObjectName('dblGaussianKSize')
        self.dblGaussianKSize.setValue(5)
        self.dblGaussianKSize.setMinimum(1)
        self.dblGaussianKSize.setSingleStep(2)
        tt = '''blurring kernel size'''
        self.dblGaussianKSize.setToolTip(tt)
        self.dblSigma = QDoubleSpinBox()
        self.dblSigma.setObjectName('dblSigma')
        self.dblSigma.setValue(0)
        tt = '''Gaussian kernel standard deviation.  If sigma is zero, it is computed from ksize
                (see getGaussianKernel for details);'''
        self.dblSigma.setToolTip(tt)
        self.dblSigma.setSingleStep(.1)
        gridLayout.addWidget(QLabel('ksize'), 0, 0)
        gridLayout.addWidget(self.dblGaussianKSize, 0 , 1)
        gridLayout.addWidget(QLabel('sigma'), 1 ,0 )
        gridLayout.addWidget(self.dblSigma, 1, 1)
        self.gaussianPage.setLayout(gridLayout)
        
        gridLayout = QGridLayout()
        gridLayout.setSpacing(2)
        self.dblMedianKSize = QDoubleSpinBox()
        self.dblMedianKSize.setObjectName('dblMedianKSize')
        self.dblMedianKSize.setValue(5)
        self.dblMedianKSize.setMinimum(1)
        self.dblMedianKSize.setSingleStep(2)
        tt = '''aperture linear size; it must be odd and greater than 1, 
                for example: 3, 5, 7 ... '''
        self.dblMedianKSize.setToolTip(tt)
        gridLayout.addWidget(QLabel('ksize'))
        gridLayout.addWidget(self.dblMedianKSize)
        self.medianPage.setLayout(gridLayout)
        
        gridLayout = QGridLayout()
        gridLayout.setSpacing(2)
        self.dblD = QDoubleSpinBox()
        self.dblD.setObjectName('dblD')
        self.dblD.setValue(5)
        self.dblD.setMinimum(1)
        self.dblD.setSingleStep(1)
        tt = '''Diameter of each pixel neighborhood that is used during filtering.
                If it is non-positive, it is computed from sigma'''
        self.dblD.setToolTip(tt)
        self.dblBSigma = QDoubleSpinBox()
        self.dblBSigma.setObjectName('dblBSigma')
        self.dblBSigma.setValue(50)
        tt = '''Filter sigma in the color space. A larger value of the parameter
                means that farther colors within the pixel neighborhood (see 
                sigmaSpace) will be mixed together, resulting in larger areas 
                of semi-equal color.'''
        self.dblBSigma.setToolTip(tt)
        self.dblBSigma.setSingleStep(.1)
        gridLayout.addWidget(QLabel('d'), 0, 0)
        gridLayout.addWidget(self.dblD, 0 , 1)
        gridLayout.addWidget(QLabel('sigma'), 1, 0)
        gridLayout.addWidget(self.dblBSigma ,1 ,1)
        self.bilateralPage.setLayout(gridLayout)
        
        self.stackedLayout.addWidget(self.boxPage)
        self.stackedLayout.addWidget(self.gaussianPage)
        self.stackedLayout.addWidget(self.medianPage)
        self.stackedLayout.addWidget(self.bilateralPage)
        
        vbox1.addWidget(groupBox)
        vbox1.addLayout(self.stackedLayout)

        self.setLayout(vbox1)
        # ~ self.img = None
        
        # set all sizepolicy s to preferred
        for item in self.findChildren(QWidget):
            item.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        
        # set margins and spacing for all Layouts
        for item in self.findChildren(QLayout):
            item.setContentsMargins(0, 0, 0, 0)
            item.setSpacing(2)
        
        self.bgrpBlurMethod.button(0).setChecked(True)
        
    def radio_handler(self):
        self.stackedLayout.setCurrentIndex(self.bgrpBlurMethod.checkedId())
    
    def mainFunc(self, playing, scriptList, row):
        
        if self.inputImg is not None:
            if self.stackedLayout.currentIndex() == 0:  # box blur
                ksize = int(self.dblBoxKSize.value())
                ksize = (ksize, ksize)
                # ~ anchor = (-1, -1)
                self.outputImg = cv.blur(self.inputImg,
                                           ksize)
            elif self.stackedLayout.currentIndex() == 1:  # Gaussian blur
                ksize = int(self.dblGaussianKSize.value())
                ksize = (ksize, ksize)
                sigma = self.dblSigma.value()
                # ~ anchor = (-1, -1)
                self.outputImg = cv.GaussianBlur(self.inputImg,
                                           ksize,
                                           sigma, sigma)
                                           
            elif self.stackedLayout.currentIndex() == 2:  # median blur
                ksize = int(self.dblMedianKSize.value())
                self.outputImg = cv.medianBlur(self.inputImg,
                                           ksize)
            
            elif self.stackedLayout.currentIndex() == 3:  # bilateral
                d = int(self.dblD.value())
                sigma = self.dblBSigma.value()
                self.outputImg = cv.bilateralFilter(self.inputImg, d, sigma, sigma)
Пример #37
0
class ProjectTreeColumn(QDialog):

    # Signals
    dockWidget = pyqtSignal('PyQt_PyObject')
    undockWidget = pyqtSignal()
    changeTitle = pyqtSignal('PyQt_PyObject', 'QString')
    updateLocator = pyqtSignal()

    def __init__(self, parent=None):
        super(ProjectTreeColumn, self).__init__(parent)
        vbox = QVBoxLayout(self)
        # vbox.setSizeConstraint(QVBoxLayout.SetDefaultConstraint)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)
        self._buttons = []
        combo_container = ui_tools.StyledBar()
        combo_container.setProperty('gradient', True)
        combo_layout = QVBoxLayout(combo_container)
        combo_layout.setContentsMargins(0, 0, 0, 0)
        self._combo_project = QComboBox()
        combo_layout.addWidget(self._combo_project)
        self._combo_project.setProperty("gradient", True)
        self._combo_project.setContextMenuPolicy(Qt.CustomContextMenu)
        vbox.addWidget(combo_container)
        self._projects_area = QStackedLayout()
        logger.debug("This is the projects area")
        vbox.addLayout(self._projects_area)

        self.projects = []

        self._combo_project.currentIndexChanged[int].connect(
            self._change_current_project)
        self._combo_project.customContextMenuRequested[
            'const QPoint&'].connect(self.context_menu_for_root)

        connections = (
            {
                'target': 'main_container',
                'signal_name': 'addToProject(QString)',
                'slot': self._add_file_to_project
            },
            {
                'target': 'main_container',
                'signal_name': 'showFileInExplorer(QString)',
                'slot': self._show_file_in_explorer
            },
        )
        IDE.register_service('projects_explorer', self)
        IDE.register_signals('projects_explorer', connections)
        ExplorerContainer.register_tab(translations.TR_TAB_PROJECTS, self)

        # FIXME: Should have a ninja settings object that stores tree state
        # FIXME: Or bettter, application data object
        # TODO: check this:
        # self.connect(ide, SIGNAL("goingDown()"),
        #    self.tree_projects.shutdown)

        # def close_project_signal():
        #    self.emit(SIGNAL("updateLocator()"))

    def install_tab(self):
        ide = IDE.get_service('ide')
        ui_tools.install_shortcuts(self, actions.PROJECTS_TREE_ACTIONS, ide)

        ide.goingDown.connect(self.close)

    def load_session_projects(self, projects):
        for project in projects:
            if os.path.exists(project):
                self._open_project_folder(project)

    def open_project_folder(self, folderName=None):
        if settings.WORKSPACE:
            directory = settings.WORKSPACE
        else:
            directory = os.path.expanduser("~")

        if folderName is None:
            folderName = QFileDialog.getExistingDirectory(
                self, translations.TR_OPEN_PROJECT_DIRECTORY, directory)
            logger.debug("Choosing Foldername")
        if folderName:
            if not file_manager.folder_exists(folderName):
                QMessageBox.information(
                    self, translations.TR_PROJECT_NONEXIST_TITLE,
                    translations.TR_PROJECT_NONEXIST % folderName)
                return
            logger.debug("Opening %s" % folderName)
            for p in self.projects:
                if p.project.path == folderName:
                    QMessageBox.information(
                        self, translations.TR_PROJECT_PATH_ALREADY_EXIST_TITLE,
                        translations.TR_PROJECT_PATH_ALREADY_EXIST %
                        folderName)
                    return
            self._open_project_folder(folderName)

    def _open_project_folder(self, folderName):
        ninjaide = IDE.get_service("ide")
        # TODO: handle exception when .nja file is empty
        project = NProject(folderName)
        qfsm = ninjaide.filesystem.open_project(project)
        if qfsm:
            self.add_project(project)
            self.save_recent_projects(folderName)
            # FIXME: show editor area?
            # main_container = IDE.get_service('main_container')
            # if main_container:
            #    main_container.show_editor_area()
            if len(self.projects) > 1:
                title = "%s (%s)" % (translations.TR_TAB_PROJECTS,
                                     len(self.projects))
            else:
                title = translations.TR_TAB_PROJECTS
            self.changeTitle.emit(self, title)

    def _add_file_to_project(self, path):
        """Add the file for 'path' in the project the user choose here."""
        if self._projects_area.count() > 0:
            pathProject = [self.current_project]
            addToProject = add_to_project.AddToProject(pathProject, self)
            addToProject.exec_()
            if not addToProject.pathSelected:
                return
            main_container = IDE.get_service('main_container')
            if not main_container:
                return
            editorWidget = main_container.get_current_editor()
            if not editorWidget.file_path:
                name = QInputDialog.getText(
                    None, translations.TR_ADD_FILE_TO_PROJECT,
                    translations.TR_FILENAME + ": ")[0]
                if not name:
                    QMessageBox.information(
                        self, translations.TR_INVALID_FILENAME,
                        translations.TR_INVALID_FILENAME_ENTER_A_FILENAME)
                    return
            else:
                name = file_manager.get_basename(editorWidget.file_path)
            new_path = file_manager.create_path(addToProject.pathSelected,
                                                name)
            ide_srv = IDE.get_service("ide")
            old_file = ide_srv.get_or_create_nfile(path)
            new_file = old_file.save(editorWidget.text(), new_path)
            # FIXME: Make this file replace the original in the open tab
        else:
            pass
            # Message about no project

    def _show_file_in_explorer(self, path):
        '''Iterate through the list of available projects and show
        the current file in the explorer view for the first
        project that contains it (i.e. if the same file is
        included in multiple open projects, the path will be
        expanded for the first project only).
        Note: This slot is connected to the main container's
        "showFileInExplorer(QString)" signal.'''
        central = IDE.get_service('central_container')
        if central and not central.is_lateral_panel_visible():
            return
        for project in self.projects:
            index = project.model().index(path)
            if index.isValid():
                # This highlights the index in the tree for us
                project.scrollTo(index, QAbstractItemView.EnsureVisible)
                project.setCurrentIndex(index)
                break

    def add_project(self, project):
        if project not in self.projects:
            self._combo_project.addItem(project.name)
            ptree = TreeProjectsWidget(project)
            self._projects_area.addWidget(ptree)
            ptree.closeProject['PyQt_PyObject'].connect(self._close_project)
            pmodel = project.model
            ptree.setModel(pmodel)
            pindex = pmodel.index(pmodel.rootPath())
            ptree.setRootIndex(pindex)
            self.projects.append(ptree)
            current_index = self._projects_area.count()
            self._projects_area.setCurrentIndex(current_index - 1)
            self._combo_project.setCurrentIndex(current_index - 1)

    def _close_project(self, widget):
        """Close the project related to the tree widget."""
        index = self._projects_area.currentIndex()
        self.projects.remove(widget)
        self._projects_area.takeAt(index)
        self._combo_project.removeItem(index)
        index = self._combo_project.currentIndex()
        self._projects_area.setCurrentIndex(index)
        ninjaide = IDE.get_service('ide')
        ninjaide.filesystem.close_project(widget.project.path)
        widget.deleteLater()
        if len(self.projects) > 1:
            title = "%s (%s)" % (translations.TR_TAB_PROJECTS,
                                 len(self.projects))
        else:
            title = translations.TR_TAB_PROJECTS
        self.changeTitle.emit(self, title)
        self.updateLocator.emit()

    def _change_current_project(self, index):
        self._projects_area.setCurrentIndex(index)

    def close_opened_projects(self):
        for project in reversed(self.projects):
            self._close_project(project)

    def save_project(self):
        """Save all the opened files that belongs to the actual project."""
        if self._projects_area.count() > 0:
            path = self.current_project.path
            main_container = IDE.get_service('main_container')
            if path and main_container:
                main_container.save_project(path)

    def create_new_project(self):
        wizard = new_project_manager.NewProjectManager(self)
        wizard.show()

    @property
    def current_project(self):
        if self._projects_area.count() > 0:
            return self._projects_area.currentWidget().project

    @property
    def current_tree(self):
        return self._projects_area.currentWidget()

    def set_current_item(self, path):
        if self.current_project is not None:
            self.current_tree.set_current_item(path)

    def save_recent_projects(self, folder):
        settings = IDE.data_settings()
        recent_project_list = settings.value('recentProjects', {})
        # if already exist on the list update the date time
        projectProperties = json_manager.read_ninja_project(folder)
        name = projectProperties.get('name', '')
        description = projectProperties.get('description', '')

        if name == '':
            name = file_manager.get_basename(folder)

        if description == '':
            description = translations.TR_NO_DESCRIPTION

        if folder in recent_project_list:
            properties = recent_project_list[folder]
            properties["lastopen"] = QDateTime.currentDateTime()
            properties["name"] = name
            properties["description"] = description
            recent_project_list[folder] = properties
        else:
            recent_project_list[folder] = {
                "name": name,
                "description": description,
                "isFavorite": False,
                "lastopen": QDateTime.currentDateTime()
            }
            # if the length of the project list it's high that 10 then delete
            # the most old
            # TODO: add the length of available projects to setting
            if len(recent_project_list) > 10:
                del recent_project_list[self.find_most_old_open(
                    recent_project_list)]
        settings.setValue('recentProjects', recent_project_list)

    def find_most_old_open(self, recent_project_list):
        listFounder = []
        for recent_project_path, content in list(recent_project_list.items()):
            listFounder.append(
                (recent_project_path,
                 int(content["lastopen"].toString("yyyyMMddHHmmzzz"))))
        listFounder = sorted(listFounder,
                             key=lambda date: listFounder[1],
                             reverse=True)  # sort by date last used
        return listFounder[0][0]

    def reject(self):
        if self.parent() is None:
            self.dockWidget.emit(self)

    def closeEvent(self, event):
        self.dockWidget.emit(self)
        event.ignore()

    def context_menu_for_root(self):
        menu = QMenu(self)
        path = self.current_tree.project.path
        action_add_file = menu.addAction(QIcon(":img/new"),
                                         translations.TR_ADD_NEW_FILE)
        action_add_folder = menu.addAction(QIcon(":img/openProj"),
                                           translations.TR_ADD_NEW_FOLDER)
        action_create_init = menu.addAction(translations.TR_CREATE_INIT)

        # self.connect(action_add_file, SIGNAL("triggered()"),
        #             lambda: self.current_tree._add_new_file(path))
        # self.connect(action_add_folder, SIGNAL("triggered()"),
        #             lambda: self.current_tree._add_new_folder(path))
        # self.connect(action_create_init, SIGNAL("triggered()"),
        #             lambda: self.current_tree._create_init(path))
        # menu.addSeparator()
        # actionRunProject = menu.addAction(QIcon(
        #    ":img/play"), translations.TR_RUN_PROJECT)
        # self.connect(actionRunProject, SIGNAL("triggered()"),
        #             self.current_tree._execute_project)
        # if self.current_tree._added_to_console:
        #    actionRemoveFromConsole = menu.addAction(
        #        translations.TR_REMOVE_PROJECT_FROM_PYTHON_CONSOLE)
        #    self.connect(actionRemoveFromConsole, SIGNAL("triggered()"),
        #                 self.current_tree._remove_project_from_console)
        # else:
        #    actionAdd2Console = menu.addAction(
        #        translations.TR_ADD_PROJECT_TO_PYTHON_CONSOLE)
        #    self.connect(actionAdd2Console, SIGNAL("triggered()"),
        #                 self.current_tree._add_project_to_console)
        # actionShowFileSizeInfo = menu.addAction(
        #                          translations.TR_SHOW_FILESIZE)
        # self.connect(actionShowFileSizeInfo, SIGNAL("triggered()"),
        #             self.current_tree.show_filesize_info)
        # actionProperties = menu.addAction(QIcon(":img/pref"),
        #                                  translations.TR_PROJECT_PROPERTIES)
        # self.connect(actionProperties, SIGNAL("triggered()"),
        #             self.current_tree.open_project_properties)
        action_properties = menu.addAction(translations.TR_PROJECT_PROPERTIES)
        action_properties.triggered.connect(
            self.current_tree.open_project_properties)
        # menu.addSeparator()
        action_close = menu.addAction(translations.TR_CLOSE_PROJECT)
        action_add_file.triggered.connect(
            lambda: self.current_tree._add_new_file(path))
        action_add_folder.triggered.connect(
            lambda: self.current_tree._add_new_folder(path))
        action_close.triggered.connect(self.current_tree._close_project)
        # self.connect(action_close, SIGNAL("triggered()"),
        #             self.current_tree._close_project)
        # menu for the project
        for m in self.current_tree.extra_menus_by_scope['project']:
            if isinstance(m, QMenu):
                menu.addSeparator()
                menu.addMenu(m)

        # show the menu!
        menu.exec_(QCursor.pos())
Пример #38
0
class FileConverterOutputTab(QWidget):
    def __init__(self, inputTab):
        super().__init__()
        self.input = inputTab

        self.EMPTY = 0
        self.BK_SHP = 1
        self.Z_FROM_SHP = 2
        self.M_FROM_SHP = 3
        self.SHP_BK = 4
        self.Z_AND_BK = 5
        self.Z_AND_M = 6

        self.convert_type = {
            'xyz': {
                'xyz': self.EMPTY,
                'shp PointZ': self.BK_SHP,
                'csv': self.EMPTY
            },
            'i2s': {
                'i2s': self.EMPTY,
                'shp Polyline': self.BK_SHP,
                'shp Polygon': self.BK_SHP,
                'csv': self.EMPTY
            },
            'i3s': {
                'i3s': self.EMPTY,
                'i2s': self.EMPTY,
                'shp PolylineZ': self.BK_SHP,
                'shp PolygonZ': self.BK_SHP,
                'csv': self.EMPTY
            },
            'shp Point': {
                'shp Point': self.EMPTY,
                'shp PointZ': self.Z_AND_M,
                'xyz': self.Z_FROM_SHP,
                'csv': self.EMPTY
            },
            'shp PointZ': {
                'shp Point': self.EMPTY,
                'shp PointZ': self.Z_AND_M,
                'shp PointM': self.M_FROM_SHP,
                'xyz': self.Z_FROM_SHP,
                'csv': self.EMPTY
            },
            'shp PointM': {
                'shp Point': self.EMPTY,
                'shp PointM': self.M_FROM_SHP,
                'shp PointZ': self.Z_AND_M,
                'xyz': self.Z_FROM_SHP,
                'csv': self.EMPTY
            },
            'shp Polyline': {
                'shp Polyline': self.EMPTY,
                'shp PolylineZ': self.Z_AND_M,
                'i2s': self.SHP_BK,
                'i3s': self.Z_AND_BK,
                'csv': self.EMPTY
            },
            'shp Polygon': {
                'shp Polygon': self.EMPTY,
                'shp PolygonZ': self.Z_AND_M,
                'i2s': self.SHP_BK,
                'i3s': self.Z_AND_BK,
                'csv': self.EMPTY
            },
            'shp PolylineZ': {
                'shp PolylineZ': self.Z_AND_M,
                'shp Polyline': self.EMPTY,
                'i2s': self.SHP_BK,
                'i3s': self.Z_AND_BK,
                'csv': self.EMPTY
            },
            'shp PolygonZ': {
                'shp PolygonZ': self.Z_AND_M,
                'shp Polygon': self.EMPTY,
                'i2s': self.SHP_BK,
                'i3s': self.Z_AND_BK,
                'csv': self.EMPTY
            },
            'shp PolylineM': {
                'shp Polyline': self.EMPTY,
                'shp PolylineM': self.M_FROM_SHP,
                'shp PolylineZ': self.Z_AND_M,
                'i2s': self.SHP_BK,
                'i3s': self.Z_AND_BK,
                'csv': self.EMPTY
            },
            'shp PolygonM': {
                'shp Polygon': self.EMPTY,
                'shp PolygonM': self.M_FROM_SHP,
                'shp PolygonZ': self.Z_AND_M,
                'i2s': self.SHP_BK,
                'i3s': self.Z_AND_BK,
                'csv': self.EMPTY
            },
            'shp Multipoint': {
                'shp MultiPoint': self.EMPTY,
                'shp MultiPointZ': self.Z_AND_M,
                'shp MultiPointM': self.M_FROM_SHP,
                'shp Point': self.EMPTY,
                'shp PointZ': self.Z_AND_M,
                'shp PointM': self.M_FROM_SHP,
                'xyz': self.Z_FROM_SHP,
                'csv': self.EMPTY
            },
            'shp MultiPoint': {
                'shp MultiPoint': self.EMPTY,
                'shp MultiPointZ': self.Z_AND_M,
                'shp MultiPointM': self.M_FROM_SHP,
                'shp Point': self.EMPTY,
                'shp PointZ': self.Z_AND_M,
                'shp PointM': self.M_FROM_SHP,
                'xyz': self.Z_FROM_SHP,
                'csv': self.EMPTY
            },
            'shp MultiPointZ': {
                'shp MultiPoint': self.EMPTY,
                'shp MultiPointZ': self.Z_AND_M,
                'shp MultiPointM': self.M_FROM_SHP,
                'shp Point': self.EMPTY,
                'shp PointZ': self.Z_AND_M,
                'shp PointM': self.M_FROM_SHP,
                'xyz': self.Z_FROM_SHP,
                'csv': self.EMPTY
            },
            'shp MultiPointM': {
                'shp MultiPoint': self.EMPTY,
                'shp MultiPointZ': self.Z_AND_M,
                'shp MultiPointM': self.M_FROM_SHP,
                'shp Point': self.EMPTY,
                'shp PointZ': self.Z_AND_M,
                'shp PointM': self.M_FROM_SHP,
                'xyz': self.Z_FROM_SHP,
                'csv': self.EMPTY
            }
        }
        self._initWidgets()
        self._setLayout()
        self._bindEvents()

    def _initWidgets(self):
        # create a text for input information
        self.inputBox = QPlainTextEdit()
        self.inputBox.setFixedHeight(60)
        self.inputBox.setReadOnly(True)

        # create the widget displaying message logs
        self.logTextBox = QPlainTextEditLogger(self)
        self.logTextBox.setFormatter(
            logging.Formatter(settings.LOGGING_FMT_GUI))
        logging.getLogger().addHandler(self.logTextBox)
        logging.getLogger().setLevel(self.input.parent.logging_level)

        # create a combo box for output file type
        self.outTypeBox = QComboBox()
        self.outTypeBox.setFixedHeight(30)

        # create a text box for output file name
        self.outNameBox = QLineEdit()
        self.outNameBox.setReadOnly(True)
        self.outNameBox.setFixedHeight(30)

        # create the option panel
        self.stack = QStackedLayout()

        self.empty = QWidget()

        self.bkshp = QWidget()
        hlayout = QHBoxLayout()
        hlayout.addWidget(QLabel('Attribute name'))
        self.bkshpname = QLineEdit('Value')
        self.bkshpname.setFixedHeight(30)
        hlayout.addWidget(self.bkshpname)
        self.bkshp.setLayout(hlayout)

        # Fill Z for xyz
        self.zfield = QWidget()
        hlayout = QHBoxLayout()
        hlayout.addWidget(QLabel('Fill Z with'))
        self.zfieldchoice = QComboBox()
        self.zfieldchoice.setFixedHeight(30)
        hlayout.addWidget(self.zfieldchoice, Qt.AlignLeft)
        self.zfield.setLayout(hlayout)

        self.mfield = QWidget()
        hlayout = QHBoxLayout()
        hlayout.addWidget(QLabel('Fill M with'))
        self.mfieldchoice = QComboBox()
        self.mfieldchoice.setFixedHeight(30)
        hlayout.addWidget(self.mfieldchoice, Qt.AlignLeft)
        self.mfield.setLayout(hlayout)

        self.shpbk = QWidget()
        hlayout = QHBoxLayout()
        hlayout.addWidget(QLabel('Fill attribute with'))
        self.shpbkmethod = QComboBox()
        self.shpbkmethod.setFixedHeight(30)
        hlayout.addWidget(self.shpbkmethod, Qt.AlignLeft)
        self.shpbk.setLayout(hlayout)

        self.shpbkz = QWidget()
        vlayout = QVBoxLayout()
        hlayout = QHBoxLayout()
        hlayout.addWidget(QLabel('Fill Z with'))
        self.zfieldchoicebis = QComboBox()
        self.zfieldchoicebis.setFixedHeight(30)
        hlayout.addWidget(self.zfieldchoicebis, Qt.AlignLeft)
        vlayout.addLayout(hlayout)
        hlayout = QHBoxLayout()
        hlayout.addWidget(QLabel('Fill attribute with'))
        self.shpbkmethodbis = QComboBox()
        self.shpbkmethodbis.setFixedHeight(30)
        hlayout.addWidget(self.shpbkmethodbis, Qt.AlignLeft)
        vlayout.addLayout(hlayout)
        self.shpbkz.setLayout(vlayout)

        self.shpzm = QWidget()
        vlayout = QVBoxLayout()
        hlayout = QHBoxLayout()
        hlayout.addWidget(QLabel('Fill Z with'))
        self.zfieldchoiceter = QComboBox()
        self.zfieldchoiceter.setFixedHeight(30)
        hlayout.addWidget(self.zfieldchoiceter, Qt.AlignLeft)
        vlayout.addLayout(hlayout)
        hlayout = QHBoxLayout()
        hlayout.addWidget(QLabel('Fill M with'))
        self.mfieldchoicebis = QComboBox()
        self.mfieldchoicebis.setFixedHeight(30)
        hlayout.addWidget(self.mfieldchoicebis, Qt.AlignLeft)
        vlayout.addLayout(hlayout)
        self.shpzm.setLayout(vlayout)

        for panel in [
                self.empty, self.bkshp, self.zfield, self.mfield, self.shpbk,
                self.shpbkz, self.shpzm
        ]:
            self.stack.addWidget(panel)

        self.stackbis = QStackedLayout()
        self.emptybis = QWidget()

        self.resample = QGroupBox('Re-sample lines by Maximum Length')
        self.resample.setCheckable(True)
        vlayout = QVBoxLayout()
        self.valueButton = QRadioButton('Use constant')
        self.valueBox = QLineEdit('1')
        self.choiceButton = QRadioButton('Use attribute')
        self.choiceBox = QComboBox()
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.valueButton)
        hlayout.addWidget(self.valueBox)
        vlayout.addLayout(hlayout)
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.choiceButton)
        hlayout.addWidget(self.choiceBox, Qt.AlignLeft)
        vlayout.addLayout(hlayout)
        self.resample.setLayout(vlayout)
        self.choiceBox.setVisible(False)
        self.valueBox.setVisible(False)
        self.resample.setChecked(False)
        self.valueButton.toggled.connect(
            lambda checked: self.valueBox.setVisible(checked))
        self.choiceButton.toggled.connect(
            lambda checked: self.choiceBox.setVisible(checked))
        self.valueButton.setChecked(True)

        self.stackbis.addWidget(self.emptybis)
        self.stackbis.addWidget(self.resample)
        self.stackbis.setCurrentIndex(1)
        # create the submit button
        self.btnSubmit = QPushButton('Submit',
                                     self,
                                     icon=self.style().standardIcon(
                                         QStyle.SP_DialogSaveButton))
        self.btnSubmit.setToolTip('<b>Submit</b>')
        self.btnSubmit.setFixedSize(105, 50)

    def _bindEvents(self):
        self.btnSubmit.clicked.connect(self.btnSubmitEvent)
        self.outTypeBox.currentIndexChanged.connect(self.changeOutType)

    def _setLayout(self):
        mainLayout = QVBoxLayout()
        mainLayout.addItem(QSpacerItem(50, 20))
        mainLayout.addWidget(self.inputBox)
        mainLayout.addItem(QSpacerItem(50, 20))
        hlayout = QHBoxLayout()
        hlayout.addWidget(QLabel('Output file type'))
        hlayout.addWidget(self.outTypeBox, Qt.AlignLeft)
        mainLayout.addLayout(hlayout)
        mainLayout.addItem(QSpacerItem(50, 10))
        mainLayout.addLayout(self.stack)
        mainLayout.addItem(QSpacerItem(50, 10))
        mainLayout.addLayout(self.stackbis)
        mainLayout.addItem(QSpacerItem(50, 10))
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.btnSubmit)
        hlayout.addWidget(self.outNameBox)
        mainLayout.addLayout(hlayout)
        mainLayout.addItem(QSpacerItem(30, 15))
        mainLayout.addWidget(QLabel('   Message logs'))
        mainLayout.addWidget(self.logTextBox.widget)
        self.setLayout(mainLayout)

    def reset(self):
        self.inputBox.clear()
        self.outTypeBox.clear()
        self.outNameBox.clear()
        self.bkshpname.setText('Value')
        self.zfieldchoice.clear()
        self.zfieldchoicebis.clear()
        self.zfieldchoiceter.clear()
        self.mfieldchoice.clear()
        self.mfieldchoicebis.clear()
        self.shpbkmethod.clear()
        self.shpbkmethod.addItem('0')
        self.shpbkmethod.addItem('Iteration')
        self.shpbkmethodbis.clear()
        self.shpbkmethodbis.addItem('0')
        self.shpbkmethodbis.addItem('Iteration')
        self.choiceBox.clear()

    def changeOutType(self, index):
        if self.outTypeBox.currentText():
            self.stack.setCurrentIndex(self.convert_type[self.input.from_type][
                self.outTypeBox.currentText()])

    def _check_options(self):
        current_type = self.stack.currentIndex()
        if current_type == self.BK_SHP:
            attribute_name = self.bkshpname.text()
            if not attribute_name:
                QMessageBox.critical(None, 'Error',
                                     'The attribute name cannot be empty!',
                                     QMessageBox.Ok)
                return False, []
            options = [attribute_name]
        elif current_type == self.Z_FROM_SHP:
            options = [self.zfieldchoice.currentText()]
        elif current_type == self.M_FROM_SHP:
            options = [self.mfieldchoice.currentText()]
        elif current_type == self.SHP_BK:
            options = [self.shpbkmethod.currentText()]
        elif current_type == self.Z_AND_BK:
            options = [
                self.zfieldchoicebis.currentText(),
                self.shpbkmethodbis.currentText()
            ]
        elif current_type == self.Z_AND_M:
            options = [
                self.zfieldchoiceter.currentText(),
                self.mfieldchoicebis.currentText()
            ]
        else:
            options = []
        if self.stackbis.currentIndex() == 1:
            if self.resample.isChecked():
                if self.valueButton.isChecked():
                    value = self.valueBox.text()
                    try:
                        value = float(value)
                    except ValueError:
                        QMessageBox.critical(
                            None, 'Error',
                            'Re-sampling Maximum Length must be a number!',
                            QMessageBox.Ok)
                        return False, []
                    if value <= 0:
                        QMessageBox.critical(
                            None, 'Error',
                            'Re-sampling Maximum Length must be positive!',
                            QMessageBox.Ok)
                        return False, []
                    options.append('v|' + str(value))
                else:
                    attribute = self.choiceBox.currentText()
                    if not attribute:
                        QMessageBox.critical(
                            None, 'Error',
                            'No numeric attribute available for re-sampling.',
                            QMessageBox.Ok)
                        return False, []
                    options.append('a|' + attribute)
            else:
                options.append('')
        return True, options

    def getInput(self):
        self.reset()

        from_type = self.input.from_type
        message = 'The input format is of type {}.\n'.format(from_type)
        is_line = False
        possible_types = self.convert_type[from_type].keys()

        if from_type == 'i2s' or from_type == 'i3s':
            is_line = True
            self.choiceBox.addItem('Attribute')
            nb_closed, nb_open = self.input.converter.nb_closed, self.input.converter.nb_open
            if nb_closed > 0 and nb_open > 0:
                possible_types = self.convert_type[from_type].keys()
            elif nb_closed == 0:
                if from_type == 'i2s':
                    possible_types = ['i2s', 'shp Polyline', 'csv']
                else:
                    possible_types = ['i3s', 'i2s', 'shp PolylineZ', 'csv']
            else:
                if from_type == 'i2s':
                    possible_types = ['i2s', 'shp Polygon', 'csv']
                else:
                    possible_types = ['i3s', 'i2s', 'shp PolygonZ', 'csv']
            message += 'It has {} polygon{} and {} open polyline{}.\n'.format(
                nb_closed, 's' if nb_closed > 1 else '', nb_open,
                's' if nb_open > 1 else '')
        elif from_type == 'shp Point':
            numeric_fields = self.input.converter.numeric_fields
            if numeric_fields:
                self.mfieldchoicebis.addItem('0')
                for index, name in numeric_fields:
                    item = '%d - %s' % (index, name)
                    self.zfieldchoice.addItem(item)
                    self.zfieldchoiceter.addItem(item)
                    self.mfieldchoicebis.addItem(item)
            else:
                possible_types = [from_type, 'csv']

        elif from_type == 'shp PointM':
            numeric_fields = self.input.converter.numeric_fields
            self.mfieldchoice.addItem('M')
            self.mfieldchoicebis.addItem('M')
            if numeric_fields:
                for index, name in numeric_fields:
                    item = '%d - %s' % (index, name)
                    self.zfieldchoice.addItem(item)
                    self.zfieldchoiceter.addItem(item)
                    self.mfieldchoice.addItem(item)
                    self.mfieldchoicebis.addItem(item)
            else:
                possible_types = ['shp PointM', 'shp Point', 'csv']

        elif from_type == 'shp PointZ':
            self.zfieldchoice.addItem('Z')
            self.zfieldchoiceter.addItem('Z')
            self.mfieldchoice.addItem('M')
            self.mfieldchoicebis.addItem('M')
            numeric_fields = self.input.converter.numeric_fields
            if numeric_fields:
                for index, name in numeric_fields:
                    item = '%d - %s' % (index, name)
                    self.zfieldchoice.addItem(item)
                    self.zfieldchoiceter.addItem(item)
                    self.mfieldchoice.addItem(item)
                    self.mfieldchoicebis.addItem(item)

        elif from_type == 'shp Polyline' or from_type == 'shp Polygon':
            is_line = True
            numeric_fields = self.input.converter.numeric_fields
            if numeric_fields:
                self.mfieldchoicebis.addItem('0')
                for index, name in numeric_fields:
                    item = '%d - %s' % (index, name)
                    self.zfieldchoiceter.addItem(item)
                    self.mfieldchoicebis.addItem(item)
                    self.zfieldchoicebis.addItem(item)
                    self.shpbkmethod.addItem(item)
                    self.shpbkmethodbis.addItem(item)
                    self.choiceBox.addItem(item)
            else:
                possible_types = [from_type, 'i2s', 'csv']

        elif from_type == 'shp PolylineZ' or from_type == 'shp PolygonZ':
            is_line = True
            self.zfieldchoiceter.addItem('Z')
            self.zfieldchoicebis.addItem('Z')
            self.mfieldchoicebis.addItem('M')
            numeric_fields = self.input.converter.numeric_fields
            if numeric_fields:
                for index, name in numeric_fields:
                    item = '%d - %s' % (index, name)
                    self.zfieldchoiceter.addItem(item)
                    self.zfieldchoicebis.addItem(item)
                    self.mfieldchoicebis.addItem(item)
                    self.shpbkmethod.addItem(item)
                    self.shpbkmethodbis.addItem(item)
                    self.choiceBox.addItem(item)

        elif from_type == 'shp PolylineM' or from_type == 'shp PolygonM':
            is_line = True
            numeric_fields = self.input.converter.numeric_fields
            self.mfieldchoice.addItem('M')
            self.mfieldchoicebis.addItem('M')
            if numeric_fields:
                for index, name in numeric_fields:
                    item = '%d - %s' % (index, name)
                    self.mfieldchoice.addItem(item)
                    self.zfieldchoiceter.addItem(item)
                    self.zfieldchoicebis.addItem(item)
                    self.mfieldchoicebis.addItem(item)
                    self.shpbkmethod.addItem(item)
                    self.shpbkmethodbis.addItem(item)
                    self.choiceBox.addItem(item)
            else:
                possible_types = [from_type, from_type[:-1], 'i2s', 'csv']

        elif from_type == 'shp MultiPoint' or from_type == 'shp MultiPointZ':
            if from_type == 'shp MultiPointZ':
                self.zfieldchoice.addItem('Z')
                self.zfieldchoiceter.addItem('Z')
                self.mfieldchoice.addItem('M')
                self.mfieldchoicebis.addItem('M')
            numeric_fields = self.input.converter.numeric_fields
            if numeric_fields:
                for index, name in numeric_fields:
                    item = '%d - %s' % (index, name)
                    self.zfieldchoice.addItem(item)
                    self.zfieldchoiceter.addItem(item)
                    self.mfieldchoice.addItem(item)
                    self.mfieldchoicebis.addItem(item)
            else:
                possible_types = [from_type, 'xyz', 'csv']
                if from_type == 'shp MultiPointZ':
                    possible_types.append('shp MultiPoint')

        logging.debug('Possible output types: %s' % possible_types)
        for to_type in possible_types:
            self.outTypeBox.addItem(to_type)

        if is_line:
            self.stackbis.setCurrentIndex(1)
        else:
            self.stackbis.setCurrentIndex(0)

        message += 'It can be converted to the following types: {}.'.format(
            ', '.join(list(possible_types)))
        self.inputBox.appendPlainText(message)

    def btnSubmitEvent(self):
        # check the transformations options
        valid, options = self._check_options()
        if not valid:
            return

        # getting the converter options right
        if self.input.transformation is not None:
            from_index, to_index = self.input.fromBox.currentIndex(
            ), self.input.toBox.currentIndex()
            trans = self.input.transformation.get_transformation(
                from_index, to_index)
            self.input.converter.set_transformations(trans)

        out_type = self.outTypeBox.currentText()
        if out_type[:3] == 'shp':
            out_type = 'shp'
        filename, _ = QFileDialog.getSaveFileName(
            self,
            'Choose the output file name',
            '',
            '%s Files (*.%s)' % (out_type, out_type),
            options=QFileDialog.Options() | QFileDialog.DontUseNativeDialog)
        if not filename:
            return
        if len(filename) < 5 or filename[-3:] != out_type:
            filename += '.' + out_type
        if filename == self.input.converter.from_file:
            QMessageBox.critical(self, 'Error',
                                 'Cannot overwrite to the input file.',
                                 QMessageBox.Ok)
            return
        try:
            with open(filename, 'w'):
                pass
        except PermissionError:
            QMessageBox.critical(
                self, 'Error',
                'Permission denied (Is the file opened by another application?).',
                QMessageBox.Ok)
            return None

        self.outNameBox.setText(filename)
        logging.info('Start conversion from %s\nto %s' %
                     (self.input.converter.from_file, filename))
        QApplication.processEvents()
        try:
            self.input.converter.write(self.outTypeBox.currentText(), filename,
                                       options)
        except RuntimeError:
            QMessageBox.critical(
                self, 'Error',
                'The attribute used for re-sampling contains non-positive number.',
                QMessageBox.Ok)
            logging.info('Failed.')
            return None
        logging.info('Done.')
        QMessageBox.information(self, 'Success',
                                'File conversion finished successfully!',
                                QMessageBox.Ok)
Пример #39
0
class Controls(QWidget):

    def __init__(self, name, nb_player, h, w):
        QWidget.__init__(self)
        self.name = name
        self.nb_player = nb_player
        self.h = h
        self.w = w
        self.initUI()

    def initUI(self):
        # Set the window
        self.pal = self.palette()
        self.pal.setColor(self.backgroundRole(), Qt.white)
        self.setPalette(self.pal)
        self.gri = QHBoxLayout(self)
        # Set the Grid
        set_grid = grids.grid_init(self.name, self.nb_player)
        self.grid = set_grid[0]
        self.players = set_grid[1]
        # State of the game
        self.state = 0
        # Set the button for movement
        self.button_move = [basic_widgets.Button("up"),
                            basic_widgets.Button("down"),
                            basic_widgets.Button("left"),
                            basic_widgets.Button("right"),
                            ]
        self.button_move[0].clicked.connect(self.go_up)
        self.button_move[1].clicked.connect(self.go_down)
        self.button_move[2].clicked.connect(self.go_left)
        self.button_move[3].clicked.connect(self.go_right)
        # Set the button which select the player
        self.current_player = 0
        self.button_player = [basic_widgets.Button("1_button"),
                              basic_widgets.Button("2_button"),
                              basic_widgets.Button("3_button"),
                              basic_widgets.Button("4_button"),
                              ]
        for i in range(0, self.nb_player):
            self.button_player[i].clicked.connect(self.player_change)
        # We put it in a Stacked
        self.current_player = QStackedLayout()
        for i in range(0, self.nb_player):
            self.current_player.addWidget(self.button_player[i])
        self.index = self.current_player.currentIndex()
        # Set the Layout for the button of the movement
        self.grid_button = QGridLayout()
        self.grid_button.addWidget(self.button_move[0], 1, 3)
        self.grid_button.addWidget(self.button_move[1], 3, 3)
        self.grid_button.addWidget(self.button_move[2], 2, 2)
        self.grid_button.addWidget(self.button_move[3], 2, 4)
        self.grid_button.addLayout(self.current_player, 2, 3)
        # Set the Layout which display the Grid
        self.display_grid = QStackedLayout()
        self.initial_grid = QWidget(self)
        self.initial_grid.setLayout(map.Map_Grid(self.grid, self.h, self.w))
        self.display_grid.addWidget(self.initial_grid)
        # Set the Layout of the window
        self.gri.addLayout(self.display_grid)
        self.gri.addLayout(self.grid_button)
        self.setLayout(self.gri)

    def player_change(self):
        self.index = (self.index + 1) % self.nb_player
        self.current_player.setCurrentWidget(self.button_player[self.index])

    def go_up(self):
        self.state = self.players[self.index].move(0, -1, self.grid)
        self.actualize_grid()

    def go_down(self):
        self.state = self.players[self.index].move(0, 1, self.grid)
        self.actualize_grid()

    def go_left(self):
        self.state = self.players[self.index].move(-1, 0, self.grid)
        self.actualize_grid()

    def go_right(self):
        self.state = self.players[self.index].move(1, 0, self.grid)
        self.actualize_grid()

    def actualize_grid(self):
        """
        Create the new Layout where the Grid is printed because
        the grid has changed with the movement
        """
        actual_grid = QWidget(self)
        actual_grid.setLayout(map.Map_Grid(self.grid, self.h, self.w))
        self.display_grid.addWidget(actual_grid)
        self.display_grid.setCurrentWidget(actual_grid)
Пример #40
0
class OptionsWidget(QWidget):

    """
    Widget holds menu with all options.
    """

    def __init__(self, main_window, items):

        super().__init__()

        self.items = items

        self.layout = QStackedLayout()
        self._switch_user = self._get_switch_user_func(main_window)
        self.setLayout(self.layout)
        self._hide_action_button = lambda: main_window.communication.action_button_toggle.emit(False, '', None)

        self._create_layout(main_window)

    def set_current_index(self, index):
        self.layout.setCurrentIndex(index)
        if not index:
            self._hide_action_button()

    def showEvent(self, event):
        if not self.layout.currentIndex():
            self._hide_action_button()

    def _get_switch_user_func(self, main_window):
        def _switch_user():
            main_window.menu_btn_clicked(main_window.user_frame_index)
            self.layout.setCurrentIndex(0)
        return _switch_user

    def _get_template_import_func(self, main_window):
        func = self._wrap_template_func(template.Template.import_, main_window)

        def _alert_callback(path, value):
            if value:
                func(path[0])

        def _f():
            path = QFileDialog.getOpenFileName(main_window, 'Выберите файл', options.DATABASE_DIR)
            if path:
                main_window.create_alert('Шаблоны с одинаковыми именами будут перезаписаны.'
                                         '\nПродолжить?', functools.partial(_alert_callback, path))
        return _f

    def _get_template_export_func(self, main_window):
        func = self._wrap_template_func(template.Template.export, main_window)

        def _f():
            path = QFileDialog.getExistingDirectory(main_window, 'Выберите путь', options.DATABASE_DIR)
            if path:
                return func(path)
        return _f

    @staticmethod
    def _wrap_template_func(func, main_window):
        def _f(path):
            ok, result = func(path)
            if ok:
                main_window.show_message('Готово')
            else:
                main_window.create_alert('Произошла ошибка\n{}'.format(result.get('error')))
            return ok, result
        return _f

    def _create_layout(self, main_window):

        wrapper = QHBoxLayout()
        self.layout.addWidget(utils.get_scrollable(wrapper))
        rows = 8
        cols = 3
        vboxes = [QVBoxLayout() for _ in range(cols)]

        widgets = ((TemplateWidgetInOptions(main_window, self.items, self), 'Шаблоны'),
                   (UsersAndGroupsWidget(main_window, self), 'Пользователи и группы'),
                   (self._switch_user, 'Сменить пользователя'),
                   (self._get_template_export_func(main_window), 'Экспортировать шаблоны'),
                   (self._get_template_import_func(main_window), 'Импортировать шаблоны'))

        for i, widget in enumerate(widgets):
            b = QPushButton(widget[1])

            if callable(widget[0]):
                b.clicked.connect(widget[0])
            else:
                b.clicked.connect(functools.partial(self.layout.setCurrentIndex, i + 1))
                self.layout.addWidget(widget[0])

            b.setGraphicsEffect(utils.get_shadow())
            vboxes[(i // rows) % cols].addWidget(b)

        for each in vboxes:
            each.addStretch()
            wrapper.addLayout(each, stretch=int(100 / cols))