def __init__(self):
        super().__init__()
        self.setWindowTitle('Голосовая идентификация')
        self.setWindowIcon(QIcon('Voice-Search.ico'))
        self.vBox = QVBoxLayout()
        self.buttonsBox = QHBoxLayout()
        self.setLayout(self.vBox)

        # создание компонентов
        self.usersText = QLabel('В системе 28 пользователей')
        self.signUpButton = QPushButton('Зарегистрироваться')
        self.identifyButton = QPushButton('Идентифицировать')
        self.aboutButton = QPushButton('Как это работает?')

        # создание форм
        self.signUpWindow = SignUpWindow()
        self.identifyWindow = IdentifyWindow()
        self.aboutWindow = AboutWindow()

        # добавление компоненов на форму
        self.vBox.addWidget(self.usersText)
        self.vBox.addWidget(StaticImage('users.png'))
        self.vBox.addLayout(self.buttonsBox)
        self.buttonsBox.addWidget(self.signUpButton)
        self.buttonsBox.addWidget(self.identifyButton)
        self.buttonsBox.addWidget(self.aboutButton)

        # связка кнопок с формами
        self.signUpButton.clicked.connect(self.signUpWindow.show)
        self.identifyButton.clicked.connect(self.identifyWindow.show)
        self.aboutButton.clicked.connect(self.aboutWindow.show)
예제 #2
0
    def __init__(self):
        QMainWindow.__init__(self)
        self.setupUi(self)
        self.reset_app()
        self.about_window = AboutWindow(self)
        self.deploy_window = DeployWindow(self)        

        # Custom context Menu
        self.treeWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.treeWidget.customContextMenuRequested.connect(self.showContextMenu)

        # get any history of combo boxes and reset index
        self.comboServer.addItems(get_history('servers'))
        self.comboServer.setCurrentIndex(-1)
        self.comboFile.addItems(get_history('locals'))
        self.comboFile.setCurrentIndex(-1)

        # Set action for clicking About.
        self.actionAbout.triggered.connect(self.show_about_window)

        # Set action for closing the app.
        self.actionExit.triggered.connect(self.close)

        # Set action for reseting the app.
        self.actionReset.triggered.connect(self.reset_app)

        # Set action for clicking browse button
        self.buttonBrowse.clicked.connect(self.browse_file)

        # Set action for clicking the compare button
        self.buttonCompare.clicked.connect(self.compare)

        # On change of server value, check the connection.
        self.comboServer.currentIndexChanged.connect(
            self.check_server_value)
        self.comboServer.lineEdit().editingFinished.connect(
            self.check_server_value)

        # On change of folder value, check the connection.
        self.comboFile.currentIndexChanged.connect(
            self.check_folder_value)
        self.comboFile.lineEdit().editingFinished.connect(
            self.check_folder_value)

        self.setFocus()
예제 #3
0
    def __init__(self):

        super(Ruler, self).__init__()

        self.old_position = None  # is used for dragging of the window
        self.setMinimumWidth(50)
        self.setMinimumHeight(50)

        # load the options
        self.data = Data()

        # main widget
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.constructContextMenu)

        self.setWindowTitle('Screen Ruler')
        self.resize(self.data.get('ruler_width'),
                    self.data.get('ruler_height'))
        self.setMouseTracking(True)
        self.setAttribute(Qt.WA_TranslucentBackground, True)
        self.setGeometry(
            QStyle.alignedRect(
                Qt.LeftToRight, Qt.AlignCenter, self.size(),
                QGuiApplication.primaryScreen().availableGeometry()))

        windowFlags = Qt.CustomizeWindowHint | Qt.FramelessWindowHint

        leftResize = SizeGrip(self, True)
        rightResize = SizeGrip(self, False)

        self.left_resize = leftResize
        self.right_resize = rightResize

        if self.data.get('always_above'):
            windowFlags = windowFlags | Qt.WindowStaysOnTopHint
        self.setWindowFlags(
            windowFlags)  # Turns off the default window title hints

        # initialize the secondary windows
        self.about_window = AboutWindow()
        self.options_window = OptionsWindow(self)

        if self.data.get('options_opened'):
            self.openOptions()
예제 #4
0
class Ruler(QWidget):
    def __init__(self):

        super(Ruler, self).__init__()

        self.old_position = None  # is used for dragging of the window
        self.setMinimumWidth(50)
        self.setMinimumHeight(50)

        # load the options
        self.data = Data()

        # main widget
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.constructContextMenu)

        self.setWindowTitle('Screen Ruler')
        self.resize(self.data.get('ruler_width'),
                    self.data.get('ruler_height'))
        self.setMouseTracking(True)
        self.setAttribute(Qt.WA_TranslucentBackground, True)
        self.setGeometry(
            QStyle.alignedRect(
                Qt.LeftToRight, Qt.AlignCenter, self.size(),
                QGuiApplication.primaryScreen().availableGeometry()))

        windowFlags = Qt.CustomizeWindowHint | Qt.FramelessWindowHint

        leftResize = SizeGrip(self, True)
        rightResize = SizeGrip(self, False)

        self.left_resize = leftResize
        self.right_resize = rightResize

        if self.data.get('always_above'):
            windowFlags = windowFlags | Qt.WindowStaysOnTopHint
        self.setWindowFlags(
            windowFlags)  # Turns off the default window title hints

        # initialize the secondary windows
        self.about_window = AboutWindow()
        self.options_window = OptionsWindow(self)

        if self.data.get('options_opened'):
            self.openOptions()

    def resizeEvent(self, event=None):
        size = self.size()
        width = size.width()
        height = size.height()
        leftResize = self.left_resize
        rightResize = self.right_resize
        length = leftResize.length

        if self.data.get('horizontal_orientation'):
            rightResize.move(width - length, 0)

            leftResize.resize(length, height)
            rightResize.resize(length, height)

            # vertical orientation
        else:
            rightResize.move(0, size.height() - rightResize.length)

            leftResize.resize(width, length)
            rightResize.resize(width, length)

    def paintEvent(self, event):

        paint = QPainter()
        paint.begin(self)
        paint.save()

        size = self.size()
        width = size.width()
        height = size.height()
        units = self.data.get('units')

        proportion = self.getProportion()

        horizontalOrientation = self.data.get('horizontal_orientation')

        if horizontalOrientation:

            rulerLength = width
            traceLengthLimit = height

        else:  # vertical orientation
            rulerLength = height
            traceLengthLimit = width

            paint.translate(width, 0)
            paint.rotate(90)

            # the length of the traces (lines)
        small = traceLengthLimit / 6
        medium = traceLengthLimit / 4
        large = traceLengthLimit / 3

        limit = rulerLength / proportion

        # draw less lines for centimeters
        if units == 'cm':
            step = 10

        else:
            step = 5

        # begin drawing
        fontSize = 10
        font = QFont('Serif', fontSize)
        fontMetrics = QFontMetrics(font)

        # draw background
        background = self.data.get('background_color')
        paint.fillRect(0, 0, rulerLength, traceLengthLimit, background)

        # draw the lines
        paint.setPen(self.data.get('lines_color'))
        paint.setFont(font)

        # the builtin range() doesn't support floats
        def float_range(current, end, rangeStep):
            while current < end:
                yield current
                current += rangeStep

            # we skip 0 and start in the first step, since there's no point in drawing the first line/text (it would appear cut off, since we're at the limit)

        for a in float_range(step, limit, step):

            position = a * proportion

            if (a % 100) == 0:
                lineLength = large

                if units == 'px':
                    text = '{}{}'.format(str(a), units)
                else:
                    text = '{}{}'.format(str(int(a / 100)), units)

                textWidth = fontMetrics.boundingRect(text).width()

                paint.drawText(position - textWidth / 2,
                               traceLengthLimit / 2 + fontSize / 2, text)

            elif (a % 50) == 0:
                lineLength = large

                # since 'cm' has a different step compared to the other units
                if units == 'cm':
                    lineLength = medium

            elif (a % 25) == 0:
                lineLength = medium

            else:
                lineLength = small

            paint.drawLine(position, 0, position, lineLength)
            paint.drawLine(position, traceLengthLimit, position,
                           traceLengthLimit - lineLength)

        # paint the division lines

        if self.data.get('division_lines'):
            paint.setPen(self.data.get('divisions_color'))
            halfPoint = rulerLength / 2
            quarterPoint = rulerLength / 4
            threeQuarterPoint = 3 / 4 * rulerLength

            paint.drawLine(quarterPoint, 0, quarterPoint, traceLengthLimit)
            paint.drawLine(halfPoint, 0, halfPoint, traceLengthLimit)
            paint.drawLine(threeQuarterPoint, 0, threeQuarterPoint,
                           traceLengthLimit)

        paint.restore()
        paint.end()

    def mousePressEvent(self, event):

        self.old_position = event.globalPos()

        button = event.button()

        if button == Qt.MiddleButton:
            self.rotate(QCursor.pos())

    def mouseMoveEvent(self, event, fromSizeGrip=False):

        buttons = event.buttons()

        # if we're on top of a SizeGrip, then clicking means we're resizing, and not moving the ruler
        if not fromSizeGrip and (buttons & Qt.LeftButton):

            position = event.globalPos()
            diff = position - self.old_position

            self.move(self.x() + diff.x(), self.y() + diff.y())

            self.old_position = position

        if self.options_window:
            pos = self.pos()

            if self.data.get('horizontal_orientation'):
                distance = event.globalX() - pos.x()

            else:
                distance = event.globalY() - pos.y()

            unit = self.data.get('units')

            if unit != 'px':
                distance /= 100
                value = distance / self.getProportion()
                string = '{:.2f} {}'

            else:
                value = distance  # its already in pixels
                string = '{} {}'

            self.options_window.setCurrentLength(string.format(value, unit))

    def keyPressEvent(self, event):

        key = event.key()
        modifiers = event.modifiers()

        if key == Qt.Key_O and modifiers == Qt.AltModifier:
            self.openOptions()

        elif key == Qt.Key_R and modifiers == Qt.AltModifier:
            self.rotate(QCursor.pos())

    def constructContextMenu(self, position):
        globalPosition = self.mapToGlobal(position)

        menu = QMenu()

        optionsEntry = QAction('Options', menu)
        optionsEntry.setData(self.openOptions)

        def rotate():
            mousePosition = QCursor.pos()

            self.rotate(mousePosition)

        rotateEntry = QAction('Rotate', menu)
        rotateEntry.setData(rotate)

        aboutEntry = QAction('About', menu)
        aboutEntry.setData(self.openAbout)

        quitEntry = QAction('Close', menu)
        quitEntry.setData(self.quit)

        menu.addAction(optionsEntry)
        menu.addAction(rotateEntry)
        menu.addAction(aboutEntry)
        menu.addAction(quitEntry)

        selectedItem = menu.exec_(globalPosition)
        """:type : QAction"""

        if selectedItem:
            selectedItem.data()()

    def openOptions(self):
        self.options_window.show()
        self.options_window.raise_()
        self.options_window.activateWindow()

    def rotate(self, mousePosition=None):

        self.data.update('horizontal_orientation',
                         not self.data.get('horizontal_orientation'))

        size = self.size()

        # position the ruler so that the resulting rotation is based on where the mouse is
        if mousePosition:
            rulerX = self.x()
            rulerY = self.y()
            mouseX = mousePosition.x()
            mouseY = mousePosition.y()

            self.move(mouseX - (mouseY - rulerY), mouseY - (mouseX - rulerX))

            # switch the width/height (to rotate 90 degrees)
        self.resize(size.height(), size.width())

        self.resizeEvent()

        # if the options window is opened, update it
        if self.options_window:
            self.options_window.updateOrientation(
                self.data.get('horizontal_orientation'))

    def openAbout(self):
        self.about_window.show()
        self.about_window.raise_()
        self.about_window.activateWindow()

    def getProportion(self):
        units = self.data.get('units')

        if units == 'cm':
            # 1 mm -> something pixel
            # width mm -> width pixel
            pxToMm = 1 * self.width() / self.widthMM()
            proportion = pxToMm / 10  # from mm to cm

        elif units == 'inch':
            # we'll calculate from mm to inches
            pxToMm = 1 * self.width() / self.widthMM()

            # 1 inch 2.54 cm
            proportion = 0.254 * pxToMm

        else:  # pixels
            proportion = 1

        return proportion

    def quit(self):
        self.close()

    def closeEvent(self, event):
        self.data.save({
            'width': self.width(),
            'height': self.height(),
            'optionsOpened': self.options_window.isVisible()
        })
        event.accept()
        QApplication.quit()
예제 #5
0
class MainWindow(QMainWindow):

    process_add_remove_semester = pyqtSignal(str)
    process_semester_update = pyqtSignal(str)
    process_subject_state_update = pyqtSignal(str)
    process_subject_convalidation = pyqtSignal(str)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.central_window = CentralWindow()
        self.central_window.send_semester_update.connect(
            self.receive_semester_update)
        self.central_window.send_subject_state_update.connect(
            self.receive_subject_state_update)

        self.init_GUI()

    def init_GUI(self):

        self.setMinimumWidth(450)
        self.setMinimumHeight(270)

        self.central_window.setSizePolicy(QSizePolicy.Expanding,
                                          QSizePolicy.Expanding)

        self.setWindowTitle("Planificador de malla curricular")
        self.setWindowIcon(QIcon(path_logo))

        self.setCentralWidget(self.central_window)

        about_section = QAction(QIcon(path_book),
                                '&Sobre el programa',
                                self)
        about_section.setShortcut('Ctrl+S')
        about_section.setStatusTip('Más información')
        about_section.triggered.connect(self.raise_about_window)

        exit_action = QAction(QIcon(path_exit), '&Exit', self)
        exit_action.setShortcut('Ctrl+E')
        exit_action.setStatusTip('Exit application')
        exit_action.triggered.connect(QApplication.quit)

        convalidate_action = QAction(QIcon(path_check_mark),
                                     '&Convalidar', self)
        convalidate_action.setStatusTip('Convalidar ramos')
        convalidate_action.triggered.connect(self.raise_convalidate_window)

        add_semester = QAction(QIcon(path_plus),
                               '&Agregar Semestre',
                               self)
        add_semester.setStatusTip('Se agregará un semestre al final')
        add_semester.triggered.connect(self.add_semester)

        remove_semester = QAction(QIcon(path_minus),
                                  '&Eliminar Semestre',
                                  self)
        message = 'Se eliminará el último semestre si está vacío'
        remove_semester.setStatusTip(message)
        remove_semester.triggered.connect(self.remove_semester)

        help_window = QAction(QIcon(path_question),
                              '&Ayuda',
                              self)
        message = 'Se mostrará una ventana de ayuda'
        help_window.setStatusTip(message)
        help_window.triggered.connect(self.raise_help_window)

        menubar = self.menuBar()
        archivo_menu = menubar.addMenu('&Opciones')
        archivo_menu.addAction(convalidate_action)
        archivo_menu.addAction(about_section)
        archivo_menu.addAction(exit_action)

        toolbar = self.addToolBar('Toolbar')
        toolbar.addAction(add_semester)
        toolbar.addAction(remove_semester)
        toolbar.addAction(help_window)
        toolbar.setIconSize(QSize(100, 16))

        self.setGeometry(main_window_x_pos, main_window_y_pos,
                         window_width, window_height)

    def resizeEvent(self, *args, **kwargs):
        self.process_semester_update.emit("")
        super().resizeEvent(*args, **kwargs)

    def update_status_bar(self, mensaje):
        self.statusBar().showMessage(mensaje)

    def raise_about_window(self):
        self.about_window = AboutWindow()
        self.about_window.show()

    def raise_convalidate_window(self):
        self.convalidate_window = ConvalidateWindow()
        self.convalidate_window.send_convalidation_to_main_window.connect(
            self.receive_subject_convalidation)

    def raise_help_window(self):
        self.help_window = HelpWindow()
        self.help_window.show()

    def receive_semester_update(self, string):
        self.process_semester_update.emit(string)

    def receive_subject_state_update(self, string):
        self.process_subject_state_update.emit(string)

    def receive_subject_convalidation(self, subject):
        self.process_subject_convalidation.emit(subject)

    def update_planner(self, string):
        self.central_window.update(string)

    def update_convalidate_window(self, message):
        self.convalidate_window.setMessage(message)

    def add_semester(self):
        self.process_add_remove_semester.emit('true')

    def remove_semester(self):
        self.process_add_remove_semester.emit('false')
예제 #6
0
 def raise_about_window(self):
     self.about_window = AboutWindow()
     self.about_window.show()
예제 #7
0
 def show_about_window(self):
     about = AboutWindow(self)
예제 #8
0
    def init_calculator_gui(self):
        if self.master != None:
            self.master.title("Calculator")
            self.master.geometry('350x350')

        # Menubar -------------------------------------------------------------
        # File Menu
        self.menubar = tk.Menu(self.master)
        self.filemenu = tk.Menu(self.menubar, tearoff=0)
        self.filemenu.add_command(label="Quit", command=self.quit)
        self.menubar.add_cascade(label="File", menu=self.filemenu)
        # About Menu
        self.about = AboutWindow("Calculator")
        self.helpmenu = tk.Menu(self.menubar, tearoff=0)
        self.helpmenu.add_command(label="About", command=self.about.run)
        self.menubar.add_cascade(label="Help", menu=self.helpmenu)

        if self.master != None:
            self.master.config(menu=self.menubar)

        # Status Bar
        self.status_text = tk.StringVar()
        self.status_text.set('')
        self.statusbar = tk.Label(self.master,
                                  textvariable=self.status_text,
                                  bd=1,
                                  relief=tk.SUNKEN,
                                  anchor=tk.W)
        self.statusbar.pack(side=tk.BOTTOM, fill=tk.X)

        # Calculator Display --------------------------------------------------
        # Container for Calculator Display
        self.disp_container = tk.Frame(self.master,
                                       padx=5,
                                       pady=5,
                                       relief=tk.SUNKEN)
        self.disp_container.pack()
        # Variable for updating calculator display
        self.disp_text = tk.StringVar()
        self.disp_text.set('0')
        # Calculator display entry
        self.calc_display = tk.Label(self.disp_container,
                                     bg='white',
                                     textvariable=self.disp_text,
                                     height=2,
                                     width=48,
                                     anchor='e',
                                     padx=10,
                                     font='Helvetica 16 bold')
        self.calc_display.pack()

        # Calculator Keypad ---------------------------------------------------
        # Container for Calculator Keypad
        self.keypad_container = tk.Frame(self.master,
                                         padx=5,
                                         pady=5,
                                         relief=tk.RAISED)
        self.keypad_container.pack()
        # Calculator keys
        btn_percent = tk.Button(self.keypad_container,
                                text="%",
                                height=2,
                                width=5,
                                command=lambda: self.on_click_operator('%'))
        btn_percent.grid(row=0,
                         column=0,
                         padx=(3, 1),
                         pady=(3, 1),
                         sticky=tk.W + tk.E + tk.S + tk.N)
        btn_divide = tk.Button(self.keypad_container,
                               text="/",
                               height=2,
                               width=5,
                               command=lambda: self.on_click_operator('/'))
        btn_divide.grid(row=0, column=1, sticky=tk.W + tk.E)
        btn_multi = tk.Button(self.keypad_container,
                              text="*",
                              height=2,
                              width=5,
                              command=lambda: self.on_click_operator('*'))
        btn_multi.grid(row=0,
                       column=2,
                       padx=(3, 1),
                       pady=(3, 1),
                       sticky=tk.W + tk.E + tk.S + tk.N)
        btn_subtract = tk.Button(self.keypad_container,
                                 text="-",
                                 height=2,
                                 width=5,
                                 command=lambda: self.on_click_operator('-'))
        btn_subtract.grid(row=0,
                          column=3,
                          padx=(3, 1),
                          pady=(3, 1),
                          sticky=tk.W + tk.E + tk.S + tk.N)
        btn_clear = tk.Button(self.keypad_container,
                              text="C",
                              height=2,
                              width=5,
                              bg="#d65a29",
                              command=lambda: self.on_click_clear())
        btn_clear.grid(row=0,
                       column=4,
                       padx=(3, 1),
                       pady=(3, 1),
                       sticky=tk.W + tk.E + tk.S + tk.N)
        btn_seven = tk.Button(self.keypad_container,
                              text="7",
                              height=2,
                              width=5,
                              command=lambda: self.on_click_digit('7'))
        btn_seven.grid(row=1,
                       column=0,
                       padx=(3, 1),
                       pady=(3, 1),
                       sticky=tk.W + tk.E + tk.S + tk.N)
        btn_eight = tk.Button(self.keypad_container,
                              text="8",
                              height=2,
                              width=5,
                              command=lambda: self.on_click_digit('8'))
        btn_eight.grid(row=1,
                       column=1,
                       padx=(3, 1),
                       pady=(3, 1),
                       sticky=tk.W + tk.E + tk.S + tk.N)
        btn_nine = tk.Button(self.keypad_container,
                             text="9",
                             height=2,
                             width=5,
                             command=lambda: self.on_click_digit('9'))
        btn_nine.grid(row=1,
                      column=2,
                      padx=(3, 1),
                      pady=(3, 1),
                      sticky=tk.W + tk.E + tk.S + tk.N)
        btn_add = tk.Button(self.keypad_container,
                            text="+",
                            height=5,
                            width=5,
                            command=lambda: self.on_click_operator('+'))
        btn_add.grid(row=1,
                     column=3,
                     padx=(3, 1),
                     pady=(3, 1),
                     rowspan=2,
                     sticky=tk.W + tk.E + tk.S + tk.N)
        btn_ac = tk.Button(self.keypad_container,
                           text="AC",
                           height=2,
                           width=5,
                           command=lambda: self.on_click_ac())
        btn_ac.grid(row=1,
                    column=4,
                    padx=(3, 1),
                    pady=(3, 1),
                    sticky=tk.W + tk.E + tk.S + tk.N)
        btn_four = tk.Button(self.keypad_container,
                             text="4",
                             height=2,
                             width=5,
                             command=lambda: self.on_click_digit('4'))
        btn_four.grid(row=2,
                      column=0,
                      padx=(3, 1),
                      pady=(3, 1),
                      sticky=tk.W + tk.E + tk.S + tk.N)
        btn_five = tk.Button(self.keypad_container,
                             text="5",
                             height=2,
                             width=5,
                             command=lambda: self.on_click_digit('5'))
        btn_five.grid(row=2,
                      column=1,
                      padx=(3, 1),
                      pady=(3, 1),
                      sticky=tk.W + tk.E + tk.S + tk.N)
        btn_six = tk.Button(self.keypad_container,
                            text="6",
                            height=2,
                            width=5,
                            command=lambda: self.on_click_digit('6'))
        btn_six.grid(row=2,
                     column=2,
                     padx=(3, 1),
                     pady=(3, 1),
                     sticky=tk.W + tk.E + tk.S + tk.N)
        btn_openbrace = tk.Button(self.keypad_container,
                                  text="(",
                                  height=2,
                                  width=5,
                                  command=lambda: self.on_click_symbol('('))
        btn_openbrace.grid(row=2,
                           column=4,
                           padx=(3, 1),
                           pady=(3, 1),
                           sticky=tk.W + tk.E + tk.S + tk.N)
        btn_one = tk.Button(self.keypad_container,
                            text="1",
                            height=2,
                            width=5,
                            command=lambda: self.on_click_digit('1'))
        btn_one.grid(row=3,
                     column=0,
                     padx=(3, 1),
                     pady=(3, 1),
                     sticky=tk.W + tk.E + tk.S + tk.N)
        btn_two = tk.Button(self.keypad_container,
                            text="2",
                            height=2,
                            width=5,
                            command=lambda: self.on_click_digit('2'))
        btn_two.grid(row=3,
                     column=1,
                     padx=(3, 1),
                     pady=(3, 1),
                     sticky=tk.W + tk.E + tk.S + tk.N)
        btn_three = tk.Button(self.keypad_container,
                              text="3",
                              height=2,
                              width=5,
                              command=lambda: self.on_click_digit('3'))
        btn_three.grid(row=3,
                       column=2,
                       padx=(3, 1),
                       pady=(3, 1),
                       sticky=tk.W + tk.E + tk.S + tk.N)
        btn_equals = tk.Button(self.keypad_container,
                               text="=",
                               height=5,
                               width=5,
                               command=lambda: self.on_click_result())
        btn_equals.grid(row=3,
                        column=3,
                        padx=(3, 1),
                        pady=(3, 1),
                        rowspan=2,
                        sticky=tk.W + tk.E + tk.S + tk.N)
        btn_closebrace = tk.Button(self.keypad_container,
                                   text=")",
                                   height=2,
                                   width=5,
                                   command=lambda: self.on_click_symbol(')'))
        btn_closebrace.grid(row=3,
                            column=4,
                            padx=(3, 1),
                            pady=(3, 1),
                            sticky=tk.W + tk.E + tk.S + tk.N)
        btn_zero = tk.Button(self.keypad_container,
                             text="0",
                             height=2,
                             width=15,
                             command=lambda: self.on_click_digit('0'))
        btn_zero.grid(row=4,
                      column=0,
                      padx=(3, 1),
                      pady=(3, 1),
                      columnspan=2,
                      sticky=tk.W + tk.E + tk.S + tk.N)
        btn_dot = tk.Button(self.keypad_container,
                            text=".",
                            height=2,
                            width=5,
                            command=lambda: self.on_click_digit('.'))
        btn_dot.grid(row=4,
                     column=2,
                     padx=(3, 1),
                     pady=(3, 1),
                     sticky=tk.W + tk.E + tk.S + tk.N)
        btn_sign = tk.Button(self.keypad_container,
                             text="+/-",
                             height=2,
                             width=5,
                             command=lambda: self.on_click_sign())
        btn_sign.grid(row=4,
                      column=4,
                      padx=(3, 1),
                      pady=(3, 1),
                      sticky=tk.W + tk.E + tk.S + tk.N)

        for i in range(4):
            self.keypad_container.grid_rowconfigure(i, weight=1)
        for i in range(4):
            self.keypad_container.grid_columnconfigure(i, weight=1)
예제 #9
0
class SSISDeployCheck(QMainWindow, SSISDeploymentChecker_ui.Ui_MainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.setupUi(self)
        self.reset_app()
        self.about_window = AboutWindow(self)
        self.deploy_window = DeployWindow(self)        

        # Custom context Menu
        self.treeWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.treeWidget.customContextMenuRequested.connect(self.showContextMenu)

        # get any history of combo boxes and reset index
        self.comboServer.addItems(get_history('servers'))
        self.comboServer.setCurrentIndex(-1)
        self.comboFile.addItems(get_history('locals'))
        self.comboFile.setCurrentIndex(-1)

        # Set action for clicking About.
        self.actionAbout.triggered.connect(self.show_about_window)

        # Set action for closing the app.
        self.actionExit.triggered.connect(self.close)

        # Set action for reseting the app.
        self.actionReset.triggered.connect(self.reset_app)

        # Set action for clicking browse button
        self.buttonBrowse.clicked.connect(self.browse_file)

        # Set action for clicking the compare button
        self.buttonCompare.clicked.connect(self.compare)

        # On change of server value, check the connection.
        self.comboServer.currentIndexChanged.connect(
            self.check_server_value)
        self.comboServer.lineEdit().editingFinished.connect(
            self.check_server_value)

        # On change of folder value, check the connection.
        self.comboFile.currentIndexChanged.connect(
            self.check_folder_value)
        self.comboFile.lineEdit().editingFinished.connect(
            self.check_folder_value)

        self.setFocus()

    def show_about_window(self):
        self.about_window.show()

    def show_deploy_window(self, cmd, source, destination):
        self.deploy_window.server = self._compare_server
        sourcefolder = source.split('"')[-2]
        self.deploy_window.source_path = '\\'.join(sourcefolder.split('\\')[-5:-3])
        self.deploy_window.deploy_path = destination.split('"')[-2]
        self.deploy_window.cmd = cmd
        self.deploy_window.update_deploy_label()
        self.deploy_window.show()

    def showContextMenu(self, position):
        """Creates a context menu for left click on tree."""
        menu = QMenu(self)
        copy = QAction('Copy', self) 
        deploy = QAction('Deploy', self)
        no_deploy = QAction('No local to deploy', self)
        menu.addAction(copy)
        

        # Add deploy option if left click is on valid Project node.
        current = self.treeWidget.currentItem()
        if not current.parent():
            menu.addSeparator()
            if current.text(1) != 'No local copy found':
                menu.addAction(deploy)
            else:
                menu.addAction(no_deploy)

        copy.triggered.connect(self.copy_text)
        deploy.triggered.connect(self.deploy_project)
        menu.popup(self.treeWidget.mapToGlobal(position))

    def deploy_project(self, project):
        """Starts window to deploy the project to the given server."""
        deploy_wizard = find_deployment_exe()

        if not deploy_wizard:
            QMessageBox.critical(self, "Deploy Error",
                'No Deploy Wizard installed. Check your SQL installation.')
            return
        
        project = self.treeWidget.currentItem()
        
        project_details = [x for x in self._projects
                           if x.name == project.text(0)][0]

        # Source Path
        fmt = '/SourcePath:"{}" '
        ispac_file = project_details.path.replace('\\obj\\','\\bin\\')
        ispac_file = ispac_file.replace('.dtproj','.ispac')
        if not os.path.isfile(ispac_file):
            QMessageBox.critical(self, "Deploy Error",
                             'No valid ispac file found to deploy.')
            return
        source_path = fmt.format(ispac_file)

        # Destination Server
        fmt = '/DestinationServer:"{}" '
        dest_server = fmt.format(self._compare_server)

        # Destination Path
        fmt = '/DestinationPath:"/{a[0]}/{a[1]}/{a[2]}" '
        dest_path = fmt.format(a = ['SSISDB',
                              project_details.folder,
                              project_details.name])

        # Command Line
        cmd_line = ' '.join(['"{}"'.format(deploy_wizard),
                            '/Silent ',
                             source_path,
                             dest_server,
                             dest_path])

        #QMessageBox.information(self, "Deploy", 'Can Deploy to:\n{}'.format(
        #    cmd_line))

        self.show_deploy_window(cmd_line, source_path, dest_path)

    def copy_text(self):
        """Copies the selected text from the tree."""
        try:
            current_item = self.treeWidget.currentItem()#.text(0)
        except:
            return

        # Lowest level of tree
        if current_item.childCount() == 0:
            text = current_item.text(0)
        # Second level of tree.
        elif current_item.parent():
            text = '{} - {}'.format(current_item.parent().text(0),
                                    current_item.text(0))
            for n in range(current_item.childCount()):
                text += '\n\t{}'.format(current_item.child(n).text(0))
        else:
            text = current_item.text(0)
            for n in range(current_item.childCount()):
                text += '\n{}'.format(current_item.child(n).text(0))
                for n1 in range(current_item.child(n).childCount()):
                    text += '\n\t{}'.format(
                        current_item.child(n).child(n1).text(0))        

        pyperclip.copy(text)      

    def compare(self):
        """Compares the local project against the deployed project."""
##        if license_check():
##            QMessageBox.critical(self, "Expired", 'No longer available.')
##            return
        
        # Check the server is valid
        if self._current_server == '' or not self._projects:
            QMessageBox.warning(self, "Warning", 'Please select a valid server.')
            return
        
        # Check that the folder is valid.
        if not os.path.isdir(self._current_folder):
            QMessageBox.warning(self, "Warning", 'Please select a valid folder.')
            return

        # Get dtproj files
        local_projects = lp.find_obj_path(self._current_folder)
        if not local_projects:
            QMessageBox.warning(self, "Warning",
                    'No project files found. Check folder and try again.')
            return

        # Match up the local project to server project.
        local_project_files = {x:os.path.basename(x) for x in local_projects}
        project_matches = {p:[k for k,v in local_project_files.items()
                              if p.name == v.split('.')[0]]
                           for p in self._projects}       

        duplicates = check_dupes(project_matches)
        if duplicates:
            message = 'The following projects have mulitple local versions - '
            message += '{}/n'.format('\t\n'.join(duplicates))
            message += 'Please check the folder you selected and try again.'
            QMessageBox.warning(self,message)
            return

        # Add path to server_projects
        self.append_project_path(project_matches)

        # Show message to confirm projects are being compared and set projects
        project_matches = self.projects_to_compare(project_matches)

        # Reset the tree view ahead of the reload.
        self.reset_tree()
        
        # Compare the packages between the server local
        
        for server_project, local_file in sorted(
                            project_matches.items(),
                            key=lambda x: x[0].name):
            if local_file:
                compares = deploy_check.main(self._connection,
                                             server_project.name, local_file[0])
                self.add_to_tree(server_project, compares)
            else:
                self.add_to_tree(server_project, None, no_local=True)

        # Add the successful server and folder to the history to be used again.
        self.add_server_history()
        self.add_folder_history()
        self._compare_server = self._current_server
        
        self.treeWidget.show()

    def append_project_path(self, local_projects):
        """Appends the local path to the project if available."""
        for project in self._projects:
            project.append_path({k.name:v[0] for k,v
                                 in local_projects.items() if v})

    def add_to_tree(self, server_project, compares, no_local = False):
        """Adds a new trunk to the tree view for that particular project."""       
        project_item = QTreeWidgetItem(self.treeWidget)
        project_item.setText(0,server_project.name)
        project_item.setToolTip(0,server_project.last_deploy())
        if no_local:
            project_item.setIcon(0,self.error_icon)
            project_item.setText(1,'No local copy found')
            return
        if not compares:
            project_item.setIcon(0,self.success_icon)
            project_item.setText(1,'Projects in Sync')
            return
        project_item.setIcon(0,self.project_icon)
        for comp_type, packages in [(k,v) for k,v in
                                    sorted(compares.items(), key=lambda x: x[0])
                                    if v]:
            folder_item = QTreeWidgetItem(project_item)
            folder_item.setText(0,comp_type[2:])
            folder_item.setIcon(0,self.folder_icon)
            folder_item.setToolTip(0, self.tool_tips[comp_type])
            for package in packages:
                package_item = QTreeWidgetItem(folder_item)
                package_item.setText(0,package[0])
                package_item.setIcon(0,self.package_icon)
                if comp_type == '2.No Local Version':
                    package_item.setText(2,str(package[1]))
                elif comp_type == '1.No Server Version':
                    package_item.setText(1,str(package[1]))
                else:
                    package_item.setText(1,str(package[1]))
                    package_item.setText(2,str(package[2]))
                
                package_item.setIcon(0,self.package_icon)
                            
    def projects_to_compare(self, projects):
        """Show message to confirm projects are being compared and set projects."""
        project = self.comboProject.currentText()
        if project in ['', 'All']:
            message = ('Comparing all projects on {} to local copy {}'.format(
                self._current_server, self._current_folder))
            self.statusbar.showMessage(message)
        else:
            message = ("Comparing '{}' project on {} to local copy {}".format(
                project, self._current_server, self._current_folder))
            self.statusbar.showMessage(message)
            projects = {k:v for k,v in
                        projects.items() if k.name == project}
        return projects 

    def check_server_value(self):
        """Checks the value of the server box and checks the connection."""
        if not self.comboServer.currentText():
            self.server_neutral()
            return
        new_value = self.comboServer.currentText()
        if self._current_server != new_value:
            self._current_server = new_value
            self._connection = check_server(self._current_server)
            self.statusbar.showMessage('finally here')
            if self._connection and type(self._connection) != str:
                self.successful_server()
            else:
                self.server_failure(
                    self._connection if self._connection
                    else 'Unable to connect to SSISDB')
                self._connection = None
                self.clear_projects()
                
    def successful_server(self):
        """Shows a successful connection to get projects."""
        self.server_success()
        #self.add_server_history()
        self.set_projects()

    def set_projects(self):
        self._projects = server.get_projects(self._connection)
        if self._projects:
            message = 'Projects: %s' %(', '.join(
                [x.name for x in self._projects]))
            self.add_projects()
            self.statusbar.showMessage(message)
        else:
            self.statusbar.showMessage('No projects found on server.')

    def add_projects(self):
        """Adds projects to project drop down."""
        items = ['All'] + [x.name for x in self._projects]
        self.comboProject.clear()
        self.comboProject.addItems(items)
        self.comboProject.show()

    def clear_projects(self):
        """Clears project drop down."""
        self._projects = []
        self.comboProject.clear()
        self.comboProject.hide()

    def add_server_history(self):
        """Adds to the existing history if server is successfully searched."""
        current_text = self.comboServer.currentText()
        all_items = [self.comboServer.itemText(i) for i
                     in range(self.comboServer.count())]

        if (current_text not in all_items):
            self.comboServer.addItem(current_text)
            add_history(current_text, all_items, 'servers')

    def check_folder_value(self):
        """Checks the value of the folder is a real directory."""
        if not self.comboFile.currentText():
            self.folder_neutral()
            return
        new_value = self.comboFile.currentText()
        if self._current_folder != new_value:
            self._current_folder = new_value
            if os.path.isdir(new_value):
                self.folder_success()
                #self.add_folder_history()
            else:
                self.folder_failure('The folder does not exist.')

    def check_folder(self):
        """Checks if the folder exists."""
        if os.path.isdir(self._current_folder):
            self.folder_success()
            self.add_folder_history()
        else:
            self.folder_failure('The folder does not exist.')

    def add_folder_history(self):
        """Adds to the existing history if folder exists."""
        current_text = self.comboFile.currentText()
        all_items = [self.comboFile.itemText(i) for i
                     in range(self.comboFile.count())]

        if (current_text not in all_items):
            self.comboFile.addItem(current_text)
            add_history(current_text, all_items, 'locals')
            
    def reset_app(self):
        """Sets application back to start position."""
        self.comboServer.setCurrentIndex(-1)
        self.comboFile.setCurrentIndex(-1)
        self.setFocus()
        self.reset_tree()
        self.comboProject.hide()
        self._current_server = ''
        self._current_folder = ''
        self._compare_server = ''
        self._connection = None
        self._projects = []
        self.comboProject.hide()
        self.treeWidget.hide()

    def reset_tree(self):
        """Clears the tree view and hides from window."""
        self.treeWidget.clear()
        self.treeWidget.hide()
        
    def browse_file(self):
        """Shows directory explorer to pick a folder."""
        start_folder = (self._current_folder if self._current_folder != ''
                        else 'C:\\')
        self._current_folder = str(QFileDialog.getExistingDirectory(self,
                                                         "Select Directory",
                                                         start_folder))
        self.comboFile.lineEdit().setText(
            QDir.toNativeSeparators(self._current_folder))
        self.check_folder()