Beispiel #1
0
 def testButtonClick(self):
     """Indirect qt signal emission using the QPushButton.click() method """
     button = QPushButton('label')
     QObject.connect(button, SIGNAL('clicked()'), self.cb)
     self.args = tuple()
     button.click()
     self.assertTrue(self.called)
 def testButtonClick(self):
     """Indirect qt signal emission using the QPushButton.click() method """
     button = QPushButton('label')
     QObject.connect(button, SIGNAL('clicked()'), self.cb)
     self.args = tuple()
     button.click()
     self.assert_(self.called)
class CheckUpdateDialog(QDialog):
    def __init__(self, settings, parent=None) -> None:
        QDialog.__init__(self)
        self.settings = settings
        self.signal = CheckUpdateSignals()
        self.current_version = 'Dev'
        self.downloadUrl = ''
        currentVersionLabel = QLabel('Current Version: {}'.format(
            self.current_version))
        self.latestVersionLabel = QLabel(
            'Latest Version: {}'.format('Unknown'))
        self.checkUpdatePushButton = QPushButton('Check Update')
        self.checkUpdatePushButton.clicked.connect(self.getUpdate)
        self.versionInformationBox = QTextEdit()
        self.versionInformationBox.setReadOnly(True)
        self.downloadButton = QPushButton('Download')
        self.downloadButton.setVisible(False)
        self.downloadButton.clicked.connect(self.downloadUpdate)
        self.copyUrlButton = QPushButton('Copy Download Url')
        self.copyUrlButton.setVisible(False)
        self.copyUrlButton.clicked.connect(self.copy)
        layout = QGridLayout()
        layout.addWidget(currentVersionLabel)
        layout.addWidget(self.latestVersionLabel)
        layout.addWidget(self.versionInformationBox)
        layout.addWidget(self.checkUpdatePushButton)
        layout.addWidget(self.downloadButton)
        layout.addWidget(self.copyUrlButton)
        self.versionInformationBox.setText('')
        self.signal.versionInformationSignal.connect(
            self.setVersionInformation)
        self.signal.versionLabelSignal.connect(self.setVersionLabel)
        self.signal.downloadUrlSignal.connect(self.updateDownloadUrl)
        self.setLayout(layout)
        self.setWindowTitle('Check Update')
        self.setWindowFlag(Qt.WindowMinMaxButtonsHint)
        self.checkUpdatePushButton.click()

    def getUpdate(self):
        self.checkUpdatePushButton.setDisabled(True)
        worker = CheckUpdateWorker(self.settings, self)
        worker.start()

    def setVersionLabel(self, text: str):
        self.latestVersionLabel.setText('Latest Version: {}'.format(text))

    def setVersionInformation(self, text: str):
        self.versionInformationBox.setText(text)

    def updateDownloadUrl(self, url: str):
        self.downloadButton.setVisible(True)
        self.copyUrlButton.setVisible(True)
        self.downloadUrl = url

    def downloadUpdate(self):
        QDesktopServices.openUrl(self.downloadUrl)

    def copy(self):
        pyperclip.copy(self.downloadUrl)
        self.copyUrlButton.setText('Copied!')
    def testButtonClickClose(self):
        button = QPushButton()
        button.connect(button, SIGNAL('clicked()'), SLOT('close()'))

        button.show()
        self.assertTrue(button.isVisible())
        button.click()
        self.assertTrue(not button.isVisible())
    def testButtonClickClose(self):
        button = QPushButton()
        button.connect(button, SIGNAL('clicked()'), SLOT('close()'))

        button.show()
        self.assert_(button.isVisible())
        button.click()
        self.assert_(not button.isVisible())
 def testButton(self):
     #Connecting a lambda to a QPushButton.clicked()
     obj = QPushButton('label')
     ctr = Control()
     func = lambda: setattr(ctr, 'arg', True)
     QObject.connect(obj, SIGNAL('clicked()'), func)
     obj.click()
     self.assert_(ctr.arg)
     QObject.disconnect(obj, SIGNAL('clicked()'), func)
    def testWindowButtonClickClose(self):
        button = QPushButton()
        window = QWidget()
        window.connect(button, SIGNAL('clicked()'), SLOT('close()'))

        window.show()
        self.assertTrue(window.isVisible())
        button.click()
        self.assertTrue(not window.isVisible())
Beispiel #8
0
 def testButton(self):
     #Connecting a lambda to a QPushButton.clicked()
     obj = QPushButton('label')
     ctr = Control()
     func = lambda: setattr(ctr, 'arg', True)
     QObject.connect(obj, SIGNAL('clicked()'), func)
     obj.click()
     self.assert_(ctr.arg)
     QObject.disconnect(obj, SIGNAL('clicked()'), func)
    def testWindowButtonClickClose(self):
        button = QPushButton()
        window = QWidget()
        window.connect(button, SIGNAL('clicked()'), SLOT('close()'))

        window.show()
        self.assert_(window.isVisible())
        button.click()
        self.assert_(not window.isVisible())
 def testQuit(self):
     app = Test([])
     button = QPushButton("BUTTON")
     app.connect(button, SIGNAL("clicked()"), app.called)
     button.click()
     self.assertTrue(app._called)
Beispiel #11
0
class MainWindow(QMainWindow):

    kill_thread = Signal()

    def __init__(self, app):

        self.app = app
 
        # self.qmp = QMP('localhost', 55555)
        self.qmp = QMP()

        self.qmp.stateChanged.connect(self.handle_pause_button)
        self.qmp.connectionChange.connect(self.handle_connect_button)

        self.paused = False

        super().__init__()
        self.init_ui()

        self.qmp.timeUpdate.connect(self.update_time)
        self.t = TimeThread(self.qmp)
        
        self.time_mult = TimeMultiplier(self.qmp, self.kill_thread)

        self.window = []

        self.default_theme = QGuiApplication.palette()

    def init_ui(self):

        # Window Setup
        self.setWindowTitle("QEMU Control")
        self.setGeometry(100, 100, 275, 225)
        self.setFixedSize(self.size())

        # App Icon
        icon = QIcon('package/icons/qemu-official.png')
        self.setWindowIcon(icon)

        # User Interface
        self.menu_bar()
        self.grid_layout()

        self.show()

    def menu_bar(self):

        bar = self.menuBar()

        # Menu Bar Actions
        file_ = bar.addMenu("File")
        edit = bar.addMenu("Edit")
        run = bar.addMenu("Run")
        tools = bar.addMenu("Tools")
        help_ = bar.addMenu("Help")

        # File Menu Options
        open_ = QAction("Open Image", self)
        file_.addAction(open_)

        exit_ = QAction("Exit", self)
        exit_.triggered.connect(self.close)
        exit_.setShortcut('Ctrl+W')
        file_.addAction(exit_)

        # Edit Menu Options
        prefs = QAction("Preferences", self, triggered=lambda:self.open_new_window(Preferences(self.app, self.default_theme, self.qmp, self.t)))
        edit.addAction(prefs)

        # Run Menu Options
        pause = QAction("Pause", self, triggered=lambda:self.qmp.command('stop'))
        run.addAction(pause)

        play = QAction("Play", self, triggered=lambda:self.qmp.command('cont'))
        run.addAction(play)

        # Debug Menu Options
        hexdmp = QAction("Memory Dump", self, triggered=(lambda: self.open_new_window(MemDumpWindow(self.qmp)) if self.qmp.isSockValid() else None))
        tools.addAction(hexdmp)

        asm = QAction("Assembly View", self, triggered=(lambda: self.open_new_window(AssemblyWindow(self.qmp)) if self.qmp.isSockValid() else None))
        tools.addAction(asm)

        registers = QAction("CPU Register View", self, triggered=(lambda: self.open_new_window(RegisterView(self.qmp)) if self.qmp.isSockValid() else None))
        tools.addAction(registers)

        errors = QAction("Logging View", self, triggered=lambda:self.open_new_window(LoggingWindow(self.qmp)))
        tools.addAction(errors)

        tree = QAction("Memory Tree", self, triggered=(lambda: self.open_new_window(MemTree(self.qmp, self)) if self.qmp.isSockValid() else None))
        tools.addAction(tree)

        mult = QAction("Time Multiplier", self, triggered=(lambda: self.time_mult.show() if self.qmp.isSockValid() else None))
        tools.addAction(mult)

        trace = QAction("Trace Event Viewer", self, triggered=lambda: self.open_new_window(TraceWindow(self.qmp)))
        tools.addAction(trace)

        self.addPlugins(tools)
        # Help Menu Options 
        usage = QAction("Usage Guide", self)
        help_.addAction(usage)

    def addPlugins(self, menu):
        plugins = menu.addMenu('Plugins')
        self.manager = PluginManager()
        self.manager.setPluginPlaces(['plugins'])
        self.manager.locatePlugins()
        self.manager.loadPlugins()
        for plugin in self.manager.getAllPlugins():
            plugins.addAction(QAction(plugin.name, self, triggered=(lambda: self.open_new_window(plugin.plugin_object.display(self.qmp)) if self.qmp.isSockValid() else None)))
        

    def grid_layout(self):

        grid = QVBoxLayout()
        grid.setSpacing(15)

        self.pause_button = QPushButton('■')
        self.running_state = QLabel('Current State: <font color="grey">Inactive</font>')

        def cont_sim():
            self.pause_button.setText('■')
            self.running_state.setText('Current State: <font color="green">Running</font>')
            self.qmp.command('cont')

        def stop_sim():
            self.pause_button.setText('▶')
            self.running_state.setText('Current State: <font color="red">Paused</font>')
            self.qmp.command('stop')

        subgrid = QHBoxLayout()

        self.pause_button.clicked.connect(lambda: stop_sim() if not self.paused else cont_sim())
        self.pause_button.setFixedSize(QSize(50, 50))
        subgrid.addWidget(self.pause_button, 0)
        # self.pause_button.setCheckable(True)

        # self.handle_pause_button(False)
        self.pause_button.setEnabled(False)

        meatball = QLabel(self)
        logo = QPixmap('package/icons/nasa.png')
        logo = logo.scaled(75, 75, Qt.KeepAspectRatio)
        meatball.setPixmap(logo)
        subgrid.addWidget(meatball, 1)

        grid.addLayout(subgrid, 0)

        self.time = QLabel('Time: 00:00:00')
        self.time.setFont(QFont('Courier New'))
        grid.addWidget(self.time, 1)

        grid.addWidget(self.running_state, 2)

        self.banner = QLabel('<font color="grey">Connect to QMP to get started!</font>')
        grid.addWidget(self.banner, 3)

        conn_grid = QHBoxLayout()

        self.connect_button = QPushButton("Connect")
        self.connect_button.setCheckable(True)
        self.connect_button.clicked.connect(self.qmp_start)

        self.host = QLineEdit()
        self.host.returnPressed.connect(lambda: self.connect_button.click() if not self.connect_button.isChecked() else None)

        self.port = QLineEdit()
        self.port.returnPressed.connect(lambda: self.connect_button.click() if not self.connect_button.isChecked() else None)


        conn_grid.addWidget(self.host)
        conn_grid.addWidget(self.port)
        conn_grid.addWidget(self.connect_button)

        grid.addLayout(conn_grid)

        center = QWidget()
        center.setLayout(grid)
        self.setCentralWidget(center)

    def throwError(self):
        msgBox = QMessageBox(self)
        msgBox.setText('Lost Connection to QMP!')
        msgBox.show()

    @Slot(bool)
    def handle_pause_button(self, value):
        # Catches signals from QMPWrapper
        #print('recieved: ', value)
        # time.sleep(0.05) # fix race condition
        if value:
            self.paused = False
            self.pause_button.setText('■')
            self.running_state.setText('Current State: <font color="green">Running</font>')
        elif not value and value is not None:
            self.paused = True 
            self.pause_button.setText('▶')
            self.running_state.setText('Current State: <font color="red">Paused</font>')

    def handle_connect_button(self, value):
        self.connect_button.setChecked(value)
        self.host.setReadOnly(value)
        self.port.setReadOnly(value)

    def open_new_window(self, new_window):
        if self.qmp.isSockValid():
            self.window.append(new_window)

    def update_time(self, time):
        date = datetime.fromtimestamp(time / 1000000000, timezone.utc)
        self.time.setText(f'Time: {date.day - 1:02}:{date.hour:02}:{date.minute:02}:{date.second:02}') # -1 for day because it starts from 1

    def qmp_start(self):
        if self.qmp.isSockValid():
            self.qmp.sock_disconnect()
            self.kill_thread.emit()
            self.banner.setText('<font color="grey">Connect to QMP to get started!</font>')
            self.pause_button.setText('■')
            self.running_state.setText('Current State: <font color="grey">Inactive</font>')
            self.pause_button.setEnabled(False)
            return
        else:
            s = self.port.text()
            if s.isnumeric():
                self.qmp.sock_connect(self.host.text(), int(s))
                if self.qmp.isSockValid():
                    self.time_mult.start()
                    self.banner.setText('QEMU Version ' + str(self.qmp.banner['QMP']['version']['package']))
                    self.pause_button.setEnabled(True)
            else:
                self.host.setText('127.0.0.1')
                self.port.setText('55555')
                self.qmp.sock_connect('127.0.0.1', 55555)
                if self.qmp.isSockValid():
                    self.time_mult.start()
                    self.banner.setText('QEMU Version ' + str(self.qmp.banner['QMP']['version']['package']))
                    self.pause_button.setEnabled(True)
        # check if running initally
        if self.qmp.running:
            self.paused = False
            self.pause_button.setText('■')
            self.running_state.setText('Current State: <font color="green">Running</font>')
        else:
            self.paused = True 
            self.pause_button.setText('▶')
            self.running_state.setText('Current State: <font color="red">Paused</font>')
        if not self.qmp.isAlive():
            self.qmp.start()
        if not self.t.isAlive():
            self.t.start()

    def closeEvent(self, event):
        self.kill_thread.emit()
        event.accept()

    def show_time_mult(self):
        self.scene = QGraphicsScene()
        self.view = QGraphicsView(self.scene)
        self.scene.addItem(self.time_mult.chart)
        self.view.show()
Beispiel #12
0
class CourseTreeWidget(QWidget, ABookCore):
    def __init__(self, path, settings, session):
        QWidget.__init__(self)
        ABookCore.__init__(self, path, settings, session)

        self.signal = CourseTreeWidgetSignals()
        self.selectedList = []

        self.treeWidget = QTreeWidget()
        self.treeWidget.setHeaderLabels(['Name', "Course ID", "Chapter ID"])
        self.treeWidget.itemChanged.connect(self.checkbox_toggled)
        self.treeWidget.clicked.connect(self.loadResourceList)

        self.addDownloadTaskButton = QPushButton("Add to Downloader")
        self.addDownloadTaskButton.clicked.connect(self.addDownloadTask)

        self.importCourseButton = QPushButton("Import Courses")
        self.importCourseButton.clicked.connect(self.startImportCourseWidget)

        main_layout = QGridLayout()
        main_layout.addWidget(self.treeWidget, 0, 0, 1, 2)
        main_layout.addWidget(self.importCourseButton, 1, 0)
        main_layout.addWidget(self.addDownloadTaskButton, 1, 1)
        main_layout.setMargin(0)
        self.setLayout(main_layout)

        if settings['first_launch'] is True:
            settings['first_launch'] = False
            self.importCourseButton.click()
        else:
            self.createTreeRoot()

    def createTreeRoot(self):
        courseList = self.getCourseList()
        for course in courseList:
            courseId = course['courseInfoId']
            currentChapterList = self.getChapterList(courseId)
            self.createTree(self.treeWidget, 'course', course,
                            currentChapterList, courseId)

    def createTree(self, parentItem, itemType, itemData, chapterList,
                   courseId):
        if itemType == 'course':
            courseName = itemData['courseTitle']
            courseId = itemData['courseInfoId']
            courseItem = self.createCourseTreeItem(courseName, courseId,
                                                   'None', True)
            parentItem.addTopLevelItem(courseItem)
            childChapterList = self.getChildChapterList(chapterList, {'id': 0})
            self.createTree(courseItem, 'chapter', childChapterList,
                            chapterList, courseId)
        elif itemType == 'chapter':
            for chapter in itemData:
                childChapterList = self.getChildChapterList(
                    chapterList, chapter)
                chapterName = chapter['name']
                chapterId = chapter['id']
                hasChild = len(childChapterList) > 0
                chapterItem = self.createCourseTreeItem(
                    chapterName, courseId, chapterId, hasChild)
                parentItem.addChild(chapterItem)
                if hasChild:
                    self.createTree(chapterItem, 'chapter', childChapterList,
                                    chapterList, courseId)
        else:
            raise KeyError('Wrong TODO')

    def checkbox_toggled(self, node: QTreeWidgetItem, column: int):
        if node.checkState(column) == Qt.Checked:
            self.selectedList.append(
                [node.text(0), node.text(1),
                 node.text(2)])
        elif node.checkState(column) == Qt.Unchecked:
            if len(self.selectedList) > 1:
                self.selectedList.remove(
                    [node.text(0), node.text(1),
                     node.text(2)])
            else:
                self.selectedList = []

    def createCourseTreeItem(self, name: str, courseId: str, chapterId: str,
                             hasChild: bool):
        item = QTreeWidgetItem()
        item.setText(0, str(name))
        item.setText(1, str(courseId))
        item.setText(2, str(chapterId))
        if hasChild is True:
            item.setFlags(item.flags() | Qt.ItemIsTristate
                          | Qt.ItemIsUserCheckable)
        else:
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(0, Qt.Unchecked)
        return item

    def addDownloadTask(self):
        for item in self.selectedList:
            if item[1] != "None" and item[2] != "None":
                courseId = item[1]
                chapterId = item[2]
                downloadList = self.getResourceList(courseId, chapterId)
                if downloadList is not None:
                    for resource in downloadList:
                        fileDir, filePath, fileName, coursePath = self.getResourcePath(
                            courseId, chapterId, resource["resourceInfoId"])
                        self.signal.addDownloadTask.emit(
                            fileName, filePath,
                            "http://abook.hep.com.cn/ICourseFiles/" +
                            resource["resFileUrl"])

    def startImportCourseWidget(self):
        wizard = ImportCourseWizard(self)
        wizard.show()

    def loadResourceList(self):
        # When triggered on click, first adjust the width of the column
        self.treeWidget.resizeColumnToContents(0)
        self.treeWidget.resizeColumnToContents(1)
        self.treeWidget.resizeColumnToContents(2)

        # Get the course_id and chapter_id
        courseId = self.sender().currentItem().text(1)
        chapterId = self.sender().currentItem().text(2)

        # Ignore the root nodes
        if courseId != "None" and chapterId != "None":

            # Get the resource list
            # resource_list = self.get_resource_info(courseId, chapterId)
            resourceList = self.getResourceList(courseId, chapterId)
            # Clear the FileListWidget
            self.signal.clearFileListWidget.emit()
            # If resource list is not empty
            if isinstance(resourceList, list):
                # Each resource item is a QStandardItem
                # data role -1 stores the url of the resource
                # data role -2 stores the url of the preview image of the resource
                # data role Qt.TooltipRole stores the url of the resource
                # data role Qt.DecorationRole stores the preview image of the resource
                # We need to lazy load and cache the preview image so that the main thread will not be blocked
                # 1. create items without the Qt.DecorationRole and add it to resourceItemList
                # 2. pass the resource_item_list to LoadPicWorker to cache and load
                resourceItemList = []
                for resource in resourceList:
                    resName = resource["resTitle"]
                    urlBase = "http://abook.hep.com.cn/ICourseFiles/"
                    resFileUrl = urlBase + resource["resFileUrl"]
                    resourceItem = QStandardItem(resName)
                    resourceItem.setData(resFileUrl, Qt.ToolTipRole)
                    resourceItem.setData(resFileUrl, -1)
                    resourceItem.setData(resource['picUrl'], -2)
                    self.signal.appendRowFileListWidget.emit(resourceItem)
                    resourceItemList.append(resourceItem)
                loadPicWorker = LoadPicWorker(resourceItemList, self)
                loadPicWorker.start()
Beispiel #13
0
    def init_ui(self):

        self.setWindowTitle('Trace Event Window')
        self.setGeometry(100, 100, 800, 600)

        bar = self.menuBar()

        file_ = bar.addMenu('File')
        export_log = QAction('Save to File',
                             self,
                             triggered=lambda: self.save_log())

        options = bar.addMenu('Options')
        auto_refresh = QAction(
            'Auto Refresh',
            self,
            checkable=True,
            triggered=lambda: self.timer.start(100)
            if auto_refresh.isChecked() else self.timer.stop())
        auto_refresh.setChecked(True)

        options.addAction(auto_refresh)
        file_.addAction(export_log)

        vgrid = QVBoxLayout()
        grid = QHBoxLayout()

        self.tree = QTreeWidget()
        self.tree.setHeaderLabels(['Name'])

        self.top = []
        self.lst = []

        for n, event in enumerate(self.trace_events):
            word = event.split('_')[0]
            if word not in self.top:
                self.top.append(word)
                item = QTreeWidgetItem(self.tree)
                self.lst.append(item)
                item.setText(0, word)
            subitem = QTreeWidgetItem(item)
            subitem.setText(0, '    ' + event.split(' : ')[0])
            # subitem.setCheckState(0, Qt.Unchecked)
            cbox = QCheckBox()
            cbox.stateChanged.connect(lambda state, text=subitem.text(0): self.
                                      handle_checked(state, text))
            self.tree.setItemWidget(subitem, 0, cbox)

        # self.tree.setColumnWidth(0, 25)

        self.tracelist = QLabel()
        self.disp_output()

        self.traceview = QScrollArea()
        self.traceview.setWidget(self.tracelist)
        self.traceview.setWidgetResizable(True)

        search = QHBoxLayout()

        self.search_bar = QLineEdit(self)

        self.completer = QCompleter(self.top, self)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)

        self.search_bar.setCompleter(self.completer)

        search_button = QPushButton('Search')
        search_button.clicked.connect(lambda: self.tree.setCurrentItem(
            self.lst[self.top.index(self.search_bar.text())]))

        expand = QPushButton('▼')
        expand.setFixedSize(QSize(25, 25))
        expand.clicked.connect(lambda: self.tree.expandAll())

        collapse = QPushButton('▲')
        collapse.setFixedSize(QSize(25, 25))
        collapse.clicked.connect(lambda: self.tree.collapseAll())

        self.search_bar.returnPressed.connect(lambda: search_button.click())

        search.addWidget(self.search_bar)
        search.addWidget(search_button)
        search.addWidget(expand)
        search.addWidget(collapse)

        self.digest = QLabel()

        vgrid.addLayout(search)
        vgrid.addWidget(self.tree)

        vgridwid = QWidget()
        vgridwid.setLayout(vgrid)

        split = QSplitter(Qt.Horizontal)

        split.addWidget(vgridwid)
        split.addWidget(self.traceview)

        split.setStretchFactor(1, 1)

        # grid.addLayout(vgrid)
        grid.addWidget(split)
        # grid.addWidget(self.tracelist)

        self.disp_output()

        center = QWidget()
        center.setLayout(grid)
        self.setCentralWidget(center)
        self.show()
Beispiel #14
0
class SearchReplaceDialog(QDialog):
    """Search & Replace window
    """
    def __init__(self, parent, initial_query=None):
        """Initialize the search window
        """

        super(SearchReplaceDialog, self).__init__(parent)

        self.parent = parent
        self.prefs = parent.prefs
        self.items_checked = 0

        self.search_button = QPushButton('Search')
        self.search_text = MySearchField(self.search_button)
        self.search_text.setPlaceholderText("Enter search query here")
        self.search_button.clicked.connect(self.submit_search)
        input_layout = QHBoxLayout()
        input_layout.addWidget(self.search_text)
        input_layout.addWidget(self.search_button)

        self.results_tree = QTreeView()
        self.results_tree.setRootIsDecorated(False)
        self.results_tree.setAlternatingRowColors(True)
        self.results_tree.setAllColumnsShowFocus(True)
        self.results_tree.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.results_tree.setSelectionMode(QAbstractItemView.SingleSelection)
        self.results_tree.doubleClicked.connect(self.go_to_object)

        self.whole_field_checkbox = QCheckBox("Whole Field Only", self)
        self.advanced_search_checkbox = QCheckBox("Advanced Search", self)
        self.advanced_search_checkbox.stateChanged.connect(
            self.advanced_search_checked)
        self.ignore_geometry_checkbox = QCheckBox("Ignore Geometry", self)
        self.go_button = QPushButton('Go')
        self.go_button.clicked.connect(self.go_to_object)
        checks_layout = QHBoxLayout()
        checks_layout.addWidget(self.whole_field_checkbox)
        checks_layout.addWidget(self.advanced_search_checkbox)
        checks_layout.addWidget(self.ignore_geometry_checkbox)
        checks_layout.addStretch()
        checks_layout.addWidget(self.go_button)

        self.query_label = QLabel("Query:")
        self.query_label.setEnabled(False)
        self.query_text = QLineEdit()
        self.query_text.setEnabled(True)
        self.query_text.setReadOnly(True)
        self.query_text.setFrame(False)
        self.query_text.setStyleSheet("""QLineEdit {
                                   background-color: LightGray;
                                   color: white;
                                   } """)
        query_layout = QHBoxLayout()
        query_layout.addWidget(self.query_label)
        query_layout.addWidget(self.query_text)

        self.select_label = QLabel("Select:")
        self.select_all_button = QPushButton("All")
        self.select_none_button = QPushButton("None")
        self.select_invert_button = QPushButton("Invert")
        self.delete_button = QPushButton("Delete Objects")
        self.select_all_button.clicked.connect(self.select_all_clicked)
        self.select_none_button.clicked.connect(self.select_none_clicked)
        self.select_invert_button.clicked.connect(self.select_invert_clicked)
        self.delete_button.clicked.connect(self.delete_button_clicked)
        self.delete_button.setEnabled(False)
        selection_layout = QHBoxLayout()
        selection_layout.addWidget(self.select_label)
        selection_layout.addWidget(self.select_all_button)
        selection_layout.addWidget(self.select_none_button)
        selection_layout.addWidget(self.select_invert_button)
        selection_layout.addStretch()
        selection_layout.addWidget(self.delete_button)

        self.replace_with_text = QLineEdit()
        self.replace_with_label = QLabel("Replace With:")
        self.replace_button = QPushButton("Replace")
        self.replace_button.clicked.connect(self.replace_button_clicked)
        self.replace_button.setEnabled(False)
        replace_layout = QHBoxLayout()
        replace_layout.addWidget(self.replace_with_label)
        replace_layout.addWidget(self.replace_with_text)
        replace_layout.addWidget(self.replace_button)

        layout = QVBoxLayout()
        layout.addLayout(input_layout)
        layout.addLayout(checks_layout)
        layout.addLayout(query_layout)
        layout.addWidget(self.results_tree)
        layout.addLayout(selection_layout)
        layout.addLayout(replace_layout)

        self.resize(650, 450)
        self.setLayout(layout)
        self.setWindowTitle("IDF+ Search & Replace")
        self.search_text.setFocus()
        self.setTabOrder(self.search_text, self.search_button)
        self.setTabOrder(self.search_button, self.whole_field_checkbox)
        self.setTabOrder(self.whole_field_checkbox,
                         self.advanced_search_checkbox)
        self.setTabOrder(self.advanced_search_checkbox, self.select_all_button)
        self.setTabOrder(self.select_all_button, self.select_none_button)
        self.setTabOrder(self.select_none_button, self.select_invert_button)
        self.setTabOrder(self.select_invert_button, self.replace_with_text)
        self.setTabOrder(self.replace_with_text, self.replace_button)
        self.setTabOrder(self.replace_button, self.search_text)

        self.results_tree.setModel(self.create_results_model([]))
        self.results_tree.setColumnHidden(2, True)

        if initial_query is not None:
            self.search_text.setText(initial_query)
            self.search_button.click()

    def create_results_model(self, results):
        def add_result_row(row_model, value, obj_class, uuid):
            row_model.insertRow(0)
            row_model.setData(model.index(0, 0), value)
            row_model.setData(model.index(0, 1), obj_class)
            row_model.setData(model.index(0, 2), uuid)

            item_0 = model.itemFromIndex(model.index(0, 0))
            item_0.setCheckState(Qt.Unchecked)
            item_0.setFlags(item_0.flags() | Qt.ItemIsUserCheckable)
            item_0.setEditable(False)

            item_1 = model.itemFromIndex(model.index(0, 1))
            item_1.setEditable(False)

        model = QStandardItemModel(0, 3, self)
        model.setHeaderData(0, Qt.Horizontal, "Value")
        model.setHeaderData(1, Qt.Horizontal, "Class")
        model.setHeaderData(2, Qt.Horizontal, "UUID")

        for hit in results:
            add_result_row(model, hit['value'], hit['obj_class_display'],
                           hit['uuid'])

        return model

    def submit_search(self):
        """Submits a search based on the current query
        """

        user_query = self.search_text.text()
        idf = self.parent.idf
        if not user_query or len(user_query) < 2 or not idf:
            return [], ""
        results, my_query = idf.search(
            user_query, self.whole_field_checkbox.isChecked(),
            self.advanced_search_checkbox.isChecked(),
            self.ignore_geometry_checkbox.isChecked())
        self.query_text.setText(str(my_query))
        self.results_tree.setModel(self.create_results_model(results))
        self.results_tree.model().itemChanged.connect(self.item_checked)
        # self.results_tree.setColumnHidden(2, True)
        self.results_tree.resizeColumnToContents(0)
        self.results_tree.resizeColumnToContents(1)
        self.results_tree.setSortingEnabled(True)

    def item_checked(self, item):

        if item.checkState() == Qt.Checked:
            self.items_checked += 1
        else:
            self.items_checked -= 1

        if self.items_checked > 0:
            self.delete_button.setEnabled(True)
            self.replace_button.setEnabled(True)
        else:
            self.delete_button.setEnabled(False)
            self.replace_button.setEnabled(False)

    def select_all_clicked(self):

        model = self.results_tree.model()
        result_count = model.rowCount()

        for i in range(result_count):
            model.itemFromIndex(model.index(i, 0)).setCheckState(Qt.Checked)

    def select_none_clicked(self):

        model = self.results_tree.model()
        result_count = model.rowCount()

        for i in range(result_count):
            model.itemFromIndex(model.index(i, 0)).setCheckState(Qt.Unchecked)

    def select_invert_clicked(self):

        model = self.results_tree.model()
        result_count = model.rowCount()

        for i in range(result_count):
            item = model.itemFromIndex(model.index(i, 0))
            if item.checkState() == Qt.Checked:
                new_state = Qt.Unchecked
            else:
                new_state = Qt.Checked
            item.setCheckState(new_state)

    def delete_button_clicked(self):
        model = self.results_tree.model()
        result_count = model.rowCount()
        if result_count <= 0 or self.items_checked <= 0:
            return

        question = "Are you sure you want to perform this deletion?\n" \
                   "Undo is currently NOT supported for this operation."
        response = self.confirm_action(question)
        if response is not True:
            return

        for i in range(result_count):
            item_0 = model.itemFromIndex(model.index(i, 0))
            item_2 = model.itemFromIndex(model.index(i, 2))
            if item_0.checkState() != Qt.Checked:
                continue
            field = self.parent.idf.field_by_uuid(item_2.text())
            obj = field._outer
            obj_class = self.parent.idf.idf_objects(obj.obj_class)
            try:
                index = obj_class.index(obj)
                self.parent.idf.remove_objects(obj.obj_class, index, index + 1)
            except ValueError:
                pass  # already deleted

        self.parent.set_dirty(True)
        self.submit_search()
        self.parent.load_table_view(self.parent.current_obj_class)
        QMessageBox.information(self, "Delete Action", "Deletion Complete!")

    def advanced_search_checked(self):
        if self.advanced_search_checkbox.isChecked():
            self.whole_field_checkbox.setEnabled(False)
            self.whole_field_checkbox.setChecked(True)
            self.ignore_geometry_checkbox.setEnabled(False)
            self.ignore_geometry_checkbox.setChecked(False)
        else:
            self.whole_field_checkbox.setEnabled(True)
            self.whole_field_checkbox.setChecked(False)
            self.ignore_geometry_checkbox.setEnabled(True)
            self.ignore_geometry_checkbox.setChecked(False)

    def replace_button_clicked(self):
        search_text = self.search_text.text()
        replace_with_text = self.replace_with_text.text()
        if not search_text:
            return

        model = self.results_tree.model()
        result_count = model.rowCount()
        if result_count <= 0 or self.items_checked <= 0:
            return

        question = "Are you sure you want to perform this replacement?\n" \
                   "Undo is currently NOT supported for this operation."
        response = self.confirm_action(question)
        if response is not True:
            return

        for i in range(result_count):
            item_0 = model.itemFromIndex(model.index(i, 0))
            item_2 = model.itemFromIndex(model.index(i, 2))
            if item_0.checkState() != Qt.Checked:
                continue
            field = self.parent.idf.field_by_uuid(item_2.text())
            if self.whole_field_checkbox.isChecked(
            ) or self.advanced_search_checkbox.isChecked():
                field.value = replace_with_text
            else:
                regex = re.compile(re.escape(search_text), re.IGNORECASE)
                field.value = regex.sub(replace_with_text, field.value)

        self.parent.set_dirty(True)
        self.submit_search()
        self.parent.load_table_view(self.parent.current_obj_class)
        QMessageBox.information(self, "Replacement", "Replacement Complete!")

    def confirm_action(self, question):
        """Confirm user wants to perform action
        """

        flags = QMessageBox.StandardButton.Yes
        flags |= QMessageBox.StandardButton.No
        response = QMessageBox.question(self, "Are you sure?", question, flags)

        if response == QMessageBox.Yes:
            return True
        elif QMessageBox.No:
            return False
        else:
            return False

    def go_to_object(self, index=None):

        if index is None:
            selected = self.results_tree.selectedIndexes()
            if not selected:
                return
            index = selected[0]

        model = self.results_tree.model()
        item = model.itemFromIndex(model.index(index.row(), 2))
        field = self.parent.idf.field_by_uuid(item.text())
        self.parent.activateWindow()
        self.parent.jump_to_field(field)
Beispiel #15
0
 def testQuit(self):
     app = Test([])
     button = QPushButton("BUTTON")
     app.connect(button, SIGNAL("clicked()"), app.called)
     button.click()
     self.assert_(app._called)