コード例 #1
0
ファイル: main_app.py プロジェクト: pcrumley/iseult-v2
    def build_menu(self):
        menubar = self.menuBar()
        menubar.setNativeMenuBar(False)
        bar = self.menuBar()
        # File Menu
        fileMenu = bar.addMenu('&File')

        savePresetAction = QAction('Save Current State', self)
        savePresetAction.triggered.connect(self.open_save_dialog)
        fileMenu.addAction(savePresetAction)

        openSimAction = QAction('Open Simulation', self)
        openSimAction.triggered.connect(self.open_sim_dialog)
        fileMenu.addAction(openSimAction)

        makeAMovieAction = QAction('Make a Movie', self)
        makeAMovieAction.triggered.connect(self.open_movie_dialog)
        fileMenu.addAction(makeAMovieAction)

        exitAct = QAction(' &Quit', self)
        exitAct.setShortcut('Ctrl+Q')
        exitAct.triggered.connect(qApp.quit)

        fileMenu.addAction(exitAct)

        self.views_menu = bar.addMenu("Preset Views")
        self.views_update()
        self.view_dir_watcher = QFileSystemWatcher()
        self.view_dir_watcher.addPath(
            os.path.join(self.IseultDir, '.iseult_configs'))
        self.view_dir_watcher.directoryChanged.connect(self.views_update)
コード例 #2
0
ファイル: LogViewer.py プロジェクト: mygalus/LogViewer
    def on_pb_SearchDir( self ):
        ''' Called when the user presses the Browse button
        '''
        logging.debug( "Browse button pressed" )
        options = QtWidgets.QFileDialog.Options()
        options |= QtWidgets.QFileDialog.DontUseNativeDialog
        directoryName = QtWidgets.QFileDialog.getExistingDirectory(
                        None,
                        "Select Output Folder",
                        "",
                        options=options)
        if directoryName:
            logging.debug( "setting directory name: " + directoryName )
            self.model.setDirectoryName( directoryName )
            self.refreshDir()

            if self.changeDetection == True:
                self._pathToWatch = directoryName
                self._fileSysWatcher = QFileSystemWatcher()
                self._initialContent = os.listdir(self._pathToWatch)
                for f in self._initialContent:
                    if (f != "trace.log"):
                        self._fileSysWatcher.addPath(f)

                self._fileSysWatcher.fileChanged.connect(self.slotDirChanged)
                self._fileSysWatcher.directoryChanged.connect(self.slotDirChanged)
コード例 #3
0
    def __init__(self):
        """The constructor, which calls the super-class-contructor (Extension).

        Loads and sets all settings from settings file.
        Adds .blend as a supported file extension.
        Adds (stl, obj, x3d, ply) as supported file extensions for conversion.
        Adds menu items and the filewatcher trigger function.
        """

        global fs_watcher
        super().__init__()

        # Loads and sets all settings from settings file.
        self.loadAndSetSettings()

        self._supported_extensions = ['.blend']
        self._supported_foreign_extensions = ['stl', 'obj', 'x3d', 'ply']

        # Adds filewatcher and it's connection for blender files.
        fs_watcher = QFileSystemWatcher()
        fs_watcher.fileChanged.connect(self._fileChanged)

        # Adds filewatcher and it's connection for foreign files.
        self._foreign_file_watcher = QFileSystemWatcher()
        self._foreign_file_watcher.fileChanged.connect(
            self._foreignFileChanged)

        # Builds the extension menu.
        self.setMenuName(catalog.i18nc('@item:inmenu', 'CuraBlender'))
        self.addMenuItem(catalog.i18nc('@item:inmenu', 'Open in Blender'),
                         self._setUpFilePathForBlender)
        self.addMenuItem(catalog.i18nc('@item:inmenu', 'Settings'),
                         self._openSettingsWindow)
        self.addMenuItem(catalog.i18nc('@item:inmenu', 'Debug Blenderpath'),
                         self._showBlenderPath)
コード例 #4
0
    def __init__(self, gtomain, parent=None):
        try:
            super(gtoRemote, self).__init__(parent)
            self.gtomain = gtomain
            self.iface = gtomain.iface
            self.debug = gtomain.debug
            self.info = gtoInfo(self)
            self.fs_watcher = None

            if 'remote_watch_file' in gtomain.settings:
                remote_watch_path = gtomain.settings.get(
                    'remote_watch_file', None)
                if remote_watch_path is not None and remote_watch_path != "":
                    remote_watch_path = self.gtomain.helper.getFilePath(
                        remote_watch_path)
                    self.remote_watch_file = os.path.basename(
                        remote_watch_path)
                    self.remote_watch_dir = os.path.dirname(remote_watch_path)

                    if self.debug:
                        self.info.log("Watching:", self.remote_watch_dir)
                    if not os.path.exists(self.remote_watch_dir):
                        os.makedirs(self.remote_watch_dir)
                        if self.debug:
                            self.info.log("Created:", self.remote_watch_dir)

                    self.paths = [self.remote_watch_dir]
                    self.fs_watcher = QFileSystemWatcher(self.paths)
                    #if file already exists
                    self.directory_changed(self.paths[0])
                    self.fs_watcher.directoryChanged.connect(
                        self.directory_changed)
                    self.fs_watcher.fileChanged.connect(self.file_changed)
        except Exception as e:
            self.info.err(e)
コード例 #5
0
class EditorPidWatcher(QObject):

    appeared = pyqtSignal()

    def __init__(self, directory, parent=None):
        super().__init__(parent)
        self._pidfile = directory / 'editor_pid'
        self._watcher = QFileSystemWatcher(self)
        self._watcher.addPath(str(directory))
        self._watcher.directoryChanged.connect(self._check_update)
        self.has_pidfile = False
        self._check_update()

    @pyqtSlot()
    def _check_update(self):
        if self.has_pidfile:
            return

        if self._pidfile.check():
            if self._pidfile.read():
                self.has_pidfile = True
                self.appeared.emit()
            else:
                self._watcher.addPath(str(self._pidfile))

    def manual_check(self):
        return self._pidfile.check()
コード例 #6
0
    def __init__(self,ebeveyn=None):
        super(Gonderici,self).__init__(ebeveyn)
        kutu = QVBoxLayout()
        self.ebeveyn = ebeveyn
        self.setLayout(kutu)
        kutu.setContentsMargins(5,5,5,5)

        self.mesaj_liste = QListWidget()
        self.mesaj_liste.setSelectionMode(QListView.ExtendedSelection)
        kutu.addWidget(self.mesaj_liste)

        self.tum_mesajlar_fonk()
        self.dosya_izleyici = QFileSystemWatcher()
        self.dosya_izleyici.addPath(self.MESAJ_DIZINI)
        self.dosya_izleyici.directoryChanged.connect(self.tum_mesajlar_fonk)

        kutu_h = QHBoxLayout()
        kutu_h.addWidget(QLabel("<b>Mesaj Tipi :</b>"))
        self.mesaj_tipi_text = QComboBox()
        self.mesaj_tipi_text.addItems(["------","bilgi","sistem","kritik",])
        kutu_h.addWidget(self.mesaj_tipi_text)
        kutu.addLayout(kutu_h)

        kutu_h = QHBoxLayout()
#        kutu_h.addWidget(QLabel("<b>Mesaj :</b>"))
        self.gonderilen_text = QTextEdit()
        self.gonderilen_text.setFixedHeight(100)
        kutu_h.addWidget(self.gonderilen_text)

        self.gonder_dugme = QPushButton("Gönder")
        self.gonder_dugme.setFixedHeight(100)
        self.gonder_dugme.clicked.connect(self.gonder_fonk)
        kutu_h.addWidget(self.gonder_dugme)
        kutu.addLayout(kutu_h)
コード例 #7
0
ファイル: mainwindow.py プロジェクト: cyberegoorg/cetech
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)

        self.centralwidget.hide()

        self.project = ProjectManager()
        self.modules_manager = ModuleManager(self)

        self.setTabPosition(Qt.AllDockWidgetAreas, QTabWidget.North)

        self.modules_manager.init_modules([
            CompilerModule,
            LevelWidget,
            AssetViewWidget,
            AssetBrowser,
            LogWidget,
            ProfilerWidget,
            ScriptEditorManager
        ])

        self.file_watch = QFileSystemWatcher(self)
        self.file_watch.fileChanged.connect(self.file_changed)
        self.file_watch.directoryChanged.connect(self.dir_changed)

        self.build_file_watch = QFileSystemWatcher(self)
        self.build_file_watch.fileChanged.connect(self.build_file_changed)
        self.build_file_watch.directoryChanged.connect(self.build_dir_changed)
コード例 #8
0
def test_killed_command(qtbot, tmpdir, py_proc, runner):
    text_file = tmpdir / 'text'
    text_file.write('This is text')

    pidfile = tmpdir / 'pid'
    watcher = QFileSystemWatcher()
    watcher.addPath(str(tmpdir))

    env = {'QUTE_TEXT': str(text_file)}
    cmd, args = py_proc(r"""
        import os
        import time
        import sys

        # We can't use QUTE_FIFO to transmit the PID because that wouldn't work
        # on Windows, where QUTE_FIFO is only monitored after the script has
        # exited.

        with open(sys.argv[1], 'w') as f:
            f.write(str(os.getpid()))

        time.sleep(30)
    """)
    args.append(str(pidfile))

    with qtbot.waitSignal(watcher.directoryChanged, timeout=10000):
        runner.run(cmd, *args, env=env)

    # Make sure the PID was written to the file, not just the file created
    time.sleep(0.5)

    with qtbot.waitSignal(runner.finished):
        os.kill(int(pidfile.read()), signal.SIGTERM)

    assert not text_file.exists()
コード例 #9
0
    def __init__(self, parent=None):
        super().__init__(parent)

        self.mWatchCount = QMap()
        self.mWatcher = QFileSystemWatcher(self)
        self.mWatcher.fileChanged.connect(self.onFileChanged)
        self.mWatcher.directoryChanged.connect(self.onDirectoryChanged)
コード例 #10
0
    def __init__(self):
        """Loads the UI-file and sets up the GUI."""
        super(AutocutView, self).__init__()
        uic.loadUi(Resources.files.autocut_view, self)

        self.setWindowFlags(Qt.WindowCloseButtonHint
                            | Qt.WindowMinimizeButtonHint)
        self.setFixedSize(self.size())

        self.init_stylesheet()

        "QSS HOT RELOAD"
        self.__qss_watcher = QFileSystemWatcher()
        self.__qss_watcher.addPath(Resources.files.qss_dark)
        self.__qss_watcher.fileChanged.connect(self.update_qss)

        # centering the window
        rectangle = self.frameGeometry()
        center_point = QDesktopWidget().availableGeometry().center()
        rectangle.moveCenter(center_point)
        self.move(rectangle.topLeft())

        cross_path = Resources.images.cross
        tick_path = Resources.images.tick
        self.cross = QPixmap(cross_path).scaledToHeight(50, mode=1)
        self.tick = QPixmap(tick_path).scaledToHeight(50, mode=1)

        self.video_image_label.setPixmap(self.cross)
        self.pdf_image_label.setPixmap(self.cross)
コード例 #11
0
ファイル: fswatcher.py プロジェクト: atavacron/galacteek
    def __init__(self):
        super().__init__()

        self._watcher = QFileSystemWatcher(self)
        self._watcher.directoryChanged.connect(self.onChanged)
        self._watcher.fileChanged.connect(self.onChanged)
        self._events = {}
コード例 #12
0
ファイル: iprangescan.py プロジェクト: hktkqwe123/ipscan
    def run_masscan(self):
        self.process = QProcess(self)
        response = IpAsnRangeDoc().search().query('match', owner='amazon.com').execute()

        tmp_file = '/tmp/masscan_in.tmp'
        with open(tmp_file, 'a') as f:
            for iprange_doc in response:
                for range in iprange_doc.ranges:
                    debug('scan cidr %s' % range.cidr)
                    f.write('%s\n' % range.cidr)

        params = ['--output-format', 'json', '--output-filename', '/tmp/masscan_out.tmp', '--source-port', '60000',
                  '-p%s' % ''.join(str(self.scan_ports)[1:-1]),'--rate', '%s' % self.spinBox.value(), '-iL',
                  '/tmp/masscan_in.tmp']
        debug('masscan params' % params)

        self.process.start('masscan', params)

        self.startScanButton.setEnabled(False)
        self.startScanButton.setText('starting..')
        self.process.waitForStarted(1)
        self.startScanButton.setText('stop scan')
        self.startScanButton.setEnabled(True)
        self.spinBox.setEnabled(False)

        watch = QFileSystemWatcher(self)
        watch.addPath('/tmp/masscan_out.tmp')
        watch.fileChanged.connect(functools.partial(self.data_available))

        self.process.setProcessChannelMode(QProcess.MergedChannels)
        self.process.readyReadStandardError.connect(functools.partial(self.stderrReady))
        self.process.stateChanged.connect(functools.partial(self.process_state_change))
コード例 #13
0
def test_killed_command(qtbot, tmpdir, py_proc, runner):
    text_file = tmpdir / 'text'
    text_file.write('This is text')

    pidfile = tmpdir / 'pid'
    watcher = QFileSystemWatcher()
    watcher.addPath(str(tmpdir))

    env = {'QUTE_TEXT': str(text_file)}
    cmd, args = py_proc(r"""
        import os
        import time
        import sys

        # We can't use QUTE_FIFO to transmit the PID because that wouldn't work
        # on Windows, where QUTE_FIFO is only monitored after the script has
        # exited.

        with open(sys.argv[1], 'w') as f:
            f.write(str(os.getpid()))

        time.sleep(30)
    """)
    args.append(str(pidfile))

    with qtbot.waitSignal(watcher.directoryChanged, timeout=10000):
        runner.run(cmd, *args, env=env)

    # Make sure the PID was written to the file, not just the file created
    time.sleep(0.5)

    with qtbot.waitSignal(runner.finished):
        os.kill(int(pidfile.read()), signal.SIGTERM)

    assert not text_file.exists()
コード例 #14
0
    def __init__(self, path, notebook):
        """
        Class representing the actual tab pane for a plain .txt note file, including the editor,
        the toolbar and the save/load logic.

        path is the path to the file(which does not need to exist yet)
        notebook must be the Notebook instance the note will be a part of

        """
        QWidget.__init__(self)
        self.notebook = notebook
        self.path = path
        #Set up the embedded webkit
        self.edit = QTextEdit()

        #set up the toolbar
        self.tools = QWidget()
        self.tools.lo = QHBoxLayout()
        self.tools.setLayout(self.tools.lo)

        if self.path:
            #Watch the file so we can auto reload
            self.watcher = QFileSystemWatcher()
            self.watcher.addPath(self.path)
            self.watcher.fileChanged.connect(self.reload)

        #Put the widgets together
        self.lo = QVBoxLayout()
        self.setLayout(self.lo)
        self.tools = NoteToolBar(self, richtext=False)
        self.lo.addWidget(self.tools)
        self.lo.addWidget(self.edit)

        self.reload()
コード例 #15
0
 def __init__(self, parent=None, watch=False):
     super().__init__(parent)
     self._filename = None
     self._proc = None
     self._remove_file = None
     self._watcher = QFileSystemWatcher(parent=self) if watch else None
     self._content = None
コード例 #16
0
class AppBuffer(BrowserBuffer):
    def __init__(self, buffer_id, url, config_dir, arguments, emacs_var_dict,
                 module_path):
        BrowserBuffer.__init__(self, buffer_id, url, config_dir, arguments,
                               emacs_var_dict, module_path, False)

        self.url = url
        self.preview_file = tempfile.mkstemp(prefix='eaf-',
                                             suffix='.html',
                                             text=True)[1]
        self.render_js = os.path.join(os.path.dirname(__file__), "render.js")
        self.server_port = get_free_port()
        self.dark_mode = "false"
        if emacs_var_dict["eaf-markdown-dark-mode"] == "true" or \
           (emacs_var_dict["eaf-markdown-dark-mode"] == "follow" and emacs_var_dict["eaf-emacs-theme-mode"] == "dark"):
            self.dark_mode = "true"

        self.draw_progressbar = True

        self.run_render_server()
        self.render()

        self.file_watcher = QFileSystemWatcher()
        self.file_watcher.fileChanged.connect(self.on_file_changed)
        self.file_watcher.addPath(url)

    def run_render_server(self):
        args = ["node", self.render_js, str(self.server_port)]
        subprocess.Popen(args,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT,
                         shell=False)

    def on_file_changed(self, *args):
        self.render()

    def retry_if_connection_refused(ex):
        return isinstance(ex, URLError) and isinstance(ex.reason,
                                                       ConnectionRefusedError)

    @retry(wait_fixed=500,
           stop_max_attempt_number=10,
           retry_on_exception=retry_if_connection_refused)
    def render(self):
        params = {
            "input_file": self.url,
            "output_file": self.preview_file,
            "dark_mode": self.dark_mode
        }
        url = 'http://localhost:{}?{}'.format(self.server_port,
                                              urlencode(params))
        with urlopen(url) as f:
            resp = f.read().decode("utf-8")
            if resp == "ok":
                self.buffer_widget.load(QUrl.fromLocalFile(self.preview_file))
                if platform.system() == "Windows":
                    eval_in_emacs('eaf-activate-emacs-window', [])
            else:
                message_to_emacs("preview failed: {}".format(resp))
コード例 #17
0
    def __init__(self, parent=None):

        super(Editor, self).__init__(parent)
        ComponentMixin.__init__(self)

        self._filename = ''

        self.setup_editor(linenumbers=True,
                          markers=True,
                          edge_line=False,
                          tab_mode=False,
                          show_blanks=True,
                          language='Python')

        self._actions =  \
                {'File' : [QAction(icon('new'),
                                  'New',
                                  self,
                                  shortcut='ctrl+N',
                                  triggered=self.new),
                          QAction(icon('open'),
                                  'Open',
                                  self,
                                  shortcut='ctrl+O',
                                  triggered=self.open),
                          QAction(icon('save'),
                                  'Save',
                                  self,
                                  shortcut='ctrl+S',
                                  triggered=self.save),
                          QAction(icon('save_as'),
                                  'Save as',
                                  self,
                                  shortcut='ctrl+shift+S',
                                  triggered=self.save_as),
                          QAction(icon('autoreload'),
                                  'Automatic reload and preview',
                                  self,triggered=self.autoreload,
                                  checkable=True,
                                  checked=False,
                                  objectName='autoreload'),
                          ]}

        for a in self._actions.values():
            self.addActions(a)

        self._fixContextMenu()
        self.updatePreferences()

        # autoreload support
        self._file_watcher = QFileSystemWatcher(self)
        self._watched_file = None
        # we wait for 50ms after a file change for the file to be written completely
        self._file_watch_timer = QTimer(self)
        self._file_watch_timer.setInterval(50)
        self._file_watch_timer.setSingleShot(True)
        self._file_watcher.fileChanged.connect(
            lambda val: self._file_watch_timer.start())
        self._file_watch_timer.timeout.connect(self._file_changed)
コード例 #18
0
 def __init__(self, directory, parent=None):
     super().__init__(parent)
     self._pidfile = directory / 'editor_pid'
     self._watcher = QFileSystemWatcher(self)
     self._watcher.addPath(str(directory))
     self._watcher.directoryChanged.connect(self._check_update)
     self.has_pidfile = False
     self._check_update()
コード例 #19
0
ファイル: styles.py プロジェクト: EternityForest/mdNotes
    def __init__(self, csspath):

        self.path = csspath
        #Watch the file so we can auto reload
        self.csswatcher = QFileSystemWatcher()
        self.csswatcher.addPath(csspath)
        self.csswatcher.fileChanged.connect(self.rlcss)
        print("Watching " + self.path)
コード例 #20
0
    def __init__(self, parent=None):
        super().__init__(parent)  #调用父类构造函数,创建窗体
        self.ui = Ui_MainWindow()  #创建UI对象
        self.ui.setupUi(self)  #构造UI界面

        self.ui.toolBox.setCurrentIndex(0)
        self.fileWatcher = QFileSystemWatcher()
        self.fileWatcher.directoryChanged.connect(self.do_directoryChanged)
        self.fileWatcher.fileChanged.connect(self.do_fileChanged)
コード例 #21
0
 def start_watching(self):
     """Create a file system watcher and connect its fileChanged
     SIGNAL to our _file_changed SLOT"""
     if not self.__watcher:
         self.__watcher = QFileSystemWatcher(self)
         self.__watcher.fileChanged['const QString&'].connect(self._file_changed)
     if self._file_path is not None:
         self.__mtime = os.path.getmtime(self._file_path)
         self.__watcher.addPath(self._file_path)
コード例 #22
0
ファイル: vm_main.py プロジェクト: gabrielvf1/Z01---Grupo-H
 def setup_editor(self):
     self.rom_stream = tempfile.SpooledTemporaryFile(
         max_size=self.TEMP_MAX_RAM_USE, mode="w+")
     self.rom_path = None
     self.lst_parser = None
     self.rom_watcher = QFileSystemWatcher()
     self.rom_watcher.fileChanged.connect(self.reload_rom)
     self.spinBox.setValue(500)
     self.on_new()
コード例 #23
0
 def __init__(self,
              fname=None,
              data=None,
              comment='#',
              skiprows=0,
              delimiter=' ',
              expressions={},
              autoupdate=False,
              parent=None,
              matplotlib=False,
              plotIndex=None,
              colors=None):
     QDialog.__init__(self, parent=parent)
     loadUi('UI_Forms/Data_Dialog.ui', self)
     self.colcycler = cycle(['r', 'g', 'b', 'c', 'm', 'y', 'w'])
     self.plotWidget = PlotWidget(parent=self, matplotlib=matplotlib)
     self.plotTab = self.tabWidget.addTab(self.plotWidget, 'Plots')
     self.tabWidget.setCurrentIndex(0)
     self.show()
     self.fileWatcher = QFileSystemWatcher()
     self.fileWatcher.fileChanged.connect(self.fileUpdated)
     self.cwd = None
     self.plotNum = 0
     self.xlabel = []
     self.ylabel = []
     self.oldPlotIndex = {}
     self.oldColors = {}
     self.dataAltered = False
     self.expressions = expressions
     if data is not None:
         self.data = data
         self.autoUpdateCheckBox.setEnabled(False)
     elif fname is not None:
         self.data = self.readData(fname,
                                   comment=comment,
                                   skiprows=skiprows,
                                   delimiter=delimiter)
     else:
         self.data = None
         self.autoUpdateCheckBox.setEnabled(False)
         self.saveDataPushButton.setEnabled(False)
         self.addRowPushButton.setEnabled(False)
         self.removeRowsPushButton.setEnabled(False)
         self.removeColumnPushButton.setEnabled(False)
     if self.data is not None:
         self.setMeta2Table()
         self.setData2Table()
         if plotIndex is None:
             self.addPlots(color=None)
         else:
             self.addMultiPlots(plotIndex=plotIndex, colors=colors)
     self.init_signals()
     self.okPushButton.setAutoDefault(False)
     self.make_default()
     self.setWindowTitle('Data Dialog')
     self.acceptData = True
コード例 #24
0
class MainWatcher:
    def __init__(self):
        self.watcher = QFileSystemWatcher()
        self.folders = []
        self.files = []

    def connect(self):
        self.watcher.directoryChanged.connect(self.directory_changed)

    def add_paths(self, list_of_paths):
        self.watcher.addPaths(list_of_paths)

    def directory_changed(self, path):
        for f in listdir(path):
            complete_path = join(path, f)
            sub_folder = self.map_path_to_folder_id(path)
            if not exists(complete_path):
                continue
            if complete_path in self.folders or complete_path in self.files:
                continue
            if isfile(complete_path):
                fw = FileWatcher()
                fw.subfolder = sub_folder
                fw.base_path = complete_path
                fw.connect()
                fw.finished.connect(self.copied_file)
                self.files.append(fw)
            else:
                fw = SubFolderWatcher()
                fw.base_path = complete_path
                fw.subfolder = sub_folder
                fw.connect()
                fw.finished.connect(self.copied_folder)
                self.folders.append(fw)

    def copied_file(self, path):
        try:
            i = self.files.index(path)
        except IndexError:
            pass
        else:
            del self.files[i]

    def copied_folder(self, path):
        try:
            i = self.folders.index(path)
        except IndexError:
            pass
        else:
            del self.folders[i]

    @staticmethod
    def map_path_to_folder_id(path):
        normalized_path = normpath(path)
        ending = split(normalized_path)[-1]
        return ending
コード例 #25
0
ファイル: filewatcher.py プロジェクト: westvind/vintel
 def __init__(self, path, max_age):
     QThread.__init__(self)
     self.path = path
     self.max_age = max_age
     self.files = {}
     self.file_reg = re.compile('(.+)_\d{8}_\d{6}' + re.escape(os.path.extsep) + 'txt$', re.IGNORECASE)
     self.qtfw = QFileSystemWatcher()
     self.qtfw.directoryChanged.connect(self.directory_changed)
     self.qtfw.addPath(path)
     self.update_watched_files(path)
コード例 #26
0
ファイル: BLENDWriter.py プロジェクト: awiegel/CuraBlender
    def __init__(self):
        """The constructor, which calls the super-class-contructor (MeshWriter).

        Adds a filewatcher to replace the saved file from the writer job by our own generated file.
        """

        super().__init__(add_to_recent_files = False)

        self._write_watcher = QFileSystemWatcher()
        self._write_watcher.fileChanged.connect(self._writeChanged)
コード例 #27
0
    def start(self):
        # if the file does not exist
        # create it then watch it
        if not os.path.exists(self.fnam):
            with open(self.fnam, 'w') as f:
                pass

        # watch file
        self.w = QFileSystemWatcher([self.fnam])
        self.w.fileChanged.connect(self.fileChanged)
コード例 #28
0
class FileWatcher(object):
    def __init__(self, files=None):
        self._watcher = QFileSystemWatcher()
        self._files = list()  # List of file(s) to watch
        self.isWatching = False
        if files is not None:
            self.addFile(files)

    def test(self):
        file = ['/Users/bitzer/hudat.spec']

        self.addFile(file)

    def addFile(self, files):
        # Add a file(s) to the watch list
        # Files needs to be a list, even if a single file

        # Do it while actively watching?

        for _f in files:
            print(_f)
            self._files.append(_f)

    def removeFile(self):
        # Remove a file
        pass

    def replaceFile(self, file):
        # In the (usual) case of a watching a single file, replace it
        if len(self._files) != 1:
            print('Only allowed if one file is currently watched')

        self._files[0] = file

    def startWatch(self):
        # Start watching the files

        self._watcher.addPaths(self._files)

        self._watcher.fileChanged.connect(self.onChange)
        self.isWatching = True

    def stopWatch(self):
        # Stop Watching the folder

        self._watcher.removePaths(self._files)

        self._watcher.fileChanged.disconnect(self.onChange)

        self.isWatching = False

    def onChange(self, file):
        # When a file changes, do something
        # Which file changed?
        print('changed ' + file)
コード例 #29
0
class AutocutView(QMainWindow):
    """Class that displays the view for the autocut feature."""
    def __init__(self):
        """Loads the UI-file and sets up the GUI."""
        super(AutocutView, self).__init__()
        uic.loadUi(Resources.files.autocut_view, self)

        self.setWindowFlags(Qt.WindowCloseButtonHint
                            | Qt.WindowMinimizeButtonHint)
        self.setFixedSize(self.size())

        self.init_stylesheet()

        "QSS HOT RELOAD"
        self.__qss_watcher = QFileSystemWatcher()
        self.__qss_watcher.addPath(Resources.files.qss_dark)
        self.__qss_watcher.fileChanged.connect(self.update_qss)

        # centering the window
        rectangle = self.frameGeometry()
        center_point = QDesktopWidget().availableGeometry().center()
        rectangle.moveCenter(center_point)
        self.move(rectangle.topLeft())

        cross_path = Resources.images.cross
        tick_path = Resources.images.tick
        self.cross = QPixmap(cross_path).scaledToHeight(50, mode=1)
        self.tick = QPixmap(tick_path).scaledToHeight(50, mode=1)

        self.video_image_label.setPixmap(self.cross)
        self.pdf_image_label.setPixmap(self.cross)

    def init_stylesheet(self):
        current_stylesheet = Settings.get_instance().get_settings(
        ).design.color_theme.current
        if current_stylesheet == 0:
            self.setStyleSheet(open(Resources.files.qss_dark, "r").read())
        elif current_stylesheet == 1:
            self.setStyleSheet(open(Resources.files.qss_light, "r").read())

    def show(self):
        """Starts the window normal (not maximized)."""
        self.showNormal()

    def change_icon(self, label):
        """Changes the icon of a label to a tick icon."""
        label.setPixmap(self.tick)

    def update_qss(self):
        """ Updates the View when stylesheet changed, can be removed in production"""
        self.setStyleSheet(open(Resources.files.qss_dark, "r").read())
        self.__qss_watcher = QFileSystemWatcher()
        self.__qss_watcher.addPath(Resources.files.qss_dark)
        self.__qss_watcher.fileChanged.connect(self.update_qss)
コード例 #30
0
 def __init__(self, parent):
     """
     Constructor
     
     @param parent reference to parent object (Project.Project)
     """
     super(ProjectBrowserModel, self).__init__(parent, nopopulate=True)
     
     rootData = self.tr("Name")
     self.rootItem = BrowserItem(None, rootData)
     self.rootItem.itemData.append(self.tr("VCS Status"))
     
     self.progDir = None
     self.project = parent
     
     self.watchedItems = {}
     self.watcher = QFileSystemWatcher(self)
     self.watcher.directoryChanged.connect(self.directoryChanged)
     
     self.inRefresh = False
     
     self.projectBrowserTypes = {
         "SOURCES": ProjectBrowserSourceType,
         "FORMS": ProjectBrowserFormType,
         "RESOURCES": ProjectBrowserResourceType,
         "INTERFACES": ProjectBrowserInterfaceType,
         "PROTOCOLS": ProjectBrowserProtocolsType,
         "TRANSLATIONS": ProjectBrowserTranslationType,
         "OTHERS": ProjectBrowserOthersType,
     }
     
     self.colorNames = {
         "A": "VcsAdded",
         "M": "VcsModified",
         "O": "VcsRemoved",
         "R": "VcsReplaced",
         "U": "VcsUpdate",
         "Z": "VcsConflict",
     }
     self.itemBackgroundColors = {
         " ": QColor(),
         "A": Preferences.getProjectBrowserColour(self.colorNames["A"]),
         "M": Preferences.getProjectBrowserColour(self.colorNames["M"]),
         "O": Preferences.getProjectBrowserColour(self.colorNames["O"]),
         "R": Preferences.getProjectBrowserColour(self.colorNames["R"]),
         "U": Preferences.getProjectBrowserColour(self.colorNames["U"]),
         "Z": Preferences.getProjectBrowserColour(self.colorNames["Z"]),
     }
     
     self.highLightColor = Preferences.getProjectBrowserColour(
         "Highlighted")
     # needed by preferencesChanged()
     
     self.vcsStatusReport = {}
コード例 #31
0
 def __init__(self):
     super(SubFolderWatcher, self).__init__()
     self.base_path = ''
     self.subfolder = ''
     self.files = {}
     self.finished_checking = False
     self.watcher = QFileSystemWatcher()
     self.timer = QTimer()
     self.check_threshold = 3
     self.check_number = 0
     self.sub_folder = ''
コード例 #32
0
 def setup_editor(self):
     self.rom_stream = tempfile.SpooledTemporaryFile(
         max_size=self.TEMP_MAX_RAM_USE, mode="w+")
     self.rom_path = None
     self.rom_type_sel = self.actionROMAssembly
     self.lst_parser = None
     self.rom_watcher = QFileSystemWatcher()
     self.rom_watcher.fileChanged.connect(self.reload_rom)
     self.editor_converting = False
     self.spinBox.setValue(100)
     self.on_new()
コード例 #33
0
    def __init__(self, parent = None):
        super().__init__(parent)

        self.mWatchCount = QMap()
        self.mWatcher = QFileSystemWatcher(self)
        self.mWatcher.fileChanged.connect(self.onFileChanged)
        self.mWatcher.directoryChanged.connect(self.onDirectoryChanged)
コード例 #34
0
ファイル: editor.py プロジェクト: The-Compiler/qutebrowser
 def __init__(self, parent=None, watch=False):
     super().__init__(parent)
     self._filename = None
     self._proc = None
     self._remove_file = None
     self._watcher = QFileSystemWatcher(parent=self) if watch else None
     self._content = None
コード例 #35
0
def test_killed_command(qtbot, tmpdir, py_proc, runner):
    data_file = tmpdir / "data"
    watcher = QFileSystemWatcher()
    watcher.addPath(str(tmpdir))

    cmd, args = py_proc(
        r"""
        import os
        import time
        import sys
        import json

        data = {
            'pid': os.getpid(),
            'text_file': os.environ['QUTE_TEXT'],
        }

        # We can't use QUTE_FIFO to transmit the PID because that wouldn't work
        # on Windows, where QUTE_FIFO is only monitored after the script has
        # exited.

        with open(sys.argv[1], 'w') as f:
            json.dump(data, f)

        time.sleep(30)
    """
    )
    args.append(str(data_file))

    with qtbot.waitSignal(watcher.directoryChanged, timeout=10000):
        runner.prepare_run(cmd, *args)
        runner.store_text("Hello World")
        runner.store_html("")

    # Make sure the PID was written to the file, not just the file created
    time.sleep(0.5)

    data = json.load(data_file)

    with qtbot.waitSignal(runner.finished):
        os.kill(int(data["pid"]), signal.SIGTERM)

    assert not os.path.exists(data["text_file"])
コード例 #36
0
    def __init__(self, path):
        QObject.__init__(self)
        self._contents = None
        self._watcher = QFileSystemWatcher()
        self._timer = None
        self._path = path

        self._lastEmittedModifiedStatus = None
        self._lastEmittedRemovedStatus = None

        self.setPath(path)
        self.enable()
コード例 #37
0
ファイル: ProjectBrowserModel.py プロジェクト: testmana2/test
 def __init__(self, parent):
     """
     Constructor
     
     @param parent reference to parent object (Project.Project)
     """
     super(ProjectBrowserModel, self).__init__(parent, nopopulate=True)
     
     rootData = self.tr("Name")
     self.rootItem = BrowserItem(None, rootData)
     self.rootItem.itemData.append(self.tr("VCS Status"))
     
     self.progDir = None
     self.project = parent
     
     self.watchedItems = {}
     self.watcher = QFileSystemWatcher(self)
     self.watcher.directoryChanged.connect(self.directoryChanged)
     
     self.inRefresh = False
     
     self.projectBrowserTypes = {
         "SOURCES": ProjectBrowserSourceType,
         "FORMS": ProjectBrowserFormType,
         "RESOURCES": ProjectBrowserResourceType,
         "INTERFACES": ProjectBrowserInterfaceType,
         "TRANSLATIONS": ProjectBrowserTranslationType,
         "OTHERS": ProjectBrowserOthersType,
     }
     
     self.colorNames = {
         "A": "VcsAdded",
         "M": "VcsModified",
         "O": "VcsRemoved",
         "R": "VcsReplaced",
         "U": "VcsUpdate",
         "Z": "VcsConflict",
     }
     self.itemBackgroundColors = {
         " ": QColor(),
         "A": Preferences.getProjectBrowserColour(self.colorNames["A"]),
         "M": Preferences.getProjectBrowserColour(self.colorNames["M"]),
         "O": Preferences.getProjectBrowserColour(self.colorNames["O"]),
         "R": Preferences.getProjectBrowserColour(self.colorNames["R"]),
         "U": Preferences.getProjectBrowserColour(self.colorNames["U"]),
         "Z": Preferences.getProjectBrowserColour(self.colorNames["Z"]),
     }
     
     self.highLightColor = \
         Preferences.getProjectBrowserColour("Highlighted")
     # needed by preferencesChanged()
     
     self.vcsStatusReport = {}
コード例 #38
0
ファイル: Scene.py プロジェクト: Ultimaker/Uranium
    def __init__(self) -> None:
        super().__init__()

        from UM.Scene.SceneNode import SceneNode
        self._root = SceneNode(name = "Root")
        self._root.setCalculateBoundingBox(False)
        self._connectSignalsRoot()
        self._active_camera = None  # type: Optional[Camera]
        self._ignore_scene_changes = False
        self._lock = threading.Lock()

        # Watching file for changes.
        self._file_watcher = QFileSystemWatcher()
        self._file_watcher.fileChanged.connect(self._onFileChanged)

        self._reload_message = None  # type: Optional[Message]
コード例 #39
0
class FileSystemWatcher(QObject):
    fileChanged = pyqtSignal(str)
    directoryChanged = pyqtSignal(str)

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

        self.mWatchCount = QMap()
        self.mWatcher = QFileSystemWatcher(self)
        self.mWatcher.fileChanged.connect(self.onFileChanged)
        self.mWatcher.directoryChanged.connect(self.onDirectoryChanged)

    def addPath(self, path):
        # Just silently ignore the request when the file doesn't exist
        if (not QFile.exists(path)):
            return
        entry = self.mWatchCount.find(path)
        if not entry:
            self.mWatcher.addPath(path)
            self.mWatchCount.insert(path, 1)
        else:
            # Path is already being watched, increment watch count
            self.mWatchCount[path] += 1

    def removePath(self, path):
        entry = self.mWatchCount.find(path)
        if (entry == self.mWatchCount.end()):
            if (QFile.exists(path)):
                qWarning("FileSystemWatcher: Path was never added:\n"+path)
            return

        # Decrement watch count
        entry -= 1
        self.mWatchCount[path] = entry
        if (entry == 0):
            self.mWatchCount.erase(path)
            self.mWatcher.removePath(path)

    def onFileChanged(self, path):
        # If the file was replaced, the watcher is automatically removed and needs
        # to be re-added to keep watching it for changes. This happens commonly
        # with applications that do atomic saving.
        if (not self.mWatcher.files().__contains__(path)):
            if (QFile.exists(path)):
                self.mWatcher.addPath(path)
        self.fileChanged.emit(path)

    def onDirectoryChanged(self, path):
        self.directoryChanged.emit(path)
コード例 #40
0
	def load(self, filename):
		# Load HDR image with FreeImage
		image = self.loadHDRImage(filename)
		if image is None:
			return False

		# Change window size
		self.sizeChanged.emit(image.width(), image.height())

		# Set the image to imageLabel
		self.setPixmap(QPixmap.fromImage(image))
		self.adjustSize()

		# Begin to watch modification
		self.watcher = QFileSystemWatcher()
		self.watcher.addPath(filename)
		self.watcher.fileChanged.connect(self.onFileChanged)

		return True
コード例 #41
0
ファイル: qnotify.py プロジェクト: Grumbel/dirtool
def main(argv):
    signal.signal(signal.SIGINT, signal.SIG_DFL)

    app = QCoreApplication([])
    watcher = QFileSystemWatcher()

    print("Watching /tmp/")

    watcher.addPath("/tmp/")
    watcher.addPath("/tmp/foo")

    # Files have to be watched specifically for this to trigger.
    # Deleting and recreating a file makes this no longer trigger.
    watcher.fileChanged.connect(file_changed)

    # This triggers on file creation and deletion
    watcher.directoryChanged.connect(directory_changed)

    print("files:", watcher.files())
    print("directories:", watcher.directories())

    sys.exit(app.exec())
コード例 #42
0
class ExecuteOptionsPlugin(QWidget, Plugin):
    """
    Handles setting the various arguments for running.
    Signals:
        executableChanged(str): Path of the new executable is emitted when changed
        executableInfoChanged(ExecutableInfo): Emitted when the executable path is changed
        workingDirChanged(str): Path of the current directory is changed
    """
    executableChanged = pyqtSignal(str)
    executableInfoChanged = pyqtSignal(ExecutableInfo)
    workingDirChanged = pyqtSignal(str)
    useTestObjectsChanged = pyqtSignal(bool)

    def __init__(self, **kwds):
        super(ExecuteOptionsPlugin, self).__init__(**kwds)

        self._preferences.addInt("execute/maxRecentWorkingDirs",
                "Max recent working directories",
                10,
                1,
                50,
                "Set the maximum number of recent working directories that have been used.",
                )
        self._preferences.addInt("execute/maxRecentExes",
                "Max recent executables",
                10,
                1,
                50,
                "Set the maximum number of recent executables that have been used.",
                )
        self._preferences.addInt("execute/maxRecentArgs",
                "Max recent command line arguments",
                10,
                1,
                50,
                "Set the maximum number of recent command line arguments that have been used.",
                )
        self._preferences.addBool("execute/allowTestObjects",
                "Allow using test objects",
                False,
                "Allow using test objects by default",
                )
        self._preferences.addBool("execute/mpiEnabled",
                "Enable MPI by default",
                False,
                "Set the MPI checkbox on by default",
                )
        self._preferences.addString("execute/mpiArgs",
                "Default mpi command",
                "mpiexec -n 2",
                "Set the default MPI command to run",
                )
        self._preferences.addBool("execute/threadsEnabled",
                "Enable threads by default",
                False,
                "Set the threads checkbox on by default",
                )
        self._preferences.addString("execute/threadsArgs",
                "Default threads arguments",
                "--n-threads=2",
                "Set the default threads arguments",
                )

        self.all_exe_layout = WidgetUtils.addLayout(grid=True)
        self.setLayout(self.all_exe_layout)

        self.working_label = WidgetUtils.addLabel(None, self, "Working Directory")
        self.all_exe_layout.addWidget(self.working_label, 0, 0)
        self.choose_working_button = WidgetUtils.addButton(None, self, "Choose", self._chooseWorkingDir)
        self.all_exe_layout.addWidget(self.choose_working_button, 0, 1)
        self.working_line = WidgetUtils.addLineEdit(None, self, None, readonly=True)
        self.working_line.setText(os.getcwd())
        self.all_exe_layout.addWidget(self.working_line, 0, 2)

        self.exe_label = WidgetUtils.addLabel(None, self, "Executable")
        self.all_exe_layout.addWidget(self.exe_label, 1, 0)
        self.choose_exe_button = WidgetUtils.addButton(None, self, "Choose", self._chooseExecutable)
        self.all_exe_layout.addWidget(self.choose_exe_button, 1, 1)
        self.exe_line = WidgetUtils.addLineEdit(None, self, None, readonly=True)
        self.all_exe_layout.addWidget(self.exe_line, 1, 2)

        self.args_label = WidgetUtils.addLabel(None, self, "Extra Arguments")
        self.all_exe_layout.addWidget(self.args_label, 2, 0)
        self.args_line = WidgetUtils.addLineEdit(None, self, None)
        self.all_exe_layout.addWidget(self.args_line, 2, 2)

        self.test_label = WidgetUtils.addLabel(None, self, "Allow test objects")
        self.all_exe_layout.addWidget(self.test_label, 3, 0)
        self.test_checkbox = WidgetUtils.addCheckbox(None, self, "", self._allowTestObjects)
        self.test_checkbox.setChecked(self._preferences.value("execute/allowTestObjects"))
        self.all_exe_layout.addWidget(self.test_checkbox, 3, 1, alignment=Qt.AlignHCenter)

        self.mpi_label = WidgetUtils.addLabel(None, self, "Use MPI")
        self.all_exe_layout.addWidget(self.mpi_label, 4, 0)
        self.mpi_checkbox = WidgetUtils.addCheckbox(None, self, "", None)
        self.mpi_checkbox.setChecked(self._preferences.value("execute/mpiEnabled"))
        self.all_exe_layout.addWidget(self.mpi_checkbox, 4, 1, alignment=Qt.AlignHCenter)
        self.mpi_line = WidgetUtils.addLineEdit(None, self, None)
        self.mpi_line.setText(self._preferences.value("execute/mpiArgs"))
        self.mpi_line.cursorPositionChanged.connect(self._mpiLineCursorChanged)
        self.all_exe_layout.addWidget(self.mpi_line, 4, 2)

        self.threads_label = WidgetUtils.addLabel(None, self, "Use Threads")
        self.all_exe_layout.addWidget(self.threads_label, 5, 0)
        self.threads_checkbox = WidgetUtils.addCheckbox(None, self, "", None)
        self.threads_checkbox.setChecked(self._preferences.value("execute/threadsEnabled"))
        self.all_exe_layout.addWidget(self.threads_checkbox, 5, 1, alignment=Qt.AlignHCenter)
        self.threads_line = WidgetUtils.addLineEdit(None, self, None)
        self.threads_line.setText(self._preferences.value("execute/threadsArgs"))
        self.threads_line.cursorPositionChanged.connect(self._threadsLineCursorChanged)
        self.all_exe_layout.addWidget(self.threads_line, 5, 2)

        self.csv_label = WidgetUtils.addLabel(None, self, "Postprocessor CSV Output")
        self.all_exe_layout.addWidget(self.csv_label, 6, 0)
        self.csv_checkbox = WidgetUtils.addCheckbox(None, self, "", None)
        self.all_exe_layout.addWidget(self.csv_checkbox, 6, 1, alignment=Qt.AlignHCenter)
        self.csv_checkbox.setCheckState(Qt.Checked)

        self.recover_label = WidgetUtils.addLabel(None, self, "Recover")
        self.all_exe_layout.addWidget(self.recover_label, 7, 0)
        self.recover_checkbox = WidgetUtils.addCheckbox(None, self, "", None)
        self.all_exe_layout.addWidget(self.recover_checkbox, 7, 1, alignment=Qt.AlignHCenter)

        self._recent_exe_menu = None
        self._recent_working_menu = None
        self._recent_args_menu = None
        self._exe_watcher = QFileSystemWatcher()
        self._exe_watcher.fileChanged.connect(self.setExecutablePath)

        self._loading_dialog = QMessageBox(parent=self)
        self._loading_dialog.setWindowTitle("Loading executable")
        self._loading_dialog.setStandardButtons(QMessageBox.NoButton) # get rid of the OK button
        self._loading_dialog.setWindowModality(Qt.ApplicationModal)
        self._loading_dialog.setIcon(QMessageBox.Information)
        self._loading_dialog.setText("Loading executable")

        self.setup()

    def setExecutablePath(self, app_path):
        """
        The user select a new executable path.
        Input:
            app_path: The path of the executable.
        """
        if not app_path:
            return

        self._loading_dialog.setInformativeText(app_path)
        self._loading_dialog.show()
        self._loading_dialog.raise_()
        QApplication.processEvents()

        app_info = ExecutableInfo()
        app_info.setPath(app_path, self.test_checkbox.isChecked())

        QApplication.processEvents()

        if app_info.valid():
            self.exe_line.setText(app_path)
            self.executableInfoChanged.emit(app_info)
            self.executableChanged.emit(app_path)
            files = self._exe_watcher.files()
            if files:
                self._exe_watcher.removePaths(files)
            self._exe_watcher.addPath(app_path)
        self._updateRecentExe(app_path, not app_info.valid())
        self._loading_dialog.hide()

    def _chooseExecutable(self):
        """
        Open a dialog to allow the user to choose an executable.
        """
        #FIXME: QFileDialog seems to be a bit broken. Using
        # .setFilter() to filter only executable files doesn't
        # seem to work. Setting a QSortFilterProxyModel doesn't
        # seem to work either.
        # So just use the static method.
        exe_name, other = QFileDialog.getOpenFileName(self, "Chooose executable")
        self.setExecutablePath(exe_name)

    def _allowTestObjects(self):
        """
        Reload the ExecutableInfo based on whether we are allowing test objects or not.
        """
        self.useTestObjectsChanged.emit(self.test_checkbox.isChecked())
        self.setExecutablePath(self.exe_line.text())

    def _workingDirChanged(self):
        """
        Slot called when working directory changed.
        """
        working = str(self.working_line.text())
        self.setWorkingDir(working)

    def _chooseWorkingDir(self):
        """
        Open dialog to choose a current working directory.
        """
        dirname = QFileDialog.getExistingDirectory(self, "Choose directory")
        self.setWorkingDir(dirname)

    def setWorkingDir(self, dir_name):
        """
        Sets the working directory.
        Input:
            dir_name: The path of the working directory.
        """
        if not dir_name:
            return
        old_dirname = str(self.working_line.text())
        try:
            os.chdir(dir_name)
            self.working_line.setText(dir_name)
            if old_dirname != dir_name:
                self.workingDirChanged.emit(dir_name)
            self._updateRecentWorkingDir(dir_name)
        except OSError:
            mooseutils.mooseError("Invalid directory %s" % dir_name, dialog=True)
            self._updateRecentWorkingDir(dir_name, True)

    def _setExecutableArgs(self, args):
        """
        Set the executable arguments.
        Input:
            args: str: A string of all the arguments.
        """
        self.args_line.setText(args)

    def buildCommand(self, input_file):
        cmd, args = self.buildCommandWithNoInputFile()
        args.append("-i")
        args.append(os.path.relpath(input_file))
        return cmd, args

    def buildCommandWithNoInputFile(self):
        """
        Builds the full command line with arguments.
        Return: <string of command to run>, <list of arguments>
        """
        cmd = ""
        args = []
        if self.mpi_checkbox.isChecked():
            mpi_args = shlex.split(str(self.mpi_line.text()))
            if mpi_args:
                cmd = mpi_args[0]
                args = mpi_args[1:]
                args.append(str(self.exe_line.text()))

        if not cmd:
            cmd = str(self.exe_line.text())

        args += shlex.split(str(self.args_line.text()))

        if self.recover_checkbox.isChecked():
            args.append("--recover")

        if self.csv_checkbox.isChecked():
            #args.append("--no-color")
            args.append("Outputs/csv=true")

        if self.threads_checkbox.isChecked():
            args += shlex.split(str(self.threads_line.text()))

        return cmd, args

    def _updateRecentExe(self, path, remove=False):
        """
        Updates the recently used menu with the current executable
        """
        if self._recent_exe_menu:
            abs_path = os.path.normcase(os.path.abspath(path))
            if remove:
                self._recent_exe_menu.removeEntry(abs_path)
            else:
                self._recent_exe_menu.update(abs_path)

    def _updateRecentWorkingDir(self, path, remove=False):
        """
        Updates the recently used menu with the current executable
        """
        full_path = os.path.abspath(path)
        if self._recent_working_menu:
            if remove:
                self._recent_working_menu.removeEntry(full_path)
            else:
                self._recent_working_menu.update(full_path)

    def onPreferencesSaved(self):
        self._recent_args_menu.updateRecentlyOpened()
        self._recent_working_menu.updateRecentlyOpened()
        self._recent_exe_menu.updateRecentlyOpened()

    def addToMenu(self, menu):
        """
        Adds menu entries specific to the Arguments to the menubar.
        """
        workingMenu = menu.addMenu("Recent &working dirs")
        self._recent_working_menu = RecentlyUsedMenu(workingMenu,
                "execute/recentWorkingDirs",
                "execute/maxRecentWorkingDirs",
                20,
                )
        self._recent_working_menu.selected.connect(self.setWorkingDir)
        self._workingDirChanged()

        exeMenu = menu.addMenu("Recent &executables")
        self._recent_exe_menu = RecentlyUsedMenu(exeMenu,
                "execute/recentExes",
                "execute/maxRecentExes",
                20,
                )
        self._recent_exe_menu.selected.connect(self.setExecutablePath)

        argsMenu = menu.addMenu("Recent &arguments")
        self._recent_args_menu = RecentlyUsedMenu(argsMenu,
                "execute/recentArgs",
                "execute/maxRecentArgs",
                20,
                )
        self._recent_args_menu.selected.connect(self._setExecutableArgs)

    def clearRecentlyUsed(self):
        if self._recent_args_menu:
            self._recent_args_menu.clearValues()
            self._recent_working_menu.clearValues()
            self._recent_exe_menu.clearValues()
            self._workingDirChanged()

    def _mpiLineCursorChanged(self, old, new):
        self.mpi_checkbox.setChecked(True)

    def _threadsLineCursorChanged(self, old, new):
        self.threads_checkbox.setChecked(True)
コード例 #43
0
ファイル: window.py プロジェクト: daffodil/retext
class ReTextWindow(QMainWindow):
	def __init__(self, parent=None):
		QMainWindow.__init__(self, parent)
		self.resize(950, 700)
		screenRect = QDesktopWidget().screenGeometry()
		if globalSettings.windowGeometry:
			self.restoreGeometry(globalSettings.windowGeometry)
		else:
			self.move((screenRect.width()-self.width())/2, (screenRect.height()-self.height())/2)
		if not screenRect.contains(self.geometry()):
			self.showMaximized()
		if globalSettings.iconTheme:
			QIcon.setThemeName(globalSettings.iconTheme)
		if QIcon.themeName() in ('hicolor', ''):
			if not QFile.exists(icon_path + 'document-new.png'):
				QIcon.setThemeName(get_icon_theme())
		if QFile.exists(icon_path+'retext.png'):
			self.setWindowIcon(QIcon(icon_path+'retext.png'))
		elif QFile.exists('/usr/share/pixmaps/retext.png'):
			self.setWindowIcon(QIcon('/usr/share/pixmaps/retext.png'))
		else:
			self.setWindowIcon(QIcon.fromTheme('retext',
				QIcon.fromTheme('accessories-text-editor')))
		self.tabWidget = QTabWidget(self)
		self.initTabWidget()
		self.setCentralWidget(self.tabWidget)
		self.tabWidget.currentChanged.connect(self.changeIndex)
		self.tabWidget.tabCloseRequested.connect(self.closeTab)
		toolBar = QToolBar(self.tr('File toolbar'), self)
		self.addToolBar(Qt.TopToolBarArea, toolBar)
		self.editBar = QToolBar(self.tr('Edit toolbar'), self)
		self.addToolBar(Qt.TopToolBarArea, self.editBar)
		self.searchBar = QToolBar(self.tr('Search toolbar'), self)
		self.addToolBar(Qt.BottomToolBarArea, self.searchBar)
		toolBar.setVisible(not globalSettings.hideToolBar)
		self.editBar.setVisible(not globalSettings.hideToolBar)
		self.actionNew = self.act(self.tr('New'), 'document-new',
			self.createNew, shct=QKeySequence.New)
		self.actionNew.setPriority(QAction.LowPriority)
		self.actionOpen = self.act(self.tr('Open'), 'document-open',
			self.openFile, shct=QKeySequence.Open)
		self.actionOpen.setPriority(QAction.LowPriority)
		self.actionSetEncoding = self.act(self.tr('Set encoding'),
			trig=self.showEncodingDialog)
		self.actionSetEncoding.setEnabled(False)
		self.actionReload = self.act(self.tr('Reload'), 'view-refresh',
			lambda: self.currentTab.readTextFromFile())
		self.actionReload.setEnabled(False)
		self.actionSave = self.act(self.tr('Save'), 'document-save',
			self.saveFile, shct=QKeySequence.Save)
		self.actionSave.setEnabled(False)
		self.actionSave.setPriority(QAction.LowPriority)
		self.actionSaveAs = self.act(self.tr('Save as'), 'document-save-as',
			self.saveFileAs, shct=QKeySequence.SaveAs)
		self.actionNextTab = self.act(self.tr('Next tab'), 'go-next',
			lambda: self.switchTab(1), shct=Qt.CTRL+Qt.Key_PageDown)
		self.actionPrevTab = self.act(self.tr('Previous tab'), 'go-previous',
			lambda: self.switchTab(-1), shct=Qt.CTRL+Qt.Key_PageUp)
		self.actionPrint = self.act(self.tr('Print'), 'document-print',
			self.printFile, shct=QKeySequence.Print)
		self.actionPrint.setPriority(QAction.LowPriority)
		self.actionPrintPreview = self.act(self.tr('Print preview'), 'document-print-preview',
			self.printPreview)
		self.actionViewHtml = self.act(self.tr('View HTML code'), 'text-html', self.viewHtml)
		self.actionChangeEditorFont = self.act(self.tr('Change editor font'),
			trig=self.changeEditorFont)
		self.actionChangePreviewFont = self.act(self.tr('Change preview font'),
			trig=self.changePreviewFont)
		self.actionSearch = self.act(self.tr('Find text'), 'edit-find', shct=QKeySequence.Find)
		self.actionSearch.setCheckable(True)
		self.actionSearch.triggered[bool].connect(self.searchBar.setVisible)
		self.searchBar.visibilityChanged.connect(self.searchBarVisibilityChanged)
		self.actionPreview = self.act(self.tr('Preview'), shct=Qt.CTRL+Qt.Key_E,
			trigbool=self.preview)
		if QIcon.hasThemeIcon('document-preview'):
			self.actionPreview.setIcon(QIcon.fromTheme('document-preview'))
		elif QIcon.hasThemeIcon('preview-file'):
			self.actionPreview.setIcon(QIcon.fromTheme('preview-file'))
		elif QIcon.hasThemeIcon('x-office-document'):
			self.actionPreview.setIcon(QIcon.fromTheme('x-office-document'))
		else:
			self.actionPreview.setIcon(QIcon(icon_path+'document-preview.png'))
		self.actionLivePreview = self.act(self.tr('Live preview'), shct=Qt.CTRL+Qt.Key_L,
		trigbool=self.enableLivePreview)
		menuPreview = QMenu()
		menuPreview.addAction(self.actionLivePreview)
		self.actionPreview.setMenu(menuPreview)
		self.actionTableMode = self.act(self.tr('Table mode'), shct=Qt.CTRL+Qt.Key_T,
			trigbool=lambda x: self.currentTab.editBox.enableTableMode(x))
		if ReTextFakeVimHandler:
			self.actionFakeVimMode = self.act(self.tr('FakeVim mode'),
				shct=Qt.CTRL+Qt.ALT+Qt.Key_V, trigbool=self.enableFakeVimMode)
			if globalSettings.useFakeVim:
				self.actionFakeVimMode.setChecked(True)
				self.enableFakeVimMode(True)
		self.actionFullScreen = self.act(self.tr('Fullscreen mode'), 'view-fullscreen',
			shct=Qt.Key_F11, trigbool=self.enableFullScreen)
		self.actionFullScreen.setPriority(QAction.LowPriority)
		self.actionConfig = self.act(self.tr('Preferences'), icon='preferences-system',
			trig=self.openConfigDialog)
		self.actionConfig.setMenuRole(QAction.PreferencesRole)
		self.actionSaveHtml = self.act('HTML', 'text-html', self.saveFileHtml)
		self.actionPdf = self.act('PDF', 'application-pdf', self.savePdf)
		self.actionOdf = self.act('ODT', 'x-office-document', self.saveOdf)
		self.getExportExtensionsList()
		self.actionQuit = self.act(self.tr('Quit'), 'application-exit', shct=QKeySequence.Quit)
		self.actionQuit.setMenuRole(QAction.QuitRole)
		self.actionQuit.triggered.connect(self.close)
		self.actionUndo = self.act(self.tr('Undo'), 'edit-undo',
			lambda: self.currentTab.editBox.undo(), shct=QKeySequence.Undo)
		self.actionRedo = self.act(self.tr('Redo'), 'edit-redo',
			lambda: self.currentTab.editBox.redo(), shct=QKeySequence.Redo)
		self.actionCopy = self.act(self.tr('Copy'), 'edit-copy',
			lambda: self.currentTab.editBox.copy(), shct=QKeySequence.Copy)
		self.actionCut = self.act(self.tr('Cut'), 'edit-cut',
			lambda: self.currentTab.editBox.cut(), shct=QKeySequence.Cut)
		self.actionPaste = self.act(self.tr('Paste'), 'edit-paste',
			lambda: self.currentTab.editBox.paste(), shct=QKeySequence.Paste)
		self.actionUndo.setEnabled(False)
		self.actionRedo.setEnabled(False)
		self.actionCopy.setEnabled(False)
		self.actionCut.setEnabled(False)
		qApp = QApplication.instance()
		qApp.clipboard().dataChanged.connect(self.clipboardDataChanged)
		self.clipboardDataChanged()
		if enchant_available:
			self.actionEnableSC = self.act(self.tr('Enable'), trigbool=self.enableSpellCheck)
			self.actionSetLocale = self.act(self.tr('Set locale'), trig=self.changeLocale)
		self.actionWebKit = self.act(self.tr('Use WebKit renderer'), trigbool=self.enableWebKit)
		self.actionWebKit.setChecked(globalSettings.useWebKit)
		self.actionShow = self.act(self.tr('Show directory'), 'system-file-manager', self.showInDir)
		self.actionFind = self.act(self.tr('Next'), 'go-next', self.find,
			shct=QKeySequence.FindNext)
		self.actionFindPrev = self.act(self.tr('Previous'), 'go-previous',
			lambda: self.find(back=True), shct=QKeySequence.FindPrevious)
		self.actionCloseSearch = self.act(self.tr('Close'), 'window-close',
			lambda: self.searchBar.setVisible(False))
		self.actionCloseSearch.setPriority(QAction.LowPriority)
		self.actionHelp = self.act(self.tr('Get help online'), 'help-contents', self.openHelp)
		self.aboutWindowTitle = self.tr('About ReText')
		self.actionAbout = self.act(self.aboutWindowTitle, 'help-about', self.aboutDialog)
		self.actionAbout.setMenuRole(QAction.AboutRole)
		self.actionAboutQt = self.act(self.tr('About Qt'))
		self.actionAboutQt.setMenuRole(QAction.AboutQtRole)
		self.actionAboutQt.triggered.connect(qApp.aboutQt)
		availableMarkups = markups.get_available_markups()
		if not availableMarkups:
			print('Warning: no markups are available!')
		self.defaultMarkup = availableMarkups[0] if availableMarkups else None
		if globalSettings.defaultMarkup:
			mc = markups.find_markup_class_by_name(globalSettings.defaultMarkup)
			if mc and mc.available():
				self.defaultMarkup = mc
		if len(availableMarkups) > 1:
			self.chooseGroup = QActionGroup(self)
			markupActions = []
			for markup in availableMarkups:
				markupAction = self.act(markup.name, trigbool=self.markupFunction(markup))
				if markup == self.defaultMarkup:
					markupAction.setChecked(True)
				self.chooseGroup.addAction(markupAction)
				markupActions.append(markupAction)
		self.actionBold = self.act(self.tr('Bold'), shct=QKeySequence.Bold,
			trig=lambda: self.insertFormatting('bold'))
		self.actionItalic = self.act(self.tr('Italic'), shct=QKeySequence.Italic,
			trig=lambda: self.insertFormatting('italic'))
		self.actionUnderline = self.act(self.tr('Underline'), shct=QKeySequence.Underline,
			trig=lambda: self.insertFormatting('underline'))
		self.usefulTags = ('header', 'italic', 'bold', 'underline', 'numbering',
			'bullets', 'image', 'link', 'inline code', 'code block', 'blockquote')
		self.usefulChars = ('deg', 'divide', 'dollar', 'hellip', 'laquo', 'larr',
			'lsquo', 'mdash', 'middot', 'minus', 'nbsp', 'ndash', 'raquo',
			'rarr', 'rsquo', 'times')
		self.formattingBox = QComboBox(self.editBar)
		self.formattingBox.addItem(self.tr('Formatting'))
		self.formattingBox.addItems(self.usefulTags)
		self.formattingBox.activated[str].connect(self.insertFormatting)
		self.symbolBox = QComboBox(self.editBar)
		self.symbolBox.addItem(self.tr('Symbols'))
		self.symbolBox.addItems(self.usefulChars)
		self.symbolBox.activated.connect(self.insertSymbol)
		self.updateStyleSheet()
		menubar = self.menuBar()
		menuFile = menubar.addMenu(self.tr('File'))
		menuEdit = menubar.addMenu(self.tr('Edit'))
		menuHelp = menubar.addMenu(self.tr('Help'))
		menuFile.addAction(self.actionNew)
		menuFile.addAction(self.actionOpen)
		self.menuRecentFiles = menuFile.addMenu(self.tr('Open recent'))
		self.menuRecentFiles.aboutToShow.connect(self.updateRecentFiles)
		menuFile.addAction(self.actionShow)
		menuFile.addAction(self.actionSetEncoding)
		menuFile.addAction(self.actionReload)
		menuFile.addSeparator()
		menuFile.addAction(self.actionSave)
		menuFile.addAction(self.actionSaveAs)
		menuFile.addSeparator()
		menuFile.addAction(self.actionNextTab)
		menuFile.addAction(self.actionPrevTab)
		menuFile.addSeparator()
		menuExport = menuFile.addMenu(self.tr('Export'))
		menuExport.addAction(self.actionSaveHtml)
		menuExport.addAction(self.actionOdf)
		menuExport.addAction(self.actionPdf)
		if self.extensionActions:
			menuExport.addSeparator()
			for action, mimetype in self.extensionActions:
				menuExport.addAction(action)
			menuExport.aboutToShow.connect(self.updateExtensionsVisibility)
		menuFile.addAction(self.actionPrint)
		menuFile.addAction(self.actionPrintPreview)
		menuFile.addSeparator()
		menuFile.addAction(self.actionQuit)
		menuEdit.addAction(self.actionUndo)
		menuEdit.addAction(self.actionRedo)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionCut)
		menuEdit.addAction(self.actionCopy)
		menuEdit.addAction(self.actionPaste)
		menuEdit.addSeparator()
		if enchant_available:
			menuSC = menuEdit.addMenu(self.tr('Spell check'))
			menuSC.addAction(self.actionEnableSC)
			menuSC.addAction(self.actionSetLocale)
		menuEdit.addAction(self.actionSearch)
		menuEdit.addAction(self.actionChangeEditorFont)
		menuEdit.addAction(self.actionChangePreviewFont)
		menuEdit.addSeparator()
		if len(availableMarkups) > 1:
			self.menuMode = menuEdit.addMenu(self.tr('Default markup'))
			for markupAction in markupActions:
				self.menuMode.addAction(markupAction)
		menuFormat = menuEdit.addMenu(self.tr('Formatting'))
		menuFormat.addAction(self.actionBold)
		menuFormat.addAction(self.actionItalic)
		menuFormat.addAction(self.actionUnderline)
		menuEdit.addAction(self.actionWebKit)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionViewHtml)
		menuEdit.addAction(self.actionPreview)
		menuEdit.addAction(self.actionTableMode)
		if ReTextFakeVimHandler:
			menuEdit.addAction(self.actionFakeVimMode)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionFullScreen)
		menuEdit.addAction(self.actionConfig)
		menuHelp.addAction(self.actionHelp)
		menuHelp.addSeparator()
		menuHelp.addAction(self.actionAbout)
		menuHelp.addAction(self.actionAboutQt)
		toolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		toolBar.addAction(self.actionNew)
		toolBar.addSeparator()
		toolBar.addAction(self.actionOpen)
		toolBar.addAction(self.actionSave)
		toolBar.addAction(self.actionPrint)
		toolBar.addSeparator()
		toolBar.addAction(self.actionPreview)
		toolBar.addAction(self.actionFullScreen)
		self.editBar.addAction(self.actionUndo)
		self.editBar.addAction(self.actionRedo)
		self.editBar.addSeparator()
		self.editBar.addAction(self.actionCut)
		self.editBar.addAction(self.actionCopy)
		self.editBar.addAction(self.actionPaste)
		self.editBar.addSeparator()
		self.editBar.addWidget(self.formattingBox)
		self.editBar.addWidget(self.symbolBox)
		self.searchEdit = QLineEdit(self.searchBar)
		self.searchEdit.setPlaceholderText(self.tr('Search'))
		self.searchEdit.returnPressed.connect(self.find)
		self.csBox = QCheckBox(self.tr('Case sensitively'), self.searchBar)
		self.searchBar.addWidget(self.searchEdit)
		self.searchBar.addSeparator()
		self.searchBar.addWidget(self.csBox)
		self.searchBar.addAction(self.actionFindPrev)
		self.searchBar.addAction(self.actionFind)
		self.searchBar.addAction(self.actionCloseSearch)
		self.searchBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		self.searchBar.setVisible(False)
		self.autoSaveEnabled = globalSettings.autoSave
		if self.autoSaveEnabled:
			timer = QTimer(self)
			timer.start(60000)
			timer.timeout.connect(self.saveAll)
		self.ind = None
		if enchant_available:
			self.sl = globalSettings.spellCheckLocale
			if self.sl:
				try:
					enchant.Dict(self.sl)
				except Exception as e:
					print(e, file=sys.stderr)
					self.sl = None
			if globalSettings.spellCheck:
				self.actionEnableSC.setChecked(True)
		self.fileSystemWatcher = QFileSystemWatcher()
		self.fileSystemWatcher.fileChanged.connect(self.fileChanged)

	def iterateTabs(self):
		for i in range(self.tabWidget.count()):
			yield self.tabWidget.widget(i).tab

	def updateStyleSheet(self):
		if globalSettings.styleSheet:
			sheetfile = QFile(globalSettings.styleSheet)
			sheetfile.open(QIODevice.ReadOnly)
			self.ss = QTextStream(sheetfile).readAll()
			sheetfile.close()
		else:
			palette = QApplication.palette()
			self.ss = 'html { color: %s; }\n' % palette.color(QPalette.WindowText).name()
			self.ss += 'td, th { border: 1px solid #c3c3c3; padding: 0 3px 0 3px; }\n'
			self.ss += 'table { border-collapse: collapse; }\n'

	def initTabWidget(self):
		def dragEnterEvent(e):
			e.acceptProposedAction()
		def dropEvent(e):
			fn = bytes(e.mimeData().data('text/plain')).decode().rstrip()
			if fn.startswith('file:'):
				fn = QUrl(fn).toLocalFile()
			self.openFileWrapper(fn)
		self.tabWidget.setTabsClosable(True)
		self.tabWidget.setAcceptDrops(True)
		self.tabWidget.setMovable(True)
		self.tabWidget.dragEnterEvent = dragEnterEvent
		self.tabWidget.dropEvent = dropEvent

	def act(self, name, icon=None, trig=None, trigbool=None, shct=None):
		if not isinstance(shct, QKeySequence):
			shct = QKeySequence(shct)
		if icon:
			action = QAction(self.actIcon(icon), name, self)
		else:
			action = QAction(name, self)
		if trig:
			action.triggered.connect(trig)
		elif trigbool:
			action.setCheckable(True)
			action.triggered[bool].connect(trigbool)
		if shct:
			action.setShortcut(shct)
		return action

	def actIcon(self, name):
		return QIcon.fromTheme(name, QIcon(icon_path+name+'.png'))

	def printError(self):
		import traceback
		print('Exception occured while parsing document:', file=sys.stderr)
		traceback.print_exc()

	def createTab(self, fileName):
		self.currentTab = ReTextTab(self, fileName,
			previewState=int(globalSettings.livePreviewByDefault))
		self.tabWidget.addTab(self.currentTab.getSplitter(), self.tr("New document"))

	def closeTab(self, ind):
		if self.maybeSave(ind):
			if self.tabWidget.count() == 1:
				self.createTab("")
			currentWidget = self.tabWidget.widget(ind)
			if currentWidget.tab.fileName:
				self.fileSystemWatcher.removePath(currentWidget.tab.fileName)
			del currentWidget.tab
			self.tabWidget.removeTab(ind)

	def docTypeChanged(self):
		markupClass = self.currentTab.getMarkupClass()
		if type(self.currentTab.markup) != markupClass:
			self.currentTab.setMarkupClass(markupClass)
			self.currentTab.updatePreviewBox()
		dtMarkdown = (markupClass == markups.MarkdownMarkup)
		dtMkdOrReST = dtMarkdown or (markupClass == markups.ReStructuredTextMarkup)
		self.formattingBox.setEnabled(dtMarkdown)
		self.symbolBox.setEnabled(dtMarkdown)
		self.actionUnderline.setEnabled(dtMarkdown)
		self.actionBold.setEnabled(dtMkdOrReST)
		self.actionItalic.setEnabled(dtMkdOrReST)
		canReload = bool(self.currentTab.fileName) and not self.autoSaveActive()
		self.actionSetEncoding.setEnabled(canReload)
		self.actionReload.setEnabled(canReload)

	def changeIndex(self, ind):
		self.currentTab = self.tabWidget.currentWidget().tab
		editBox = self.currentTab.editBox
		previewState = self.currentTab.previewState
		self.actionUndo.setEnabled(editBox.document().isUndoAvailable())
		self.actionRedo.setEnabled(editBox.document().isRedoAvailable())
		self.actionCopy.setEnabled(editBox.textCursor().hasSelection())
		self.actionCut.setEnabled(editBox.textCursor().hasSelection())
		self.actionPreview.setChecked(previewState >= PreviewLive)
		self.actionLivePreview.setChecked(previewState == PreviewLive)
		self.actionTableMode.setChecked(editBox.tableModeEnabled)
		self.editBar.setEnabled(previewState < PreviewNormal)
		self.ind = ind
		if self.currentTab.fileName:
			self.setCurrentFile()
		else:
			self.setWindowTitle(self.tr('New document') + '[*]')
			self.docTypeChanged()
		self.modificationChanged(editBox.document().isModified())
		editBox.setFocus(Qt.OtherFocusReason)

	def changeEditorFont(self):
		font, ok = QFontDialog.getFont(globalSettings.editorFont, self)
		if ok:
			globalSettings.editorFont = font
			for tab in self.iterateTabs():
				tab.editBox.updateFont()

	def changePreviewFont(self):
		font, ok = QFontDialog.getFont(globalSettings.font, self)
		if ok:
			globalSettings.font = font
			for tab in self.iterateTabs():
				tab.updatePreviewBox()

	def preview(self, viewmode):
		self.currentTab.previewState = viewmode * 2
		self.actionLivePreview.setChecked(False)
		self.editBar.setDisabled(viewmode)
		self.currentTab.updateBoxesVisibility()
		if viewmode:
			self.currentTab.updatePreviewBox()

	def enableLivePreview(self, livemode):
		self.currentTab.previewState = int(livemode)
		self.actionPreview.setChecked(livemode)
		self.editBar.setEnabled(True)
		self.currentTab.updateBoxesVisibility()
		if livemode:
			self.currentTab.updatePreviewBox()

	def enableWebKit(self, enable):
		globalSettings.useWebKit = enable
		for i in range(self.tabWidget.count()):
			splitter = self.tabWidget.widget(i)
			tab = splitter.tab
			tab.previewBox.disconnectExternalSignals()
			tab.previewBox.setParent(None)
			tab.previewBox.deleteLater()
			tab.previewBox = tab.createPreviewBox(tab.editBox)
			tab.previewBox.setMinimumWidth(125)
			splitter.addWidget(tab.previewBox)
			splitter.setSizes((50, 50))
			tab.updatePreviewBox()
			tab.updateBoxesVisibility()

	def enableCopy(self, copymode):
		self.actionCopy.setEnabled(copymode)
		self.actionCut.setEnabled(copymode)

	def enableFullScreen(self, yes):
		if yes:
			self.showFullScreen()
		else:
			self.showNormal()

	def openConfigDialog(self):
		dlg = ConfigDialog(self)
		dlg.setWindowTitle(self.tr('Preferences'))
		dlg.show()

	def enableFakeVimMode(self, yes):
		globalSettings.useFakeVim = yes
		if yes:
			FakeVimMode.init(self)
			for tab in self.iterateTabs():
				tab.installFakeVimHandler()
		else:
			FakeVimMode.exit(self)

	def enableSpellCheck(self, yes):
		if yes:
			self.setAllDictionaries(enchant.Dict(self.sl or None))
		else:
			self.setAllDictionaries(None)
		globalSettings.spellCheck = yes

	def setAllDictionaries(self, dictionary):
		for tab in self.iterateTabs():
			hl = tab.highlighter
			hl.dictionary = dictionary
			hl.rehighlight()

	def changeLocale(self):
		if self.sl:
			localedlg = LocaleDialog(self, defaultText=self.sl)
		else:
			localedlg = LocaleDialog(self)
		if localedlg.exec() != QDialog.Accepted:
			return
		sl = localedlg.localeEdit.text()
		setdefault = localedlg.checkBox.isChecked()
		if sl:
			try:
				sl = str(sl)
				enchant.Dict(sl)
			except Exception as e:
				QMessageBox.warning(self, '', str(e))
			else:
				self.sl = sl
				self.enableSpellCheck(self.actionEnableSC.isChecked())
		else:
			self.sl = None
			self.enableSpellCheck(self.actionEnableSC.isChecked())
		if setdefault:
			globalSettings.spellCheckLocale = sl

	def searchBarVisibilityChanged(self, visible):
		self.actionSearch.setChecked(visible)
		if visible:
			self.searchEdit.setFocus(Qt.ShortcutFocusReason)

	def find(self, back=False):
		flags = QTextDocument.FindFlags()
		if back:
			flags |= QTextDocument.FindBackward
		if self.csBox.isChecked():
			flags |= QTextDocument.FindCaseSensitively
		text = self.searchEdit.text()
		editBox = self.currentTab.editBox
		cursor = editBox.textCursor()
		newCursor = editBox.document().find(text, cursor, flags)
		if not newCursor.isNull():
			editBox.setTextCursor(newCursor)
			return self.setSearchEditColor(True)
		cursor.movePosition(QTextCursor.End if back else QTextCursor.Start)
		newCursor = editBox.document().find(text, cursor, flags)
		if not newCursor.isNull():
			editBox.setTextCursor(newCursor)
			return self.setSearchEditColor(True)
		self.setSearchEditColor(False)

	def setSearchEditColor(self, found):
		palette = self.searchEdit.palette()
		palette.setColor(QPalette.Active, QPalette.Base,
		                 Qt.white if found else QColor(255, 102, 102))
		self.searchEdit.setPalette(palette)

	def showInDir(self):
		if self.currentTab.fileName:
			path = QFileInfo(self.currentTab.fileName).path()
			QDesktopServices.openUrl(QUrl.fromLocalFile(path))
		else:
			QMessageBox.warning(self, '', self.tr("Please, save the file somewhere."))

	def setCurrentFile(self):
		self.setWindowTitle("")
		self.tabWidget.setTabText(self.ind, self.currentTab.getDocumentTitle(baseName=True))
		self.tabWidget.setTabToolTip(self.ind, self.currentTab.fileName or '')
		self.setWindowFilePath(self.currentTab.fileName)
		files = readListFromSettings("recentFileList")
		while self.currentTab.fileName in files:
			files.remove(self.currentTab.fileName)
		files.insert(0, self.currentTab.fileName)
		if len(files) > 10:
			del files[10:]
		writeListToSettings("recentFileList", files)
		QDir.setCurrent(QFileInfo(self.currentTab.fileName).dir().path())
		self.docTypeChanged()

	def createNew(self, text=None):
		self.createTab("")
		self.ind = self.tabWidget.count()-1
		self.tabWidget.setCurrentIndex(self.ind)
		if text:
			self.currentTab.editBox.textCursor().insertText(text)

	def switchTab(self, shift=1):
		self.tabWidget.setCurrentIndex((self.ind + shift) % self.tabWidget.count())

	def updateRecentFiles(self):
		self.menuRecentFiles.clear()
		self.recentFilesActions = []
		filesOld = readListFromSettings("recentFileList")
		files = []
		for f in filesOld:
			if QFile.exists(f):
				files.append(f)
				self.recentFilesActions.append(self.act(f, trig=self.openFunction(f)))
		writeListToSettings("recentFileList", files)
		for action in self.recentFilesActions:
			self.menuRecentFiles.addAction(action)

	def markupFunction(self, markup):
		return lambda: self.setDefaultMarkup(markup)

	def openFunction(self, fileName):
		return lambda: self.openFileWrapper(fileName)

	def extensionFunction(self, data):
		return lambda: \
		self.runExtensionCommand(data['Exec'], data['FileFilter'], data['DefaultExtension'])

	def getExportExtensionsList(self):
		extensions = []
		for extsprefix in datadirs:
			extsdir = QDir(extsprefix+'/export-extensions/')
			if extsdir.exists():
				for fileInfo in extsdir.entryInfoList(['*.desktop', '*.ini'],
				QDir.Files | QDir.Readable):
					extensions.append(self.readExtension(fileInfo.filePath()))
		locale = QLocale.system().name()
		self.extensionActions = []
		for extension in extensions:
			try:
				if ('Name[%s]' % locale) in extension:
					name = extension['Name[%s]' % locale]
				elif ('Name[%s]' % locale.split('_')[0]) in extension:
					name = extension['Name[%s]' % locale.split('_')[0]]
				else:
					name = extension['Name']
				data = {}
				for prop in ('FileFilter', 'DefaultExtension', 'Exec'):
					if 'X-ReText-'+prop in extension:
						data[prop] = extension['X-ReText-'+prop]
					elif prop in extension:
						data[prop] = extension[prop]
					else:
						data[prop] = ''
				action = self.act(name, trig=self.extensionFunction(data))
				if 'Icon' in extension:
					action.setIcon(self.actIcon(extension['Icon']))
				mimetype = extension['MimeType'] if 'MimeType' in extension else None
			except KeyError:
				print('Failed to parse extension: Name is required', file=sys.stderr)
			else:
				self.extensionActions.append((action, mimetype))

	def updateExtensionsVisibility(self):
		markupClass = self.currentTab.getMarkupClass()
		for action in self.extensionActions:
			if markupClass is None:
				action[0].setEnabled(False)
				continue
			mimetype = action[1]
			if mimetype == None:
				enabled = True
			elif markupClass == markups.MarkdownMarkup:
				enabled = (mimetype in ("text/x-retext-markdown", "text/x-markdown"))
			elif markupClass == markups.ReStructuredTextMarkup:
				enabled = (mimetype in ("text/x-retext-rst", "text/x-rst"))
			else:
				enabled = False
			action[0].setEnabled(enabled)

	def readExtension(self, fileName):
		extFile = QFile(fileName)
		extFile.open(QIODevice.ReadOnly)
		extension = {}
		stream = QTextStream(extFile)
		while not stream.atEnd():
			line = stream.readLine()
			if '=' in line:
				index = line.index('=')
				extension[line[:index].rstrip()] = line[index+1:].lstrip()
		extFile.close()
		return extension

	def openFile(self):
		supportedExtensions = ['.txt']
		for markup in markups.get_all_markups():
			supportedExtensions += markup.file_extensions
		fileFilter = ' (' + str.join(' ', ['*'+ext for ext in supportedExtensions]) + ');;'
		fileNames = QFileDialog.getOpenFileNames(self,
			self.tr("Select one or several files to open"), "",
			self.tr("Supported files") + fileFilter + self.tr("All files (*)"))
		for fileName in fileNames[0]:
			self.openFileWrapper(fileName)

	def openFileWrapper(self, fileName):
		if not fileName:
			return
		fileName = QFileInfo(fileName).canonicalFilePath()
		exists = False
		for i, tab in enumerate(self.iterateTabs()):
			if tab.fileName == fileName:
				exists = True
				ex = i
		if exists:
			self.tabWidget.setCurrentIndex(ex)
		elif QFile.exists(fileName):
			noEmptyTab = (
				(self.ind is None) or
				self.currentTab.fileName or
				self.currentTab.editBox.toPlainText() or
				self.currentTab.editBox.document().isModified()
			)
			if noEmptyTab:
				self.createTab(fileName)
				self.ind = self.tabWidget.count()-1
				self.tabWidget.setCurrentIndex(self.ind)
			if fileName:
				self.fileSystemWatcher.addPath(fileName)
			self.currentTab.fileName = fileName
			self.currentTab.readTextFromFile()
			editBox = self.currentTab.editBox
			self.setCurrentFile()
			self.setWindowModified(editBox.document().isModified())

	def showEncodingDialog(self):
		if not self.maybeSave(self.ind):
			return
		encoding, ok = QInputDialog.getItem(self, '',
			self.tr('Select file encoding from the list:'),
			[bytes(b).decode() for b in QTextCodec.availableCodecs()],
			0, False)
		if ok:
			self.currentTab.readTextFromFile(encoding)

	def saveFile(self):
		self.saveFileMain(dlg=False)

	def saveFileAs(self):
		self.saveFileMain(dlg=True)

	def saveAll(self):
		for tab in self.iterateTabs():
			if tab.fileName and QFileInfo(tab.fileName).isWritable():
				tab.saveTextToFile()
				tab.editBox.document().setModified(False)

	def saveFileMain(self, dlg):
		if (not self.currentTab.fileName) or dlg:
			markupClass = self.currentTab.getMarkupClass()
			if (markupClass is None) or not hasattr(markupClass, 'default_extension'):
				defaultExt = self.tr("Plain text (*.txt)")
				ext = ".txt"
			else:
				defaultExt = self.tr('%s files',
					'Example of final string: Markdown files') \
					% markupClass.name + ' (' + str.join(' ',
					('*'+extension for extension in markupClass.file_extensions)) + ')'
				if markupClass == markups.MarkdownMarkup:
					ext = globalSettings.markdownDefaultFileExtension
				elif markupClass == markups.ReStructuredTextMarkup:
					ext = globalSettings.restDefaultFileExtension
				else:
					ext = markupClass.default_extension
			newFileName = QFileDialog.getSaveFileName(self,
				self.tr("Save file"), "", defaultExt)[0]
			if newFileName:
				if not QFileInfo(newFileName).suffix():
					newFileName += ext
				if self.currentTab.fileName:
					self.fileSystemWatcher.removePath(self.currentTab.fileName)
				self.currentTab.fileName = newFileName
				self.actionSetEncoding.setDisabled(self.autoSaveActive())
		if self.currentTab.fileName:
			if self.currentTab.saveTextToFile():
				self.setCurrentFile()
				self.currentTab.editBox.document().setModified(False)
				self.setWindowModified(False)
				return True
			else:
				QMessageBox.warning(self, '',
				self.tr("Cannot save to file because it is read-only!"))
		return False

	def saveHtml(self, fileName):
		if not QFileInfo(fileName).suffix():
			fileName += ".html"
		try:
			htmltext = self.currentTab.getHtml(includeStyleSheet=False,
				webenv=True)
		except Exception:
			return self.printError()
		htmlFile = QFile(fileName)
		htmlFile.open(QIODevice.WriteOnly)
		html = QTextStream(htmlFile)
		if globalSettings.defaultCodec:
			html.setCodec(globalSettings.defaultCodec)
		html << htmltext
		htmlFile.close()

	def textDocument(self):
		td = QTextDocument()
		td.setMetaInformation(QTextDocument.DocumentTitle,
		                      self.currentTab.getDocumentTitle())
		if self.ss:
			td.setDefaultStyleSheet(self.ss)
		td.setHtml(self.currentTab.getHtml())
		td.setDefaultFont(globalSettings.font)
		return td

	def saveOdf(self):
		try:
			document = self.textDocument()
		except Exception:
			return self.printError()
		fileName = QFileDialog.getSaveFileName(self,
			self.tr("Export document to ODT"), "",
			self.tr("OpenDocument text files (*.odt)"))[0]
		if not QFileInfo(fileName).suffix():
			fileName += ".odt"
		writer = QTextDocumentWriter(fileName)
		writer.setFormat(b"odf")
		writer.write(document)

	def saveFileHtml(self):
		fileName = QFileDialog.getSaveFileName(self,
			self.tr("Save file"), "",
			self.tr("HTML files (*.html *.htm)"))[0]
		if fileName:
			self.saveHtml(fileName)

	def getDocumentForPrint(self):
		if globalSettings.useWebKit:
			return self.currentTab.previewBox
		try:
			return self.textDocument()
		except Exception:
			self.printError()

	def standardPrinter(self):
		printer = QPrinter(QPrinter.HighResolution)
		printer.setDocName(self.currentTab.getDocumentTitle())
		printer.setCreator('ReText %s' % app_version)
		return printer

	def savePdf(self):
		self.currentTab.updatePreviewBox()
		fileName = QFileDialog.getSaveFileName(self,
			self.tr("Export document to PDF"),
			"", self.tr("PDF files (*.pdf)"))[0]
		if fileName:
			if not QFileInfo(fileName).suffix():
				fileName += ".pdf"
			printer = self.standardPrinter()
			printer.setOutputFormat(QPrinter.PdfFormat)
			printer.setOutputFileName(fileName)
			document = self.getDocumentForPrint()
			if document != None:
				document.print(printer)

	def printFile(self):
		self.currentTab.updatePreviewBox()
		printer = self.standardPrinter()
		dlg = QPrintDialog(printer, self)
		dlg.setWindowTitle(self.tr("Print document"))
		if (dlg.exec() == QDialog.Accepted):
			document = self.getDocumentForPrint()
			if document != None:
				document.print(printer)

	def printPreview(self):
		document = self.getDocumentForPrint()
		if document == None:
			return
		printer = self.standardPrinter()
		preview = QPrintPreviewDialog(printer, self)
		preview.paintRequested.connect(document.print)
		preview.exec()

	def runExtensionCommand(self, command, filefilter, defaultext):
		of = ('%of' in command)
		html = ('%html' in command)
		if of:
			if defaultext and not filefilter:
				filefilter = '*'+defaultext
			fileName = QFileDialog.getSaveFileName(self,
				self.tr('Export document'), '', filefilter)[0]
			if not fileName:
				return
			if defaultext and not QFileInfo(fileName).suffix():
				fileName += defaultext
		basename = '.%s.retext-temp' % self.currentTab.getDocumentTitle(baseName=True)
		if html:
			tmpname = basename+'.html'
			self.saveHtml(tmpname)
		else:
			tmpname = basename + self.currentTab.getMarkupClass().default_extension
			self.currentTab.saveTextToFile(fileName=tmpname, addToWatcher=False)
		command = command.replace('%of', '"out'+defaultext+'"')
		command = command.replace('%html' if html else '%if', '"'+tmpname+'"')
		try:
			Popen(str(command), shell=True).wait()
		except Exception as error:
			errorstr = str(error)
			QMessageBox.warning(self, '', self.tr('Failed to execute the command:')
			+ '\n' + errorstr)
		QFile(tmpname).remove()
		if of:
			QFile('out'+defaultext).rename(fileName)

	def autoSaveActive(self, ind=None):
		tab = self.currentTab if ind is None else self.tabWidget.widget(ind).tab
		return (self.autoSaveEnabled and tab.fileName and
			QFileInfo(tab.fileName).isWritable())

	def modificationChanged(self, changed):
		if self.autoSaveActive():
			changed = False
		self.actionSave.setEnabled(changed)
		self.setWindowModified(changed)

	def clipboardDataChanged(self):
		mimeData = QApplication.instance().clipboard().mimeData()
		if mimeData is not None:
			self.actionPaste.setEnabled(mimeData.hasText())

	def insertFormatting(self, formatting):
		cursor = self.currentTab.editBox.textCursor()
		text = cursor.selectedText()
		moveCursorTo = None

		def c(cursor):
			nonlocal moveCursorTo
			moveCursorTo = cursor.position()

		def ensurenl(cursor):
			if not cursor.atBlockStart():
				cursor.insertText('\n\n')

		toinsert = {
			'header': (ensurenl, '# ', text),
			'italic': ('*', text, c, '*'),
			'bold': ('**', text, c, '**'),
			'underline': ('<u>', text, c, '</u>'),
			'numbering': (ensurenl, ' 1. ', text),
			'bullets': (ensurenl, '  * ', text),
			'image': ('![', text or self.tr('Alt text'), c, '](', self.tr('URL'), ')'),
			'link': ('[', text or self.tr('Link text'), c, '](', self.tr('URL'), ')'),
			'inline code': ('`', text, c, '`'),
			'code block': (ensurenl, '    ', text),
			'blockquote': (ensurenl, '> ', text),
		}

		if formatting not in toinsert:
			return

		cursor.beginEditBlock()
		for token in toinsert[formatting]:
			if callable(token):
				token(cursor)
			else:
				cursor.insertText(token)
		cursor.endEditBlock()

		self.formattingBox.setCurrentIndex(0)
		# Bring back the focus on the editor
		self.currentTab.editBox.setFocus(Qt.OtherFocusReason)

		if moveCursorTo:
			cursor.setPosition(moveCursorTo)
			self.currentTab.editBox.setTextCursor(cursor)

	def insertSymbol(self, num):
		if num:
			self.currentTab.editBox.insertPlainText('&'+self.usefulChars[num-1]+';')
		self.symbolBox.setCurrentIndex(0)

	def fileChanged(self, fileName):
		ind = None
		for testind, tab in enumerate(self.iterateTabs()):
			if tab.fileName == fileName:
				ind = testind
		if ind is None:
			self.fileSystemWatcher.removePath(fileName)
		self.tabWidget.setCurrentIndex(ind)
		if not QFile.exists(fileName):
			self.currentTab.editBox.document().setModified(True)
			QMessageBox.warning(self, '', self.tr(
				'This file has been deleted by other application.\n'
				'Please make sure you save the file before exit.'))
		elif not self.currentTab.editBox.document().isModified():
			# File was not modified in ReText, reload silently
			self.currentTab.readTextFromFile()
			self.currentTab.updatePreviewBox()
		else:
			text = self.tr(
				'This document has been modified by other application.\n'
				'Do you want to reload the file (this will discard all '
				'your changes)?\n')
			if self.autoSaveEnabled:
				text += self.tr(
					'If you choose to not reload the file, auto save mode will '
					'be disabled for this session to prevent data loss.')
			messageBox = QMessageBox(QMessageBox.Warning, '', text)
			reloadButton = messageBox.addButton(self.tr('Reload'), QMessageBox.YesRole)
			messageBox.addButton(QMessageBox.Cancel)
			messageBox.exec()
			if messageBox.clickedButton() is reloadButton:
				self.currentTab.readTextFromFile()
				self.currentTab.updatePreviewBox()
			else:
				self.autoSaveEnabled = False
				self.currentTab.editBox.document().setModified(True)
		if fileName not in self.fileSystemWatcher.files():
			# https://github.com/retext-project/retext/issues/137
			self.fileSystemWatcher.addPath(fileName)

	def maybeSave(self, ind):
		tab = self.tabWidget.widget(ind).tab
		if self.autoSaveActive(ind):
			tab.saveTextToFile()
			return True
		if not tab.editBox.document().isModified():
			return True
		self.tabWidget.setCurrentIndex(ind)
		ret = QMessageBox.warning(self, '',
			self.tr("The document has been modified.\nDo you want to save your changes?"),
			QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)
		if ret == QMessageBox.Save:
			return self.saveFileMain(False)
		elif ret == QMessageBox.Cancel:
			return False
		return True

	def closeEvent(self, closeevent):
		for ind in range(self.tabWidget.count()):
			if not self.maybeSave(ind):
				return closeevent.ignore()
		if globalSettings.saveWindowGeometry and not self.isMaximized():
			globalSettings.windowGeometry = self.saveGeometry()
		closeevent.accept()

	def viewHtml(self):
		htmlDlg = HtmlDialog(self)
		try:
			htmltext = self.currentTab.getHtml(includeStyleSheet=False)
		except Exception:
			return self.printError()
		winTitle = self.currentTab.getDocumentTitle(baseName=True)
		htmlDlg.setWindowTitle(winTitle+" ("+self.tr("HTML code")+")")
		htmlDlg.textEdit.setPlainText(htmltext.rstrip())
		htmlDlg.hl.rehighlight()
		htmlDlg.show()
		htmlDlg.raise_()
		htmlDlg.activateWindow()

	def openHelp(self):
		QDesktopServices.openUrl(QUrl('https://github.com/retext-project/retext/wiki'))

	def aboutDialog(self):
		QMessageBox.about(self, self.aboutWindowTitle,
		'<p><b>' + (self.tr('ReText %s (using PyMarkups %s)') % (app_version, markups.__version__))
		+'</b></p>' + self.tr('Simple but powerful editor'
		' for Markdown and reStructuredText')
		+'</p><p>'+self.tr('Author: Dmitry Shachnev, 2011').replace('2011', '2011–2016')
		+'<br><a href="https://github.com/retext-project/retext">'+self.tr('Website')
		+'</a> | <a href="http://daringfireball.net/projects/markdown/syntax">'
		+self.tr('Markdown syntax')
		+'</a> | <a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html">'
		+self.tr('reStructuredText syntax')+'</a></p>')

	def setDefaultMarkup(self, markupClass):
		self.defaultMarkup = markupClass
		defaultName = markups.get_available_markups()[0].name
		writeToSettings('defaultMarkup', markupClass.name, defaultName)
		for tab in self.iterateTabs():
			if not tab.fileName:
				tab.setMarkupClass(markupClass)
				tab.updatePreviewBox()
		self.docTypeChanged()
コード例 #44
0
ファイル: mainwindow.py プロジェクト: gitter-badger/cetech
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)

        self.centralwidget.hide()

        self.parser = argparse.ArgumentParser("playground")
        self.parser.add_argument("-d", "--data-dir", type=str, help="data dir")
        self.parser.add_argument("-a", "--console-address", type=str, help="console address", default='localhost')
        self.parser.add_argument("-p", "--console-port", type=int, help="console port", default=2222)
        self.args = self.parser.parse_args()

        self.data_dir = self.args.data_dir
        self.console_port = self.args.console_port
        self.console_address = self.args.console_address

        self.project = CetechProject()

        self.api = QtConsoleAPI(self.console_address, self.console_port)

        self.setTabPosition(Qt.AllDockWidgetAreas, QTabWidget.North)

        self.script_editor_widget = ScriptEditor(project_manager=self.project, api=self.api)
        self.script_editor_dock_widget = QDockWidget(self)
        self.script_editor_dock_widget.setWindowTitle("Script editor")
        self.script_editor_dock_widget.hide()
        self.script_editor_dock_widget.setFeatures(QDockWidget.AllDockWidgetFeatures)
        self.script_editor_dock_widget.setWidget(self.script_editor_widget)
        self.addDockWidget(Qt.TopDockWidgetArea, self.script_editor_dock_widget)

        self.log_widget = LogWidget(self.api, self.script_editor_widget)
        self.log_dock_widget = QDockWidget(self)
        self.log_dock_widget.hide()
        self.log_dock_widget.setWindowTitle("Log")
        self.log_dock_widget.setWidget(self.log_widget)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.log_dock_widget)

        self.assetb_widget = AssetBrowser()
        self.assetb_dock_widget = QDockWidget(self)
        self.assetb_dock_widget.hide()
        self.assetb_dock_widget.setWindowTitle("Asset browser")
        self.assetb_dock_widget.setFeatures(QDockWidget.AllDockWidgetFeatures)
        self.assetb_dock_widget.setWidget(self.assetb_widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.assetb_dock_widget)

        self.recorded_event_widget = RecordEventWidget(api=self.api)
        self.recorded_event_dock_widget = QDockWidget(self)
        self.recorded_event_dock_widget.setWindowTitle("Recorded events")
        self.recorded_event_dock_widget.hide()
        self.recorded_event_dock_widget.setFeatures(QDockWidget.AllDockWidgetFeatures)
        self.recorded_event_dock_widget.setWidget(self.recorded_event_widget)
        self.addDockWidget(Qt.RightDockWidgetArea, self.recorded_event_dock_widget)

        #TODO bug #114 workaround. Disable create sub engine...
        if platform.system().lower() != 'darwin':
            self.ogl_widget = CetechWidget(self, self.api)
            self.ogl_dock = QDockWidget(self)
            self.ogl_dock.hide()
            self.ogl_dock.setWidget(self.ogl_widget)
            self.addDockWidget(Qt.TopDockWidgetArea, self.ogl_dock)

        self.tabifyDockWidget(self.assetb_dock_widget, self.log_dock_widget)

        self.assetb_widget.asset_clicked.connect(self.open_asset)

        self.file_watch = QFileSystemWatcher(self)
        self.file_watch.fileChanged.connect(self.file_changed)
        self.file_watch.directoryChanged.connect(self.dir_changed)

        self.build_file_watch = QFileSystemWatcher(self)
        self.build_file_watch.fileChanged.connect(self.build_file_changed)
        self.build_file_watch.directoryChanged.connect(self.build_dir_changed)
コード例 #45
0
class _FileWatcher(QObject):
    """File watcher.

    QFileSystemWatcher notifies client about any change (file access mode, modification date, etc.)
    But, we need signal, only after file contents had been changed
    """
    modified = pyqtSignal(bool)
    removed = pyqtSignal(bool)

    def __init__(self, path):
        QObject.__init__(self)
        self._contents = None
        self._watcher = QFileSystemWatcher()
        self._timer = None
        self._path = path

        self._lastEmittedModifiedStatus = None
        self._lastEmittedRemovedStatus = None

        self.setPath(path)
        self.enable()

    def term(self):
        self.disable()

    def enable(self):
        """Enable signals from the watcher
        """
        self._watcher.fileChanged.connect(self._onFileChanged)

    def disable(self):
        """Disable signals from the watcher
        """
        self._watcher.fileChanged.disconnect(self._onFileChanged)
        self._stopTimer()

    def setContents(self, contents):
        """Set file contents. Watcher uses it to compare old and new contents of the file.
        """
        self._contents = contents
        # Qt File watcher may work incorrectly, if file was not existing, when it started
        if not self._watcher.files():
            self.setPath(self._path)
        self._lastEmittedModifiedStatus = None
        self._lastEmittedRemovedStatus = None

    def setPath(self, path):
        """Path had been changed or file had been created. Set new path
        """
        if self._watcher.files():
            self._watcher.removePaths(self._watcher.files())
        if path is not None and os.path.isfile(path):
            self._watcher.addPath(path)
        self._path = path
        self._lastEmittedModifiedStatus = None
        self._lastEmittedRemovedStatus = None

    def _emitModifiedStatus(self):
        """Emit self.modified signal with right status
        """
        isModified = self._contents != self._safeRead(self._path)
        if isModified != self._lastEmittedModifiedStatus:
            self.modified.emit(isModified)
            self._lastEmittedModifiedStatus = isModified

    def _emitRemovedStatus(self, isRemoved):
        """Emit 'removed', if status changed"""
        if isRemoved != self._lastEmittedRemovedStatus:
            self._lastEmittedRemovedStatus = isRemoved
            self.removed.emit(isRemoved)

    @pyqtSlot()
    def _onFileChanged(self):
        """File changed. Emit own signal, if contents changed
        """
        if os.path.exists(self._path):
            self._emitModifiedStatus()
        else:
            self._emitRemovedStatus(True)

        # Sometimes QFileSystemWatcher emits only 1 signal for 2 modifications
        # Check once more later
        self._startTimer()

    def _startTimer(self):
        """Init a timer.
        It is used for monitoring file after deletion.
        Git removes file, than restores it.
        """
        if self._timer is None:
            self._timer = QTimer()
            self._timer.setInterval(500)
            self._timer.timeout.connect(self._onCheckIfDeletedTimer)
        self._timer.start()

    def _stopTimer(self):
        """Stop timer, if exists
        """
        if self._timer is not None:
            self._timer.stop()

    @pyqtSlot()
    def _onCheckIfDeletedTimer(self):
        """Check, if file has been restored
        """
        if os.path.exists(self._path):
            self.setPath(self._path)  # restart Qt file watcher after file has been restored
            self._stopTimer()
            self._emitRemovedStatus(False)
            self._emitModifiedStatus()

    def _safeRead(self, path):
        """Read file. Ignore exceptions
        """
        try:
            with open(path, 'rb') as file:
                return file.read()
        except (OSError, IOError):
            return None
コード例 #46
0
ファイル: editor.py プロジェクト: The-Compiler/qutebrowser
class ExternalEditor(QObject):

    """Class to simplify editing a text in an external editor.

    Attributes:
        _text: The current text before the editor is opened.
        _filename: The name of the file to be edited.
        _remove_file: Whether the file should be removed when the editor is
                      closed.
        _proc: The GUIProcess of the editor.
        _watcher: A QFileSystemWatcher to watch the edited file for changes.
                  Only set if watch=True.
        _content: The last-saved text of the editor.

    Signals:
        file_updated: The text in the edited file was updated.
                      arg: The new text.
        editing_finished: The editor process was closed.
    """

    file_updated = pyqtSignal(str)
    editing_finished = pyqtSignal()

    def __init__(self, parent=None, watch=False):
        super().__init__(parent)
        self._filename = None
        self._proc = None
        self._remove_file = None
        self._watcher = QFileSystemWatcher(parent=self) if watch else None
        self._content = None

    def _cleanup(self):
        """Clean up temporary files after the editor closed."""
        assert self._remove_file is not None

        watched_files = self._watcher.files() if self._watcher else []
        if watched_files:
            failed = self._watcher.removePaths(watched_files)
            if failed:
                log.procs.error("Failed to unwatch paths: {}".format(failed))

        if self._filename is None or not self._remove_file:
            # Could not create initial file.
            return

        try:
            if self._proc.exit_status() != QProcess.CrashExit:
                os.remove(self._filename)
        except OSError as e:
            # NOTE: Do not replace this with "raise CommandError" as it's
            # executed async.
            message.error("Failed to delete tempfile... ({})".format(e))

    @pyqtSlot(int, QProcess.ExitStatus)
    def _on_proc_closed(self, _exitcode, exitstatus):
        """Write the editor text into the form field and clean up tempfile.

        Callback for QProcess when the editor was closed.
        """
        log.procs.debug("Editor closed")
        if exitstatus != QProcess.NormalExit:
            # No error/cleanup here, since we already handle this in
            # on_proc_error.
            return
        # do a final read to make sure we don't miss the last signal
        self._on_file_changed(self._filename)
        self.editing_finished.emit()
        self._cleanup()

    @pyqtSlot(QProcess.ProcessError)
    def _on_proc_error(self, _err):
        self._cleanup()

    def edit(self, text, caret_position=None):
        """Edit a given text.

        Args:
            text: The initial text to edit.
            caret_position: The position of the caret in the text.
        """
        if self._filename is not None:
            raise ValueError("Already editing a file!")
        try:
            self._filename = self._create_tempfile(text, 'qutebrowser-editor-')
        except OSError as e:
            message.error("Failed to create initial file: {}".format(e))
            return

        self._remove_file = True

        line, column = self._calc_line_and_column(text, caret_position)
        self._start_editor(line=line, column=column)

    def backup(self):
        """Create a backup if the content has changed from the original."""
        if not self._content:
            return
        try:
            fname = self._create_tempfile(self._content,
                                          'qutebrowser-editor-backup-')
            message.info('Editor backup at {}'.format(fname))
        except OSError as e:
            message.error('Failed to create editor backup: {}'.format(e))

    def _create_tempfile(self, text, prefix):
        # Close while the external process is running, as otherwise systems
        # with exclusive write access (e.g. Windows) may fail to update
        # the file from the external editor, see
        # https://github.com/qutebrowser/qutebrowser/issues/1767
        with tempfile.NamedTemporaryFile(
                mode='w', prefix=prefix,
                encoding=config.val.editor.encoding,
                delete=False) as fobj:
            if text:
                fobj.write(text)
            return fobj.name

    @pyqtSlot(str)
    def _on_file_changed(self, path):
        try:
            with open(path, 'r', encoding=config.val.editor.encoding) as f:
                text = f.read()
        except OSError as e:
            # NOTE: Do not replace this with "raise CommandError" as it's
            # executed async.
            message.error("Failed to read back edited file: {}".format(e))
            return
        log.procs.debug("Read back: {}".format(text))
        if self._content != text:
            self._content = text
            self.file_updated.emit(text)

    def edit_file(self, filename):
        """Edit the file with the given filename."""
        self._filename = filename
        self._remove_file = False
        self._start_editor()

    def _start_editor(self, line=1, column=1):
        """Start the editor with the file opened as self._filename.

        Args:
            line: the line number to pass to the editor
            column: the column number to pass to the editor
        """
        self._proc = guiprocess.GUIProcess(what='editor', parent=self)
        self._proc.finished.connect(self._on_proc_closed)
        self._proc.error.connect(self._on_proc_error)
        editor = config.val.editor.command
        executable = editor[0]

        if self._watcher:
            ok = self._watcher.addPath(self._filename)
            if not ok:
                log.procs.error("Failed to watch path: {}"
                                .format(self._filename))
            self._watcher.fileChanged.connect(self._on_file_changed)

        args = [self._sub_placeholder(arg, line, column) for arg in editor[1:]]
        log.procs.debug("Calling \"{}\" with args {}".format(executable, args))
        self._proc.start(executable, args)

    def _calc_line_and_column(self, text, caret_position):
        r"""Calculate line and column numbers given a text and caret position.

        Both line and column are 1-based indexes, because that's what most
        editors use as line and column starting index.  By "most" we mean at
        least vim, nvim, gvim, emacs, atom, sublimetext, notepad++, brackets,
        visual studio, QtCreator and so on.

        To find the line we just count how many newlines there are before the
        caret and add 1.

        To find the column we calculate the difference between the caret and
        the last newline before the caret.

        For example in the text `aaa\nbb|bbb` (| represents the caret):
        caret_position = 6
        text[:caret_position] = `aaa\nbb`
        text[:caret_position].count('\n') = 1
        caret_position - text[:caret_position].rfind('\n') = 3

        Thus line, column = 2, 3, and the caret is indeed in the second
        line, third column

        Args:
            text: the text for which the numbers must be calculated
            caret_position: the position of the caret in the text, or None

        Return:
            A (line, column) tuple of (int, int)
        """
        if caret_position is None:
            return 1, 1
        line = text[:caret_position].count('\n') + 1
        column = caret_position - text[:caret_position].rfind('\n')
        return line, column

    def _sub_placeholder(self, arg, line, column):
        """Substitute a single placeholder.

        If the `arg` input to this function is a valid placeholder it will
        be substituted with the appropriate value, otherwise it will be left
        unchanged.

        Args:
            arg: an argument of editor.command.
            line: the previously-calculated line number for the text caret.
            column: the previously-calculated column number for the text caret.

        Return:
            The substituted placeholder or the original argument.
        """
        replacements = {
            '{}': self._filename,
            '{file}': self._filename,
            '{line}': str(line),
            '{line0}': str(line-1),
            '{column}': str(column),
            '{column0}': str(column-1)
        }

        for old, new in replacements.items():
            arg = arg.replace(old, new)

        return arg
コード例 #47
0
ファイル: documents.py プロジェクト: mbarbon/pugdebug
class PugdebugDocuments(QObject):

    watcher = None

    open_documents = {}

    document_changed = pyqtSignal(object)

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

        self.watcher = QFileSystemWatcher()
        self.watcher.fileChanged.connect(self.handle_file_changed)

    def open_document(self, path):
        path_key = self.get_path_key(path)

        document = PugdebugDocument(path)
        self.open_documents[path_key] = document

        self.watcher.addPath(path)

        return document

    def close_document(self, path):
        path_key = self.get_path_key(path)
        self.open_documents.pop(path_key, None)

        self.watcher.removePath(path)

    def refresh_document(self, path):
        """Refresh a document

        Gets called when the file system watcher notices
        a change to an open document.
        """
        path_key = self.get_path_key(path)
        document = self.open_documents[path_key]

        document.read_file(path)

        self.document_changed.emit(document)

    def is_document_open(self, path):
        path_key = self.get_path_key(path)
        return path_key in self.open_documents

    def handle_file_changed(self, path):
        """Handle when a watched file gets changed

        Crazy stuff ahead.

        If a file is modified, some editors (systems?) will first remove
        the file and then write it back to the disk. And for that split
        second, the watcher will drop the file from being watched.

        But then again, maybe that file really got deleted? Who knows?!

        Anyway, when a file gets modified, we sleep a short while to
        see if that file will "get back" and if so, add it back to the
        watcher. If not, we'll assume the file got deleted.
        """
        if not self.__is_path_watched(path):
            fileinfo = QFileInfo(path)

            total_slept = 0
            file_exists = fileinfo.exists()

            while not file_exists:
                sleep_for = 0.1
                total_slept += sleep_for

                if total_slept > 1:
                    break

                time.sleep(sleep_for)
                file_exists = fileinfo.exists()

            if file_exists:
                self.watcher.addPath(path)

                self.refresh_document(path)
            else:
                # file got deleted?
                pass

    def get_path_key(self, path):
        path_key = hashlib.md5(path.encode("utf-8"))
        return path_key.hexdigest()

    def __is_path_watched(self, path):
        return path in self.watcher.files()
コード例 #48
0
ファイル: Scene.py プロジェクト: Ultimaker/Uranium
class Scene:
    def __init__(self) -> None:
        super().__init__()

        from UM.Scene.SceneNode import SceneNode
        self._root = SceneNode(name = "Root")
        self._root.setCalculateBoundingBox(False)
        self._connectSignalsRoot()
        self._active_camera = None  # type: Optional[Camera]
        self._ignore_scene_changes = False
        self._lock = threading.Lock()

        # Watching file for changes.
        self._file_watcher = QFileSystemWatcher()
        self._file_watcher.fileChanged.connect(self._onFileChanged)

        self._reload_message = None  # type: Optional[Message]

    def _connectSignalsRoot(self) -> None:
        self._root.transformationChanged.connect(self.sceneChanged)
        self._root.childrenChanged.connect(self.sceneChanged)
        self._root.meshDataChanged.connect(self.sceneChanged)

    def _disconnectSignalsRoot(self) -> None:
        self._root.transformationChanged.disconnect(self.sceneChanged)
        self._root.childrenChanged.disconnect(self.sceneChanged)
        self._root.meshDataChanged.disconnect(self.sceneChanged)

    def setIgnoreSceneChanges(self, ignore_scene_changes: bool) -> None:
        if self._ignore_scene_changes != ignore_scene_changes:
            self._ignore_scene_changes = ignore_scene_changes
            if self._ignore_scene_changes:
                self._disconnectSignalsRoot()
            else:
                self._connectSignalsRoot()

    ##  Gets the global scene lock.
    #
    #   Use this lock to prevent any read or write actions on the scene from other threads,
    #   assuming those threads also properly acquire the lock. Most notably, this
    #   prevents the rendering thread from rendering the scene while it is changing.
    def getSceneLock(self) -> threading.Lock:
        return self._lock

    ##  Get the root node of the scene.
    def getRoot(self) -> "SceneNode":
        return self._root

    ##  Change the root node of the scene
    def setRoot(self, node: "SceneNode") -> None:
        if self._root != node:
            if not self._ignore_scene_changes:
                self._disconnectSignalsRoot()
            self._root = node
            if not self._ignore_scene_changes:
                self._connectSignalsRoot()
            self.rootChanged.emit()

    rootChanged = Signal()

    ##  Get the camera that should be used for rendering.
    def getActiveCamera(self) -> Optional[Camera]:
        return self._active_camera

    def getAllCameras(self) -> List[Camera]:
        cameras = []
        for node in BreadthFirstIterator(self._root):  # type: ignore
            if isinstance(node, Camera):
                cameras.append(node)
        return cameras

    ##  Set the camera that should be used for rendering.
    #   \param name The name of the camera to use.
    def setActiveCamera(self, name: str) -> None:
        camera = self.findCamera(name)
        if camera:
            self._active_camera = camera
        else:
            Logger.log("w", "Couldn't find camera with name [%s] to activate!" % name)

    ##  Signal that is emitted whenever something in the scene changes.
    #   \param object The object that triggered the change.
    sceneChanged = Signal()

    ##  Find an object by id.
    #
    #   \param object_id The id of the object to search for, as returned by the python id() method.
    #
    #   \return The object if found, or None if not.
    def findObject(self, object_id: int) -> Optional["SceneNode"]:
        for node in BreadthFirstIterator(self._root):  # type: ignore
            if id(node) == object_id:
                return node
        return None

    def findCamera(self, name: str) -> Optional[Camera]:
        for node in BreadthFirstIterator(self._root):  # type: ignore
            if isinstance(node, Camera) and node.getName() == name:
                return node
        return None

    ##  Add a file to be watched for changes.
    #   \param file_path The path to the file that must be watched.
    def addWatchedFile(self, file_path: str) -> None:
        # The QT 5.10.0 issue, only on Windows. Cura crashes after loading a stl file from USB/sd-card/Cloud-based drive
        if not Platform.isWindows():
            self._file_watcher.addPath(file_path)

    ##  Remove a file so that it will no longer be watched for changes.
    #   \param file_path The path to the file that must no longer be watched.
    def removeWatchedFile(self, file_path: str) -> None:
        # The QT 5.10.0 issue, only on Windows. Cura crashes after loading a stl file from USB/sd-card/Cloud-based drive
        if not Platform.isWindows():
            self._file_watcher.removePath(file_path)

    ##  Triggered whenever a file is changed that we currently have loaded.
    def _onFileChanged(self, file_path: str) -> None:
        if not os.path.isfile(file_path) or os.path.getsize(file_path) == 0:  # File doesn't exist any more, or it is empty
            return

        # Multiple nodes may be loaded from the same file at different stages. Reload them all.
        from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator  # To find which nodes to reload when files have changed.
        modified_nodes = [node for node in DepthFirstIterator(self.getRoot()) if node.getMeshData() and node.getMeshData().getFileName() == file_path]  # type: ignore

        if modified_nodes:
            # Hide the message if it was already visible
            if self._reload_message is not None:
                self._reload_message.hide()

            self._reload_message = Message(i18n_catalog.i18nc("@info", "Would you like to reload {filename}?").format(filename = os.path.basename(file_path)),
                              title = i18n_catalog.i18nc("@info:title", "File has been modified"))
            self._reload_message.addAction("reload", i18n_catalog.i18nc("@action:button", "Reload"), icon = "", description = i18n_catalog.i18nc("@action:description", "This will trigger the modified files to reload from disk."))
            self._reload_callback = functools.partial(self._reloadNodes, modified_nodes)
            self._reload_message.actionTriggered.connect(self._reload_callback)
            self._reload_message.show()

    ##  Reloads a list of nodes after the user pressed the "Reload" button.
    #   \param nodes The list of nodes that needs to be reloaded.
    #   \param message The message that triggered the action to reload them.
    #   \param action The button that triggered the action to reload them.
    def _reloadNodes(self, nodes: List["SceneNode"], message: str, action: str) -> None:
        if action != "reload":
            return
        if self._reload_message is not None:
            self._reload_message.hide()
        for node in nodes:
            meshdata = node.getMeshData()
            if meshdata:
                filename = meshdata.getFileName()
                if not filename or not os.path.isfile(filename):  # File doesn't exist any more.
                    continue
                job = ReadMeshJob(filename)
                self._reload_finished_callback = functools.partial(self._reloadJobFinished, node)
                job.finished.connect(self._reload_finished_callback)
                job.start()

    ##  Triggered when reloading has finished.
    #
    #   This then puts the resulting mesh data in the node.
    def _reloadJobFinished(self, replaced_node: SceneNode, job: ReadMeshJob) -> None:
        for node in job.getResult():
            mesh_data = node.getMeshData()
            if mesh_data:
                replaced_node.setMeshData(mesh_data)
            else:
                Logger.log("w", "Could not find a mesh in reloaded node.")
コード例 #49
0
class ImageLabel(QLabel):

	sizeChanged = pyqtSignal(int, int)

	def __init__(self, parent=None):
		super(ImageLabel, self).__init__(parent)
		self.setBackgroundRole(QPalette.Base)
		self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
		self.setScaledContents(True)
		self.setAcceptDrops(True)
		self.setAlignment(Qt.AlignCenter)

	def dragEnterEvent(self, event):
		self.setBackgroundRole(QPalette.Highlight)
		event.acceptProposedAction()

	def dragMoveEvent(self, event):
		event.acceptProposedAction()

	def dropEvent(self, event):
		# Get path of dropped file
		mimeData = event.mimeData()
		if mimeData.hasUrls():
			filename = mimeData.urls()[0].toLocalFile()
			self.load(filename)
		event.acceptProposedAction()

	def dragLeaveEvent(self, event):
		self.clear()
		event.accept()

	def load(self, filename):
		# Load HDR image with FreeImage
		image = self.loadHDRImage(filename)
		if image is None:
			return False

		# Change window size
		self.sizeChanged.emit(image.width(), image.height())

		# Set the image to imageLabel
		self.setPixmap(QPixmap.fromImage(image))
		self.adjustSize()

		# Begin to watch modification
		self.watcher = QFileSystemWatcher()
		self.watcher.addPath(filename)
		self.watcher.fileChanged.connect(self.onFileChanged)

		return True

	def loadHDRImage(self, filename):
		try:
			# Load image
			img = fi.Image(filename).flipVertical()
			floats = array.array("f", img.getRaw())
			imageArray = np.array(floats).reshape((img.width, img.height, 3))

			# HDR compression
			imageArray_RGB8 = (np.clip(np.power(imageArray, 1/2.2), 0, 1) * 255).astype(np.uint8)

			# Convert to QImage
			return QImage(imageArray_RGB8.tostring(), img.width, img.height, QImage.Format_RGB888)

		except fi.FreeImageError:
			return None

	def onFileChanged(self, path):
		if os.path.isfile(path):
			self.load(path)
		else:
			self.clear()
			self.sizeChanged.emit(200, 200)
コード例 #50
0
ファイル: window.py プロジェクト: daffodil/retext
	def __init__(self, parent=None):
		QMainWindow.__init__(self, parent)
		self.resize(950, 700)
		screenRect = QDesktopWidget().screenGeometry()
		if globalSettings.windowGeometry:
			self.restoreGeometry(globalSettings.windowGeometry)
		else:
			self.move((screenRect.width()-self.width())/2, (screenRect.height()-self.height())/2)
		if not screenRect.contains(self.geometry()):
			self.showMaximized()
		if globalSettings.iconTheme:
			QIcon.setThemeName(globalSettings.iconTheme)
		if QIcon.themeName() in ('hicolor', ''):
			if not QFile.exists(icon_path + 'document-new.png'):
				QIcon.setThemeName(get_icon_theme())
		if QFile.exists(icon_path+'retext.png'):
			self.setWindowIcon(QIcon(icon_path+'retext.png'))
		elif QFile.exists('/usr/share/pixmaps/retext.png'):
			self.setWindowIcon(QIcon('/usr/share/pixmaps/retext.png'))
		else:
			self.setWindowIcon(QIcon.fromTheme('retext',
				QIcon.fromTheme('accessories-text-editor')))
		self.tabWidget = QTabWidget(self)
		self.initTabWidget()
		self.setCentralWidget(self.tabWidget)
		self.tabWidget.currentChanged.connect(self.changeIndex)
		self.tabWidget.tabCloseRequested.connect(self.closeTab)
		toolBar = QToolBar(self.tr('File toolbar'), self)
		self.addToolBar(Qt.TopToolBarArea, toolBar)
		self.editBar = QToolBar(self.tr('Edit toolbar'), self)
		self.addToolBar(Qt.TopToolBarArea, self.editBar)
		self.searchBar = QToolBar(self.tr('Search toolbar'), self)
		self.addToolBar(Qt.BottomToolBarArea, self.searchBar)
		toolBar.setVisible(not globalSettings.hideToolBar)
		self.editBar.setVisible(not globalSettings.hideToolBar)
		self.actionNew = self.act(self.tr('New'), 'document-new',
			self.createNew, shct=QKeySequence.New)
		self.actionNew.setPriority(QAction.LowPriority)
		self.actionOpen = self.act(self.tr('Open'), 'document-open',
			self.openFile, shct=QKeySequence.Open)
		self.actionOpen.setPriority(QAction.LowPriority)
		self.actionSetEncoding = self.act(self.tr('Set encoding'),
			trig=self.showEncodingDialog)
		self.actionSetEncoding.setEnabled(False)
		self.actionReload = self.act(self.tr('Reload'), 'view-refresh',
			lambda: self.currentTab.readTextFromFile())
		self.actionReload.setEnabled(False)
		self.actionSave = self.act(self.tr('Save'), 'document-save',
			self.saveFile, shct=QKeySequence.Save)
		self.actionSave.setEnabled(False)
		self.actionSave.setPriority(QAction.LowPriority)
		self.actionSaveAs = self.act(self.tr('Save as'), 'document-save-as',
			self.saveFileAs, shct=QKeySequence.SaveAs)
		self.actionNextTab = self.act(self.tr('Next tab'), 'go-next',
			lambda: self.switchTab(1), shct=Qt.CTRL+Qt.Key_PageDown)
		self.actionPrevTab = self.act(self.tr('Previous tab'), 'go-previous',
			lambda: self.switchTab(-1), shct=Qt.CTRL+Qt.Key_PageUp)
		self.actionPrint = self.act(self.tr('Print'), 'document-print',
			self.printFile, shct=QKeySequence.Print)
		self.actionPrint.setPriority(QAction.LowPriority)
		self.actionPrintPreview = self.act(self.tr('Print preview'), 'document-print-preview',
			self.printPreview)
		self.actionViewHtml = self.act(self.tr('View HTML code'), 'text-html', self.viewHtml)
		self.actionChangeEditorFont = self.act(self.tr('Change editor font'),
			trig=self.changeEditorFont)
		self.actionChangePreviewFont = self.act(self.tr('Change preview font'),
			trig=self.changePreviewFont)
		self.actionSearch = self.act(self.tr('Find text'), 'edit-find', shct=QKeySequence.Find)
		self.actionSearch.setCheckable(True)
		self.actionSearch.triggered[bool].connect(self.searchBar.setVisible)
		self.searchBar.visibilityChanged.connect(self.searchBarVisibilityChanged)
		self.actionPreview = self.act(self.tr('Preview'), shct=Qt.CTRL+Qt.Key_E,
			trigbool=self.preview)
		if QIcon.hasThemeIcon('document-preview'):
			self.actionPreview.setIcon(QIcon.fromTheme('document-preview'))
		elif QIcon.hasThemeIcon('preview-file'):
			self.actionPreview.setIcon(QIcon.fromTheme('preview-file'))
		elif QIcon.hasThemeIcon('x-office-document'):
			self.actionPreview.setIcon(QIcon.fromTheme('x-office-document'))
		else:
			self.actionPreview.setIcon(QIcon(icon_path+'document-preview.png'))
		self.actionLivePreview = self.act(self.tr('Live preview'), shct=Qt.CTRL+Qt.Key_L,
		trigbool=self.enableLivePreview)
		menuPreview = QMenu()
		menuPreview.addAction(self.actionLivePreview)
		self.actionPreview.setMenu(menuPreview)
		self.actionTableMode = self.act(self.tr('Table mode'), shct=Qt.CTRL+Qt.Key_T,
			trigbool=lambda x: self.currentTab.editBox.enableTableMode(x))
		if ReTextFakeVimHandler:
			self.actionFakeVimMode = self.act(self.tr('FakeVim mode'),
				shct=Qt.CTRL+Qt.ALT+Qt.Key_V, trigbool=self.enableFakeVimMode)
			if globalSettings.useFakeVim:
				self.actionFakeVimMode.setChecked(True)
				self.enableFakeVimMode(True)
		self.actionFullScreen = self.act(self.tr('Fullscreen mode'), 'view-fullscreen',
			shct=Qt.Key_F11, trigbool=self.enableFullScreen)
		self.actionFullScreen.setPriority(QAction.LowPriority)
		self.actionConfig = self.act(self.tr('Preferences'), icon='preferences-system',
			trig=self.openConfigDialog)
		self.actionConfig.setMenuRole(QAction.PreferencesRole)
		self.actionSaveHtml = self.act('HTML', 'text-html', self.saveFileHtml)
		self.actionPdf = self.act('PDF', 'application-pdf', self.savePdf)
		self.actionOdf = self.act('ODT', 'x-office-document', self.saveOdf)
		self.getExportExtensionsList()
		self.actionQuit = self.act(self.tr('Quit'), 'application-exit', shct=QKeySequence.Quit)
		self.actionQuit.setMenuRole(QAction.QuitRole)
		self.actionQuit.triggered.connect(self.close)
		self.actionUndo = self.act(self.tr('Undo'), 'edit-undo',
			lambda: self.currentTab.editBox.undo(), shct=QKeySequence.Undo)
		self.actionRedo = self.act(self.tr('Redo'), 'edit-redo',
			lambda: self.currentTab.editBox.redo(), shct=QKeySequence.Redo)
		self.actionCopy = self.act(self.tr('Copy'), 'edit-copy',
			lambda: self.currentTab.editBox.copy(), shct=QKeySequence.Copy)
		self.actionCut = self.act(self.tr('Cut'), 'edit-cut',
			lambda: self.currentTab.editBox.cut(), shct=QKeySequence.Cut)
		self.actionPaste = self.act(self.tr('Paste'), 'edit-paste',
			lambda: self.currentTab.editBox.paste(), shct=QKeySequence.Paste)
		self.actionUndo.setEnabled(False)
		self.actionRedo.setEnabled(False)
		self.actionCopy.setEnabled(False)
		self.actionCut.setEnabled(False)
		qApp = QApplication.instance()
		qApp.clipboard().dataChanged.connect(self.clipboardDataChanged)
		self.clipboardDataChanged()
		if enchant_available:
			self.actionEnableSC = self.act(self.tr('Enable'), trigbool=self.enableSpellCheck)
			self.actionSetLocale = self.act(self.tr('Set locale'), trig=self.changeLocale)
		self.actionWebKit = self.act(self.tr('Use WebKit renderer'), trigbool=self.enableWebKit)
		self.actionWebKit.setChecked(globalSettings.useWebKit)
		self.actionShow = self.act(self.tr('Show directory'), 'system-file-manager', self.showInDir)
		self.actionFind = self.act(self.tr('Next'), 'go-next', self.find,
			shct=QKeySequence.FindNext)
		self.actionFindPrev = self.act(self.tr('Previous'), 'go-previous',
			lambda: self.find(back=True), shct=QKeySequence.FindPrevious)
		self.actionCloseSearch = self.act(self.tr('Close'), 'window-close',
			lambda: self.searchBar.setVisible(False))
		self.actionCloseSearch.setPriority(QAction.LowPriority)
		self.actionHelp = self.act(self.tr('Get help online'), 'help-contents', self.openHelp)
		self.aboutWindowTitle = self.tr('About ReText')
		self.actionAbout = self.act(self.aboutWindowTitle, 'help-about', self.aboutDialog)
		self.actionAbout.setMenuRole(QAction.AboutRole)
		self.actionAboutQt = self.act(self.tr('About Qt'))
		self.actionAboutQt.setMenuRole(QAction.AboutQtRole)
		self.actionAboutQt.triggered.connect(qApp.aboutQt)
		availableMarkups = markups.get_available_markups()
		if not availableMarkups:
			print('Warning: no markups are available!')
		self.defaultMarkup = availableMarkups[0] if availableMarkups else None
		if globalSettings.defaultMarkup:
			mc = markups.find_markup_class_by_name(globalSettings.defaultMarkup)
			if mc and mc.available():
				self.defaultMarkup = mc
		if len(availableMarkups) > 1:
			self.chooseGroup = QActionGroup(self)
			markupActions = []
			for markup in availableMarkups:
				markupAction = self.act(markup.name, trigbool=self.markupFunction(markup))
				if markup == self.defaultMarkup:
					markupAction.setChecked(True)
				self.chooseGroup.addAction(markupAction)
				markupActions.append(markupAction)
		self.actionBold = self.act(self.tr('Bold'), shct=QKeySequence.Bold,
			trig=lambda: self.insertFormatting('bold'))
		self.actionItalic = self.act(self.tr('Italic'), shct=QKeySequence.Italic,
			trig=lambda: self.insertFormatting('italic'))
		self.actionUnderline = self.act(self.tr('Underline'), shct=QKeySequence.Underline,
			trig=lambda: self.insertFormatting('underline'))
		self.usefulTags = ('header', 'italic', 'bold', 'underline', 'numbering',
			'bullets', 'image', 'link', 'inline code', 'code block', 'blockquote')
		self.usefulChars = ('deg', 'divide', 'dollar', 'hellip', 'laquo', 'larr',
			'lsquo', 'mdash', 'middot', 'minus', 'nbsp', 'ndash', 'raquo',
			'rarr', 'rsquo', 'times')
		self.formattingBox = QComboBox(self.editBar)
		self.formattingBox.addItem(self.tr('Formatting'))
		self.formattingBox.addItems(self.usefulTags)
		self.formattingBox.activated[str].connect(self.insertFormatting)
		self.symbolBox = QComboBox(self.editBar)
		self.symbolBox.addItem(self.tr('Symbols'))
		self.symbolBox.addItems(self.usefulChars)
		self.symbolBox.activated.connect(self.insertSymbol)
		self.updateStyleSheet()
		menubar = self.menuBar()
		menuFile = menubar.addMenu(self.tr('File'))
		menuEdit = menubar.addMenu(self.tr('Edit'))
		menuHelp = menubar.addMenu(self.tr('Help'))
		menuFile.addAction(self.actionNew)
		menuFile.addAction(self.actionOpen)
		self.menuRecentFiles = menuFile.addMenu(self.tr('Open recent'))
		self.menuRecentFiles.aboutToShow.connect(self.updateRecentFiles)
		menuFile.addAction(self.actionShow)
		menuFile.addAction(self.actionSetEncoding)
		menuFile.addAction(self.actionReload)
		menuFile.addSeparator()
		menuFile.addAction(self.actionSave)
		menuFile.addAction(self.actionSaveAs)
		menuFile.addSeparator()
		menuFile.addAction(self.actionNextTab)
		menuFile.addAction(self.actionPrevTab)
		menuFile.addSeparator()
		menuExport = menuFile.addMenu(self.tr('Export'))
		menuExport.addAction(self.actionSaveHtml)
		menuExport.addAction(self.actionOdf)
		menuExport.addAction(self.actionPdf)
		if self.extensionActions:
			menuExport.addSeparator()
			for action, mimetype in self.extensionActions:
				menuExport.addAction(action)
			menuExport.aboutToShow.connect(self.updateExtensionsVisibility)
		menuFile.addAction(self.actionPrint)
		menuFile.addAction(self.actionPrintPreview)
		menuFile.addSeparator()
		menuFile.addAction(self.actionQuit)
		menuEdit.addAction(self.actionUndo)
		menuEdit.addAction(self.actionRedo)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionCut)
		menuEdit.addAction(self.actionCopy)
		menuEdit.addAction(self.actionPaste)
		menuEdit.addSeparator()
		if enchant_available:
			menuSC = menuEdit.addMenu(self.tr('Spell check'))
			menuSC.addAction(self.actionEnableSC)
			menuSC.addAction(self.actionSetLocale)
		menuEdit.addAction(self.actionSearch)
		menuEdit.addAction(self.actionChangeEditorFont)
		menuEdit.addAction(self.actionChangePreviewFont)
		menuEdit.addSeparator()
		if len(availableMarkups) > 1:
			self.menuMode = menuEdit.addMenu(self.tr('Default markup'))
			for markupAction in markupActions:
				self.menuMode.addAction(markupAction)
		menuFormat = menuEdit.addMenu(self.tr('Formatting'))
		menuFormat.addAction(self.actionBold)
		menuFormat.addAction(self.actionItalic)
		menuFormat.addAction(self.actionUnderline)
		menuEdit.addAction(self.actionWebKit)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionViewHtml)
		menuEdit.addAction(self.actionPreview)
		menuEdit.addAction(self.actionTableMode)
		if ReTextFakeVimHandler:
			menuEdit.addAction(self.actionFakeVimMode)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionFullScreen)
		menuEdit.addAction(self.actionConfig)
		menuHelp.addAction(self.actionHelp)
		menuHelp.addSeparator()
		menuHelp.addAction(self.actionAbout)
		menuHelp.addAction(self.actionAboutQt)
		toolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		toolBar.addAction(self.actionNew)
		toolBar.addSeparator()
		toolBar.addAction(self.actionOpen)
		toolBar.addAction(self.actionSave)
		toolBar.addAction(self.actionPrint)
		toolBar.addSeparator()
		toolBar.addAction(self.actionPreview)
		toolBar.addAction(self.actionFullScreen)
		self.editBar.addAction(self.actionUndo)
		self.editBar.addAction(self.actionRedo)
		self.editBar.addSeparator()
		self.editBar.addAction(self.actionCut)
		self.editBar.addAction(self.actionCopy)
		self.editBar.addAction(self.actionPaste)
		self.editBar.addSeparator()
		self.editBar.addWidget(self.formattingBox)
		self.editBar.addWidget(self.symbolBox)
		self.searchEdit = QLineEdit(self.searchBar)
		self.searchEdit.setPlaceholderText(self.tr('Search'))
		self.searchEdit.returnPressed.connect(self.find)
		self.csBox = QCheckBox(self.tr('Case sensitively'), self.searchBar)
		self.searchBar.addWidget(self.searchEdit)
		self.searchBar.addSeparator()
		self.searchBar.addWidget(self.csBox)
		self.searchBar.addAction(self.actionFindPrev)
		self.searchBar.addAction(self.actionFind)
		self.searchBar.addAction(self.actionCloseSearch)
		self.searchBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		self.searchBar.setVisible(False)
		self.autoSaveEnabled = globalSettings.autoSave
		if self.autoSaveEnabled:
			timer = QTimer(self)
			timer.start(60000)
			timer.timeout.connect(self.saveAll)
		self.ind = None
		if enchant_available:
			self.sl = globalSettings.spellCheckLocale
			if self.sl:
				try:
					enchant.Dict(self.sl)
				except Exception as e:
					print(e, file=sys.stderr)
					self.sl = None
			if globalSettings.spellCheck:
				self.actionEnableSC.setChecked(True)
		self.fileSystemWatcher = QFileSystemWatcher()
		self.fileSystemWatcher.fileChanged.connect(self.fileChanged)
コード例 #51
0
ファイル: nfile.py プロジェクト: ninja-ide/ninja-ide
class NFile(QObject):
    """
    SIGNALS:
    @askForSaveFileClosing(QString)
    @fileClosing(QString)
    @fileChanged()
    @willDelete(PyQt_PyObject, PyQt_PyObject)
    @willOverWrite(PyQt_PyObject, QString, QString)
    @willMove(Qt_PyQtObject, QString, QString)
    @willSave(QString, QString)
    @savedAsNewFile(PyQt_PyObject, QString, QString)
    @gotAPath(PyQt_PyObject)
    @willAttachToExistingFile(PyQt_PyObject, QString)
    """
    fileChanged = pyqtSignal()
    fileRemoved = pyqtSignal()
    fileReaded = pyqtSignal()
    willAttachToExistingFile = pyqtSignal('PyQt_PyObject', 'QString')
    gotAPath = pyqtSignal('PyQt_PyObject')
    willSave = pyqtSignal('QString', 'QString')
    willMove = pyqtSignal('PyQt_PyObject', 'QString', 'QString')
    willOverWrite = pyqtSignal('PyQt_PyObject', 'QString', 'QString')
    willCopyTo = pyqtSignal('PyQt_PyObject', 'QString', 'QString')
    willDelete = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject')
    fileClosing = pyqtSignal('QString', bool)

    def __init__(self, path=None):
        """
        """
        self._file_path = path
        self.__created = False
        self.__watcher = None
        self.__mtime = None
        super(NFile, self).__init__()
        if not self._exists():
            self.__created = True

    @property
    def file_name(self):
        """"Returns filename of nfile"""
        file_name = None
        if self._file_path is None:
            file_name = translations.TR_NEW_DOCUMENT
        else:
            file_name = get_basename(self._file_path)
        return file_name

    @property
    def display_name(self):
        """Returns a pretty name to be displayed by tabs"""
        display_name = self.file_name
        if self._file_path is not None and not self.has_write_permission():
            display_name += translations.TR_READ_ONLY
        return display_name

    @property
    def is_new_file(self):
        return self.__created

    def file_ext(self):
        """"Returns extension of nfile"""
        if self._file_path is None:
            return ''
        return get_file_extension(self._file_path)

    @property
    def file_path(self):
        """"Returns file path of nfile"""
        return self._file_path

    def start_watching(self):
        """Create a file system watcher and connect its fileChanged
        SIGNAL to our _file_changed SLOT"""
        if self.__watcher is None:
            self.__watcher = QFileSystemWatcher(self)
            self.__watcher.fileChanged['const QString&'].connect(
                self._file_changed)
        if self._file_path is not None:
            self.__mtime = os.path.getmtime(self._file_path)
            self.__watcher.addPath(self._file_path)

    def _file_changed(self, path):
        if self._exists():
            current_mtime = os.path.getmtime(self._file_path)
            if current_mtime != self.__mtime:
                self.__mtime = current_mtime
                self.fileChanged.emit()
        # FIXME: for swap file
        # else:
        #     self.fileRemoved.emit()

    def has_write_permission(self):
        if not self._exists():
            return True
        return os.access(self._file_path, os.W_OK)

    def _exists(self):
        """
        Check if we have been created with a path and if such path exists
        In case there is no path, we are most likely a new file.
        """
        file_exists = False
        if self._file_path and os.path.exists(self._file_path):
            file_exists = True
        return file_exists

    def attach_to_path(self, new_path):
        if os.path.exists(new_path):
            signal_handler = SignalFlowControl()
            self.willAttachToExistingFile.emit(signal_handler, new_path)
            if signal_handler.stopped():
                    return
        self._file_path = new_path
        self.gotAPath.emit(self)
        return self._file_path

    def create(self):
        if self.__created:
            self.save("")
        self.__created = False

    def save(self, content, path=None):
        """
        Write a temporary file with .tnj extension and copy it over the
        original one.
        .nsf = Ninja Swap File
        # FIXME: Where to locate addExtension, does not fit here
        """
        new_path = False
        if path:
            self.attach_to_path(path)
            new_path = True

        save_path = self._file_path

        if not save_path:
            raise NinjaNoFileNameException("I am asked to write a "
                                           "file but no one told me where")
        swap_save_path = "%s.nsp" % save_path

        # If we have a file system watcher, remove the file path
        # from its watch list until we are done making changes.
        if self.__watcher is not None:
            self.__watcher.removePath(save_path)

        flags = QIODevice.WriteOnly | QIODevice.Truncate
        f = QFile(swap_save_path)
        if settings.use_platform_specific_eol():
            flags |= QIODevice.Text

        if not f.open(flags):
            raise NinjaIOException(f.errorString())

        stream = QTextStream(f)
        encoding = get_file_encoding(content)
        if encoding:
            stream.setCodec(encoding)

        encoded_stream = stream.codec().fromUnicode(content)
        f.write(encoded_stream)
        f.flush()
        f.close()
        # SIGNAL: Will save (temp, definitive) to warn folder to do something
        self.willSave.emit(swap_save_path, save_path)
        self.__mtime = os.path.getmtime(swap_save_path)
        shutil.move(swap_save_path, save_path)
        self.reset_state()

        # If we have a file system watcher, add the saved path back
        # to its watch list, otherwise create a watcher and start
        # watching
        if self.__watcher is not None:
            if new_path:
                # self.__watcher.removePath(self.__watcher.files()[0])
                self.__watcher.addPath(self._file_path)
            else:
                self.__watcher.addPath(save_path)
        else:
            self.start_watching()
        return self

    def reset_state(self):
        """
        #FIXE: to have a ref to changed I need to have the doc here
        """
        self.__created = False

    def read(self, path=None):
        """
        Read the file or fail
        """
        open_path = path and path or self._file_path
        self._file_path = open_path
        if not self._file_path:
            raise NinjaNoFileNameException("I am asked to read a file "
                                           "but no one told me from where")
        try:
            with open(open_path, 'r') as f:
                content = f.read()
        except (IOError, UnicodeDecodeError) as reason:
            raise NinjaIOException(reason)
        self.fileReaded.emit()
        return content

    def move(self, new_path):
        """
        Phisically move the file
        """
        if self._exists():
            signal_handler = SignalFlowControl()
            # SIGNALL: WILL MOVE TO, to warn folder to exist
            self.willMove.emit(signal_handler,
                               self._file_path,
                               new_path)
            if signal_handler.stopped():
                return
            if os.path.exists(new_path):
                signal_handler = SignalFlowControl()
                self.willOverWrite.emit(signal_handler,
                                        self._file_path,
                                        new_path)
                if signal_handler.stopped():
                    return
            if self.__watcher is not None:
                self.__watcher.removePath(self._file_path)
            shutil.move(self._file_path, new_path)
            if self.__watcher:
                self.__watcher.addPath(new_path)
        self._file_path = new_path

    def copy(self, new_path):
        """
        Copy the file to a new path
        """
        if self._exists():
            signal_handler = SignalFlowControl()
            # SIGNALL: WILL COPY TO, to warn folder to exist
            self.willCopyTo.emit(signal_handler,
                                 self._file_path,
                                 new_path)
            if signal_handler.stopped():
                return
            if os.path.exists(new_path):
                signal_handler = SignalFlowControl()
                self.willOverWrite.emit(signal_handler,
                                        self._file_path,
                                        new_path)
                if signal_handler.stopped():
                    return

            shutil.copy(self._file_path, new_path)

    def delete(self, force=False):
        """
        This deletes the object and closes the file.
        """
        # if created but exists this file migth to someone else
        self.close()
        if ((not self.__created) or force) and self._exists():
            DEBUG("Deleting our own NFile %s" % self._file_path)
            signal_handler = SignalFlowControl()
            self.willDelete.emit(signal_handler, self)
            if not signal_handler.stopped():
                if self.__watcher is not None:
                    self.__watcher.removePath(self._file_path)
                os.remove(self._file_path)

    def close(self, force_close=False):
        """
        Lets let people know we are going down so they can act upon
        As you can see close does nothing but let everyone know that we are
        not saved yet
        """
        DEBUG("About to close NFile")
        self.fileClosing.emit(self._file_path, force_close)

    def remove_watcher(self):
        if self.__watcher is not None:
            self.__watcher.removePath(self._file_path)
コード例 #52
0
ファイル: main.py プロジェクト: justbuchanan/qbar
def main():
    # Command-line arguments
    parser = argparse.ArgumentParser(
        prog='qbar',
        description="An easily-configurable and good-looking status bar for Linux")
    parser.add_argument(
        "--monitor",
        "-m",
        type=str,
        default=None,
        help="Name of the monitor to display the bar on")

    # TODO: use css for this instead?
    parser.add_argument(
        "--height",
        type=int,
        default=30,
        help="Height (in px) of the status bar")
    parser.add_argument(
        "--css",
        type=str,
        default=None,
        help="Stylesheet file to override the default style")
    parser.add_argument(
        "--config",
        "-c",
        default=None,
        help="Congifuration file for qbar written in yaml.  Looks under $XDG_HOME or .config for qbar/config.yml by default.  if not found, uses a builtin default")
    parser.add_argument(
        "--position",
        "-p",
        type=str,
        default="top",
        choices=["top", "bottom"],
        help="Display position of the bar.  Can be 'top' or 'bottom'")
    parser.add_argument(
        "--log-level",
        "-l",
        default='WARNING',
        choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'],
        help="Change the level of information to be logged.")
    ARGS = parser.parse_args()

    # Log level for the root logger
    numeric_log_level = getattr(logging, ARGS.log_level.upper(), None)
    logging.getLogger().setLevel(numeric_log_level)

    # Init app
    app = QApplication(sys.argv)
    bar = Bar(ARGS.monitor, height=ARGS.height, position=ARGS.position)

    # Set default stylesheet and override with custom one if present
    stylesheet_files = [os.path.abspath(os.path.dirname(__file__)) + "/../configs/default.css"]
    if ARGS.css != None:
        stylesheet_files.append(ARGS.css)
    css_loader = StyleSheetLoader(stylesheet_files, lambda styles: app.setStyleSheet(styles))

    # Find config file path
    cfgfile = ARGS.config if ARGS.config != None else default_user_config_dir() + '/config.py'
    if not os.path.exists(cfgfile):
        if ARGS.config != None:
            logging.error("Specified config file does not exist: %s" % ARGS.config)
        logging.info("Using builtin default config file")
        cfgfile = os.path.abspath(os.path.dirname(__file__)) + "/../configs/default.py"

    # Load config file and set it up to reload whenever the file changes
    cfgmodule = load_config_module(cfgfile)
    bar.items = cfgmodule.items
    def reload_config(filepath):
        logging.info("Config file changed, reloading: %s" % filepath)
        try:
            importlib.reload(cfgmodule)
            bar.items = cfgmodule.items
        except SyntaxError as e:
            logging.error("SyntaxError encountered when attempting to load config file: %s" % str(e))
            bar.items = []
    watcher = QFileSystemWatcher()
    watcher.addPath(cfgfile)
    watcher.fileChanged.connect(reload_config)

    # Run!
    bar.start()
    bar.show()

    # Exit app on ctrl+c.
    # Note that a timer must be present in order for Ctrl+C to work. Otherwise
    # the python interpreter never gets a chance to run and handle the signal.
    sigtimer = QTimer()
    sigtimer.timeout.connect(lambda: None)
    sigtimer.start(500)
    def sigint_handler(signal, frame):
        print("\nReceived Ctrl+C, exiting...")
        bar.stop()
        QApplication.quit()
    signal.signal(signal.SIGINT, sigint_handler)

    ret = app.exec_()
    sys.exit(ret)
コード例 #53
0
ファイル: mainwindow.py プロジェクト: cyberegoorg/cetech
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)

        self.centralwidget.hide()

        self.project = ProjectManager()
        self.modules_manager = ModuleManager(self)

        self.setTabPosition(Qt.AllDockWidgetAreas, QTabWidget.North)

        self.modules_manager.init_modules([
            CompilerModule,
            LevelWidget,
            AssetViewWidget,
            AssetBrowser,
            LogWidget,
            ProfilerWidget,
            ScriptEditorManager
        ])

        self.file_watch = QFileSystemWatcher(self)
        self.file_watch.fileChanged.connect(self.file_changed)
        self.file_watch.directoryChanged.connect(self.dir_changed)

        self.build_file_watch = QFileSystemWatcher(self)
        self.build_file_watch.fileChanged.connect(self.build_file_changed)
        self.build_file_watch.directoryChanged.connect(self.build_dir_changed)

    def open_project(self, name, dir):
        self.project.open_project(name, dir)
        self.modules_manager.open_project(self.project)
        self.watch_project_dir()

    def reload_all(self):
        self.modules_manager['compiler'].compile_all()

        for k, v in self.project.instances.items():
            v.console_api.reload_all()

    def watch_project_dir(self):
        files = self.file_watch.files()
        directories = self.file_watch.directories()

        if len(files):
            self.file_watch.removePaths(files)

        if len(directories):
            self.file_watch.removePaths(directories)

        files = self.build_file_watch.files()
        directories = self.build_file_watch.directories()

        if len(files):
            self.build_file_watch.removePaths(files)

        if len(directories):
            self.build_file_watch.removePaths(directories)

        files = []
        it = QDirIterator(self.project.source_dir, QDirIterator.Subdirectories)
        while it.hasNext():
            files.append(it.next())

        self.file_watch.addPaths(files)

        files = []
        it = QDirIterator(self.project.build_dir, QDirIterator.Subdirectories)
        while it.hasNext():
            files.append(it.next())

        self.build_file_watch.addPaths(files)

    def file_changed(self, path):
        self.modules_manager['compiler'].compile_all()

    def dir_changed(self, path):
        self.watch_project_dir()

    def build_file_changed(self, path):
        pass

    def build_dir_changed(self, path):
        pass

    def open_script_editor(self):
        self.script_editor_dock_widget.show()

    def open_recorded_events(self):
        self.modules_manager['profiler'].dock.show()

    def run_standalone(self):
        self.project.run_release("Standalone")

    def run_level(self):
        self.project.run_develop("Level", compile_=True, continue_=True, port=5566)

    def closeEvent(self, evnt):
        self.modules_manager.close_project()
        self.project.killall()
        evnt.accept()
コード例 #54
0
ファイル: window.py プロジェクト: zisecheng/retext
class ReTextWindow(QMainWindow):
	def __init__(self, parent=None):
		QMainWindow.__init__(self, parent)
		self.resize(950, 700)
		screenRect = QDesktopWidget().screenGeometry()
		if globalSettings.windowGeometry:
			self.restoreGeometry(globalSettings.windowGeometry)
		else:
			self.move((screenRect.width()-self.width())/2, (screenRect.height()-self.height())/2)
		if not screenRect.contains(self.geometry()):
			self.showMaximized()
		if globalSettings.iconTheme:
			QIcon.setThemeName(globalSettings.iconTheme)
		if QIcon.themeName() in ('hicolor', ''):
			if not QFile.exists(icon_path + 'document-new.png'):
				QIcon.setThemeName(get_icon_theme())
		if QFile.exists(icon_path+'retext.png'):
			self.setWindowIcon(QIcon(icon_path+'retext.png'))
		elif QFile.exists('/usr/share/pixmaps/retext.png'):
			self.setWindowIcon(QIcon('/usr/share/pixmaps/retext.png'))
		else:
			self.setWindowIcon(QIcon.fromTheme('retext',
				QIcon.fromTheme('accessories-text-editor')))
		self.editBoxes = []
		self.previewBoxes = []
		self.highlighters = []
		self.markups = []
		self.fileNames = []
		self.actionPreviewChecked = []
		self.actionLivePreviewChecked = []
		self.tabWidget = QTabWidget(self)
		self.initTabWidget()
		self.setCentralWidget(self.tabWidget)
		self.tabWidget.currentChanged.connect(self.changeIndex)
		self.tabWidget.tabCloseRequested.connect(self.closeTab)
		toolBar = QToolBar(self.tr('File toolbar'), self)
		self.addToolBar(Qt.TopToolBarArea, toolBar)
		self.editBar = QToolBar(self.tr('Edit toolbar'), self)
		self.addToolBar(Qt.TopToolBarArea, self.editBar)
		self.searchBar = QToolBar(self.tr('Search toolbar'), self)
		self.addToolBar(Qt.BottomToolBarArea, self.searchBar)
		toolBar.setVisible(not globalSettings.hideToolBar)
		self.editBar.setVisible(not globalSettings.hideToolBar)
		self.actionNew = self.act(self.tr('New'), 'document-new',
			self.createNew, shct=QKeySequence.New)
		self.actionNew.setPriority(QAction.LowPriority)
		self.actionOpen = self.act(self.tr('Open'), 'document-open',
			self.openFile, shct=QKeySequence.Open)
		self.actionOpen.setPriority(QAction.LowPriority)
		self.actionSetEncoding = self.act(self.tr('Set encoding'),
			trig=self.showEncodingDialog)
		self.actionSetEncoding.setEnabled(False)
		self.actionReload = self.act(self.tr('Reload'), 'view-refresh', trig=self.openFileMain)
		self.actionReload.setEnabled(False)
		self.actionSave = self.act(self.tr('Save'), 'document-save',
			self.saveFile, shct=QKeySequence.Save)
		self.actionSave.setEnabled(False)
		self.actionSave.setPriority(QAction.LowPriority)
		self.actionSaveAs = self.act(self.tr('Save as'), 'document-save-as',
			self.saveFileAs, shct=QKeySequence.SaveAs)
		self.actionNextTab = self.act(self.tr('Next tab'), 'go-next',
			lambda: self.switchTab(1), shct=Qt.CTRL+Qt.Key_PageDown)
		self.actionPrevTab = self.act(self.tr('Previous tab'), 'go-previous',
			lambda: self.switchTab(-1), shct=Qt.CTRL+Qt.Key_PageUp)
		self.actionPrint = self.act(self.tr('Print'), 'document-print',
			self.printFile, shct=QKeySequence.Print)
		self.actionPrint.setPriority(QAction.LowPriority)
		self.actionPrintPreview = self.act(self.tr('Print preview'), 'document-print-preview',
			self.printPreview)
		self.actionViewHtml = self.act(self.tr('View HTML code'), 'text-html', self.viewHtml)
		self.actionChangeEditorFont = self.act(self.tr('Change editor font'),
			trig=self.changeEditorFont)
		self.actionChangePreviewFont = self.act(self.tr('Change preview font'),
			trig=self.changePreviewFont)
		self.actionSearch = self.act(self.tr('Find text'), 'edit-find', shct=QKeySequence.Find)
		self.actionSearch.setCheckable(True)
		self.actionSearch.triggered[bool].connect(self.searchBar.setVisible)
		self.searchBar.visibilityChanged.connect(self.searchBarVisibilityChanged)
		self.actionPreview = self.act(self.tr('Preview'), shct=Qt.CTRL+Qt.Key_E,
			trigbool=self.preview)
		if QIcon.hasThemeIcon('document-preview'):
			self.actionPreview.setIcon(QIcon.fromTheme('document-preview'))
		elif QIcon.hasThemeIcon('preview-file'):
			self.actionPreview.setIcon(QIcon.fromTheme('preview-file'))
		elif QIcon.hasThemeIcon('x-office-document'):
			self.actionPreview.setIcon(QIcon.fromTheme('x-office-document'))
		else:
			self.actionPreview.setIcon(QIcon(icon_path+'document-preview.png'))
		self.actionLivePreview = self.act(self.tr('Live preview'), shct=Qt.CTRL+Qt.Key_L,
		trigbool=self.enableLivePreview)
		self.actionTableMode = self.act(self.tr('Table mode'), shct=Qt.CTRL+Qt.Key_T,
			trigbool=lambda x: self.editBoxes[self.ind].enableTableMode(x))
		if ReTextFakeVimHandler:
			self.actionFakeVimMode = self.act(self.tr('FakeVim mode'),
				shct=Qt.CTRL+Qt.ALT+Qt.Key_V, trigbool=self.enableFakeVimMode)
			if globalSettings.useFakeVim:
				self.actionFakeVimMode.setChecked(True)
				self.enableFakeVimMode(True)
		self.actionFullScreen = self.act(self.tr('Fullscreen mode'), 'view-fullscreen',
			shct=Qt.Key_F11, trigbool=self.enableFullScreen)
		self.actionFullScreen.setPriority(QAction.LowPriority)
		self.actionConfig = self.act(self.tr('Preferences'), icon='preferences-system',
			trig=self.openConfigDialog)
		self.actionConfig.setMenuRole(QAction.PreferencesRole)
		self.actionSaveHtml = self.act('HTML', 'text-html', self.saveFileHtml)
		self.actionPdf = self.act('PDF', 'application-pdf', self.savePdf)
		self.actionOdf = self.act('ODT', 'x-office-document', self.saveOdf)
		self.getExportExtensionsList()
		self.actionQuit = self.act(self.tr('Quit'), 'application-exit', shct=QKeySequence.Quit)
		self.actionQuit.setMenuRole(QAction.QuitRole)
		self.actionQuit.triggered.connect(self.close)
		self.actionUndo = self.act(self.tr('Undo'), 'edit-undo',
			lambda: self.editBoxes[self.ind].undo(), shct=QKeySequence.Undo)
		self.actionRedo = self.act(self.tr('Redo'), 'edit-redo',
			lambda: self.editBoxes[self.ind].redo(), shct=QKeySequence.Redo)
		self.actionCopy = self.act(self.tr('Copy'), 'edit-copy',
			lambda: self.editBoxes[self.ind].copy(), shct=QKeySequence.Copy)
		self.actionCut = self.act(self.tr('Cut'), 'edit-cut',
			lambda: self.editBoxes[self.ind].cut(), shct=QKeySequence.Cut)
		self.actionPaste = self.act(self.tr('Paste'), 'edit-paste',
			lambda: self.editBoxes[self.ind].paste(), shct=QKeySequence.Paste)
		self.actionUndo.setEnabled(False)
		self.actionRedo.setEnabled(False)
		self.actionCopy.setEnabled(False)
		self.actionCut.setEnabled(False)
		qApp = QApplication.instance()
		qApp.clipboard().dataChanged.connect(self.clipboardDataChanged)
		self.clipboardDataChanged()
		if enchant_available:
			self.actionEnableSC = self.act(self.tr('Enable'), trigbool=self.enableSpellCheck)
			self.actionSetLocale = self.act(self.tr('Set locale'), trig=self.changeLocale)
		self.actionWebKit = self.act(self.tr('Use WebKit renderer'), trigbool=self.enableWebKit)
		self.actionWebKit.setChecked(globalSettings.useWebKit)
		self.actionShow = self.act(self.tr('Show directory'), 'system-file-manager', self.showInDir)
		self.actionFind = self.act(self.tr('Next'), 'go-next', self.find,
			shct=QKeySequence.FindNext)
		self.actionFindPrev = self.act(self.tr('Previous'), 'go-previous',
			lambda: self.find(back=True), shct=QKeySequence.FindPrevious)
		self.actionHelp = self.act(self.tr('Get help online'), 'help-contents', self.openHelp)
		self.aboutWindowTitle = self.tr('About ReText')
		self.actionAbout = self.act(self.aboutWindowTitle, 'help-about', self.aboutDialog)
		self.actionAbout.setMenuRole(QAction.AboutRole)
		self.actionAboutQt = self.act(self.tr('About Qt'))
		self.actionAboutQt.setMenuRole(QAction.AboutQtRole)
		self.actionAboutQt.triggered.connect(qApp.aboutQt)
		availableMarkups = markups.get_available_markups()
		if not availableMarkups:
			print('Warning: no markups are available!')
		self.defaultMarkup = availableMarkups[0] if availableMarkups else None
		if globalSettings.defaultMarkup:
			mc = markups.find_markup_class_by_name(globalSettings.defaultMarkup)
			if mc and mc.available():
				self.defaultMarkup = mc
		if len(availableMarkups) > 1:
			self.chooseGroup = QActionGroup(self)
			markupActions = []
			for markup in availableMarkups:
				markupAction = self.act(markup.name, trigbool=self.markupFunction(markup))
				if markup == self.defaultMarkup:
					markupAction.setChecked(True)
				self.chooseGroup.addAction(markupAction)
				markupActions.append(markupAction)
		self.actionBold = self.act(self.tr('Bold'), shct=QKeySequence.Bold,
			trig=lambda: self.insertChars('**'))
		self.actionItalic = self.act(self.tr('Italic'), shct=QKeySequence.Italic,
			trig=lambda: self.insertChars('*'))
		self.actionUnderline = self.act(self.tr('Underline'), shct=QKeySequence.Underline,
			trig=lambda: self.insertTag('u'))
		self.usefulTags = ('a', 'big', 'center', 'img', 's', 'small', 'span',
			'table', 'td', 'tr', 'u')
		self.usefulChars = ('deg', 'divide', 'dollar', 'hellip', 'laquo', 'larr',
			'lsquo', 'mdash', 'middot', 'minus', 'nbsp', 'ndash', 'raquo',
			'rarr', 'rsquo', 'times')
		self.tagsBox = QComboBox(self.editBar)
		self.tagsBox.addItem(self.tr('Tags'))
		self.tagsBox.addItems(self.usefulTags)
		self.tagsBox.activated.connect(self.insertTag)
		self.symbolBox = QComboBox(self.editBar)
		self.symbolBox.addItem(self.tr('Symbols'))
		self.symbolBox.addItems(self.usefulChars)
		self.symbolBox.activated.connect(self.insertSymbol)
		self.updateStyleSheet()
		menubar = QMenuBar(self)
		menubar.setGeometry(QRect(0, 0, 800, 25))
		self.setMenuBar(menubar)
		menuFile = menubar.addMenu(self.tr('File'))
		menuEdit = menubar.addMenu(self.tr('Edit'))
		menuHelp = menubar.addMenu(self.tr('Help'))
		menuFile.addAction(self.actionNew)
		menuFile.addAction(self.actionOpen)
		self.menuRecentFiles = menuFile.addMenu(self.tr('Open recent'))
		self.menuRecentFiles.aboutToShow.connect(self.updateRecentFiles)
		menuFile.addMenu(self.menuRecentFiles)
		menuFile.addAction(self.actionShow)
		menuFile.addAction(self.actionSetEncoding)
		menuFile.addAction(self.actionReload)
		menuFile.addSeparator()
		menuFile.addAction(self.actionSave)
		menuFile.addAction(self.actionSaveAs)
		menuFile.addSeparator()
		menuFile.addAction(self.actionNextTab)
		menuFile.addAction(self.actionPrevTab)
		menuFile.addSeparator()
		menuExport = menuFile.addMenu(self.tr('Export'))
		menuExport.addAction(self.actionSaveHtml)
		menuExport.addAction(self.actionOdf)
		menuExport.addAction(self.actionPdf)
		if self.extensionActions:
			menuExport.addSeparator()
			for action, mimetype in self.extensionActions:
				menuExport.addAction(action)
			menuExport.aboutToShow.connect(self.updateExtensionsVisibility)
		menuFile.addAction(self.actionPrint)
		menuFile.addAction(self.actionPrintPreview)
		menuFile.addSeparator()
		menuFile.addAction(self.actionQuit)
		menuEdit.addAction(self.actionUndo)
		menuEdit.addAction(self.actionRedo)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionCut)
		menuEdit.addAction(self.actionCopy)
		menuEdit.addAction(self.actionPaste)
		menuEdit.addSeparator()
		if enchant_available:
			menuSC = menuEdit.addMenu(self.tr('Spell check'))
			menuSC.addAction(self.actionEnableSC)
			menuSC.addAction(self.actionSetLocale)
		menuEdit.addAction(self.actionSearch)
		menuEdit.addAction(self.actionChangeEditorFont)
		menuEdit.addAction(self.actionChangePreviewFont)
		menuEdit.addSeparator()
		if len(availableMarkups) > 1:
			self.menuMode = menuEdit.addMenu(self.tr('Default markup'))
			for markupAction in markupActions:
				self.menuMode.addAction(markupAction)
		menuFormat = menuEdit.addMenu(self.tr('Formatting'))
		menuFormat.addAction(self.actionBold)
		menuFormat.addAction(self.actionItalic)
		menuFormat.addAction(self.actionUnderline)
		menuEdit.addAction(self.actionWebKit)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionViewHtml)
		menuEdit.addAction(self.actionLivePreview)
		menuEdit.addAction(self.actionPreview)
		menuEdit.addAction(self.actionTableMode)
		if ReTextFakeVimHandler:
			menuEdit.addAction(self.actionFakeVimMode)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionFullScreen)
		menuEdit.addAction(self.actionConfig)
		menuHelp.addAction(self.actionHelp)
		menuHelp.addSeparator()
		menuHelp.addAction(self.actionAbout)
		menuHelp.addAction(self.actionAboutQt)
		menubar.addMenu(menuFile)
		menubar.addMenu(menuEdit)
		menubar.addMenu(menuHelp)
		toolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		toolBar.addAction(self.actionNew)
		toolBar.addSeparator()
		toolBar.addAction(self.actionOpen)
		toolBar.addAction(self.actionSave)
		toolBar.addAction(self.actionPrint)
		toolBar.addSeparator()
		toolBar.addAction(self.actionPreview)
		toolBar.addAction(self.actionFullScreen)
		self.editBar.addAction(self.actionUndo)
		self.editBar.addAction(self.actionRedo)
		self.editBar.addSeparator()
		self.editBar.addAction(self.actionCut)
		self.editBar.addAction(self.actionCopy)
		self.editBar.addAction(self.actionPaste)
		self.editBar.addSeparator()
		self.editBar.addWidget(self.tagsBox)
		self.editBar.addWidget(self.symbolBox)
		self.searchEdit = QLineEdit(self.searchBar)
		self.searchEdit.setPlaceholderText(self.tr('Search'))
		self.searchEdit.returnPressed.connect(self.find)
		self.csBox = QCheckBox(self.tr('Case sensitively'), self.searchBar)
		self.searchBar.addWidget(self.searchEdit)
		self.searchBar.addSeparator()
		self.searchBar.addWidget(self.csBox)
		self.searchBar.addAction(self.actionFindPrev)
		self.searchBar.addAction(self.actionFind)
		self.searchBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		self.searchBar.setVisible(False)
		self.autoSaveEnabled = globalSettings.autoSave
		if self.autoSaveEnabled:
			timer = QTimer(self)
			timer.start(60000)
			timer.timeout.connect(self.saveAll)
		self.ind = None
		if enchant_available:
			self.sl = globalSettings.spellCheckLocale
			if self.sl:
				try:
					enchant.Dict(self.sl)
				except Exception as e:
					print(e, file=sys.stderr)
					self.sl = None
			if globalSettings.spellCheck:
				self.actionEnableSC.setChecked(True)
				self.enableSpellCheck(True)
		self.fileSystemWatcher = QFileSystemWatcher()
		self.fileSystemWatcher.fileChanged.connect(self.fileChanged)

	def updateStyleSheet(self):
		if globalSettings.styleSheet:
			sheetfile = QFile(globalSettings.styleSheet)
			sheetfile.open(QIODevice.ReadOnly)
			self.ss = QTextStream(sheetfile).readAll()
			sheetfile.close()
		else:
			self.ss = ''

	def initTabWidget(self):
		def dragEnterEvent(e):
			e.acceptProposedAction()
		def dropEvent(e):
			fn = bytes(e.mimeData().data('text/plain')).decode().rstrip()
			if fn.startswith('file:'):
				fn = QUrl(fn).toLocalFile()
			self.openFileWrapper(fn)
		self.tabWidget.setTabsClosable(True)
		self.tabWidget.setAcceptDrops(True)
		self.tabWidget.dragEnterEvent = dragEnterEvent
		self.tabWidget.dropEvent = dropEvent

	def act(self, name, icon=None, trig=None, trigbool=None, shct=None):
		if not isinstance(shct, QKeySequence):
			shct = QKeySequence(shct)
		if icon:
			action = QAction(self.actIcon(icon), name, self)
		else:
			action = QAction(name, self)
		if trig:
			action.triggered.connect(trig)
		elif trigbool:
			action.setCheckable(True)
			action.triggered[bool].connect(trigbool)
		if shct:
			action.setShortcut(shct)
		return action

	def actIcon(self, name):
		return QIcon.fromTheme(name, QIcon(icon_path+name+'.png'))

	def printError(self):
		import traceback
		print('Exception occured while parsing document:', file=sys.stderr)
		traceback.print_exc()

	def getSplitter(self, index):
		splitter = QSplitter(Qt.Horizontal)
		# Give both boxes a minimum size so the minimumSizeHint will be
		# ignored when splitter.setSizes is called below
		for widget in self.editBoxes[index], self.previewBoxes[index]:
			widget.setMinimumWidth(125)
			splitter.addWidget(widget)
		splitter.setSizes((50, 50))
		splitter.setChildrenCollapsible(False)
		return splitter

	def getWebView(self):
		webView = QWebView()
		if not globalSettings.handleWebLinks:
			webView.page().setLinkDelegationPolicy(QWebPage.DelegateExternalLinks)
			webView.page().linkClicked.connect(QDesktopServices.openUrl)
		settings = webView.settings()
		settings.setAttribute(QWebSettings.LocalContentCanAccessFileUrls, False)
		settings.setDefaultTextEncoding('utf-8')
		return webView

	def createTab(self, fileName):
		self.previewBlocked = False
		self.editBoxes.append(ReTextEdit(self))
		self.highlighters.append(ReTextHighlighter(self.editBoxes[-1].document()))
		if enchant_available and self.actionEnableSC.isChecked():
			self.highlighters[-1].dictionary = \
			enchant.Dict(self.sl) if self.sl else enchant.Dict()
			self.highlighters[-1].rehighlight()
		if globalSettings.useWebKit:
			self.previewBoxes.append(self.getWebView())
		else:
			self.previewBoxes.append(QTextBrowser())
			self.previewBoxes[-1].setOpenExternalLinks(True)
		self.previewBoxes[-1].setVisible(False)
		self.fileNames.append(fileName)
		markupClass = self.getMarkupClass(fileName)
		self.markups.append(self.getMarkup(fileName))
		self.highlighters[-1].docType = (markupClass.name if markupClass else '')
		liveMode = globalSettings.restorePreviewState and globalSettings.previewState
		self.actionPreviewChecked.append(liveMode)
		self.actionLivePreviewChecked.append(liveMode)
		metrics = QFontMetrics(self.editBoxes[-1].font())
		self.editBoxes[-1].setTabStopWidth(globalSettings.tabWidth * metrics.width(' '))
		self.editBoxes[-1].textChanged.connect(self.updateLivePreviewBox)
		self.editBoxes[-1].undoAvailable.connect(self.actionUndo.setEnabled)
		self.editBoxes[-1].redoAvailable.connect(self.actionRedo.setEnabled)
		self.editBoxes[-1].copyAvailable.connect(self.enableCopy)
		self.editBoxes[-1].document().modificationChanged.connect(self.modificationChanged)
		if globalSettings.useFakeVim:
			self.installFakeVimHandler(self.editBoxes[-1])
		return self.getSplitter(-1)

	def closeTab(self, ind):
		if self.maybeSave(ind):
			if self.tabWidget.count() == 1:
				self.tabWidget.addTab(self.createTab(""), self.tr("New document"))
			if self.fileNames[ind]:
				self.fileSystemWatcher.removePath(self.fileNames[ind])
			del self.editBoxes[ind]
			del self.previewBoxes[ind]
			del self.highlighters[ind]
			del self.markups[ind]
			del self.fileNames[ind]
			del self.actionPreviewChecked[ind]
			del self.actionLivePreviewChecked[ind]
			self.tabWidget.removeTab(ind)

	def getMarkupClass(self, fileName=None):
		if fileName is None:
			fileName = self.fileNames[self.ind]
		if fileName:
			markupClass = markups.get_markup_for_file_name(
				fileName, return_class=True)
			if markupClass:
				return markupClass
		return self.defaultMarkup

	def getMarkup(self, fileName=None):
		if fileName is None:
			fileName = self.fileNames[self.ind]
		markupClass = self.getMarkupClass(fileName=fileName)
		if markupClass and markupClass.available():
			return markupClass(filename=fileName)

	def docTypeChanged(self):
		oldType = self.highlighters[self.ind].docType
		markupClass = self.getMarkupClass()
		newType = markupClass.name if markupClass else ''
		if oldType != newType:
			self.markups[self.ind] = self.getMarkup()
			self.updatePreviewBox()
			self.highlighters[self.ind].docType = newType
			self.highlighters[self.ind].rehighlight()
		dtMarkdown = (newType == DOCTYPE_MARKDOWN)
		dtMkdOrReST = (newType in (DOCTYPE_MARKDOWN, DOCTYPE_REST))
		self.tagsBox.setEnabled(dtMarkdown)
		self.symbolBox.setEnabled(dtMarkdown)
		self.actionUnderline.setEnabled(dtMarkdown)
		self.actionBold.setEnabled(dtMkdOrReST)
		self.actionItalic.setEnabled(dtMkdOrReST)
		canReload = bool(self.fileNames[self.ind]) and not self.autoSaveActive()
		self.actionSetEncoding.setEnabled(canReload)
		self.actionReload.setEnabled(canReload)

	def changeIndex(self, ind):
		if ind > -1:
			self.actionUndo.setEnabled(self.editBoxes[ind].document().isUndoAvailable())
			self.actionRedo.setEnabled(self.editBoxes[ind].document().isRedoAvailable())
			self.actionCopy.setEnabled(self.editBoxes[ind].textCursor().hasSelection())
			self.actionCut.setEnabled(self.editBoxes[ind].textCursor().hasSelection())
			self.actionPreview.setChecked(self.actionPreviewChecked[ind])
			self.actionLivePreview.setChecked(self.actionLivePreviewChecked[ind])
			self.actionTableMode.setChecked(self.editBoxes[ind].tableModeEnabled)
			self.editBar.setDisabled(self.actionPreviewChecked[ind])
		self.ind = ind
		if self.fileNames[ind]:
			self.setCurrentFile()
		else:
			self.setWindowTitle(self.tr('New document') + '[*]')
			self.docTypeChanged()
		self.modificationChanged(self.editBoxes[ind].document().isModified())
		if globalSettings.restorePreviewState:
			globalSettings.previewState = self.actionLivePreviewChecked[ind]
		if self.actionLivePreviewChecked[ind]:
			self.enableLivePreview(True)
		self.editBoxes[self.ind].setFocus(Qt.OtherFocusReason)

	def changeEditorFont(self):
		font, ok = QFontDialog.getFont(globalSettings.editorFont, self)
		if ok:
			globalSettings.editorFont = font
			for editor in self.editBoxes:
				editor.updateFont()

	def changePreviewFont(self):
		font, ok = QFontDialog.getFont(globalSettings.font, self)
		if ok:
			globalSettings.font = font
			self.updatePreviewBox()

	def preview(self, viewmode):
		self.actionPreviewChecked[self.ind] = viewmode
		if self.actionLivePreview.isChecked():
			self.actionLivePreview.setChecked(False)
			return self.enableLivePreview(False)
		self.editBar.setDisabled(viewmode)
		self.editBoxes[self.ind].setVisible(not viewmode)
		self.previewBoxes[self.ind].setVisible(viewmode)
		if viewmode:
			self.updatePreviewBox()

	def enableLivePreview(self, livemode):
		if globalSettings.restorePreviewState:
			globalSettings.previewState = livemode
		self.actionLivePreviewChecked[self.ind] = livemode
		self.actionPreviewChecked[self.ind] = livemode
		self.actionPreview.setChecked(livemode)
		self.editBar.setEnabled(True)
		self.previewBoxes[self.ind].setVisible(livemode)
		self.editBoxes[self.ind].setVisible(True)
		if livemode:
			self.updatePreviewBox()

	def enableWebKit(self, enable):
		globalSettings.useWebKit = enable
		oldind = self.ind
		self.tabWidget.clear()
		for self.ind in range(len(self.editBoxes)):
			if enable:
				self.previewBoxes[self.ind] = self.getWebView()
			else:
				self.previewBoxes[self.ind] = QTextBrowser()
				self.previewBoxes[self.ind].setOpenExternalLinks(True)
			splitter = self.getSplitter(self.ind)
			self.tabWidget.addTab(splitter, self.getDocumentTitle(baseName=True))
			self.updatePreviewBox()
			self.previewBoxes[self.ind].setVisible(self.actionPreviewChecked[self.ind])
		self.ind = oldind
		self.tabWidget.setCurrentIndex(self.ind)

	def enableCopy(self, copymode):
		self.actionCopy.setEnabled(copymode)
		self.actionCut.setEnabled(copymode)

	def enableFullScreen(self, yes):
		if yes:
			self.showFullScreen()
		else:
			self.showNormal()

	def openConfigDialog(self):
		dlg = ConfigDialog(self)
		dlg.setWindowTitle(self.tr('Preferences'))
		dlg.show()

	def installFakeVimHandler(self, editor):
		if ReTextFakeVimHandler:
			fakeVimEditor = ReTextFakeVimHandler(editor, self)
			fakeVimEditor.setSaveAction(self.actionSave)
			fakeVimEditor.setQuitAction(self.actionQuit)
			self.actionFakeVimMode.triggered.connect(fakeVimEditor.remove)

	def enableFakeVimMode(self, yes):
		globalSettings.useFakeVim = yes
		if yes:
			FakeVimMode.init(self)
			for editor in self.editBoxes:
				self.installFakeVimHandler(editor)
		else:
			FakeVimMode.exit(self)

	def enableSpellCheck(self, yes):
		if yes:
			if self.sl:
				self.setAllDictionaries(enchant.Dict(self.sl))
			else:
				self.setAllDictionaries(enchant.Dict())
		else:
			self.setAllDictionaries(None)
		globalSettings.spellCheck = yes

	def setAllDictionaries(self, dictionary):
		for hl in self.highlighters:
			hl.dictionary = dictionary
			hl.rehighlight()

	def changeLocale(self):
		if self.sl:
			localedlg = LocaleDialog(self, defaultText=self.sl)
		else:
			localedlg = LocaleDialog(self)
		if localedlg.exec() != QDialog.Accepted:
			return
		sl = localedlg.localeEdit.text()
		setdefault = localedlg.checkBox.isChecked()
		if sl:
			try:
				sl = str(sl)
				enchant.Dict(sl)
			except Exception as e:
				QMessageBox.warning(self, '', str(e))
			else:
				self.sl = sl
				self.enableSpellCheck(self.actionEnableSC.isChecked())
		else:
			self.sl = None
			self.enableSpellCheck(self.actionEnableSC.isChecked())
		if setdefault:
			globalSettings.spellCheckLocale = sl

	def searchBarVisibilityChanged(self, visible):
		self.actionSearch.setChecked(visible)
		if visible:
			self.searchEdit.setFocus(Qt.ShortcutFocusReason)

	def find(self, back=False):
		flags = QTextDocument.FindFlags()
		if back:
			flags |= QTextDocument.FindBackward
		if self.csBox.isChecked():
			flags |= QTextDocument.FindCaseSensitively
		text = self.searchEdit.text()
		editBox = self.editBoxes[self.ind]
		cursor = editBox.textCursor()
		newCursor = editBox.document().find(text, cursor, flags)
		if not newCursor.isNull():
			editBox.setTextCursor(newCursor)
			return self.setSearchEditColor(True)
		cursor.movePosition(QTextCursor.End if back else QTextCursor.Start)
		newCursor = editBox.document().find(text, cursor, flags)
		if not newCursor.isNull():
			editBox.setTextCursor(newCursor)
			return self.setSearchEditColor(True)
		self.setSearchEditColor(False)

	def setSearchEditColor(self, found):
		palette = self.searchEdit.palette()
		palette.setColor(QPalette.Active, QPalette.Base,
		                 Qt.white if found else QColor(255, 102, 102))
		self.searchEdit.setPalette(palette)

	def getHtml(self, includeStyleSheet=True, includeTitle=True,
	            includeMeta=False, webenv=False):
		if self.markups[self.ind] is None:
			markupClass = self.getMarkupClass()
			errMsg = self.tr('Could not parse file contents, check if '
			'you have the <a href="%s">necessary module</a> installed!')
			try:
				errMsg %= markupClass.attributes[MODULE_HOME_PAGE]
			except (AttributeError, KeyError):
				# Remove the link if markupClass doesn't have the needed attribute
				errMsg = errMsg.replace('<a href="%s">', '')
				errMsg = errMsg.replace('</a>', '')
			return '<p style="color: red">%s</p>' % errMsg
		text = self.editBoxes[self.ind].toPlainText()
		headers = ''
		if includeStyleSheet:
			headers += '<style type="text/css">\n' + self.ss + '</style>\n'
		cssFileName = self.getDocumentTitle(baseName=True)+'.css'
		if QFile(cssFileName).exists():
			headers += '<link rel="stylesheet" type="text/css" href="%s">\n' \
			% cssFileName
		if includeMeta:
			headers += ('<meta name="generator" content="ReText %s">\n' %
			            app_version)
		fallbackTitle = self.getDocumentTitle() if includeTitle else ''
		return self.markups[self.ind].get_whole_html(text,
			custom_headers=headers, include_stylesheet=includeStyleSheet,
			fallback_title=fallbackTitle, webenv=webenv)

	def updatePreviewBox(self):
		self.previewBlocked = False
		pb = self.previewBoxes[self.ind]
		textedit = isinstance(pb, QTextEdit)
		if textedit:
			scrollbar = pb.verticalScrollBar()
			disttobottom = scrollbar.maximum() - scrollbar.value()
		else:
			frame = pb.page().mainFrame()
			scrollpos = frame.scrollPosition()
		try:
			html = self.getHtml()
		except Exception:
			return self.printError()
		if textedit:
			pb.setHtml(html)
			pb.document().setDefaultFont(globalSettings.font)
			scrollbar.setValue(scrollbar.maximum() - disttobottom)
		else:
			pb.settings().setFontFamily(QWebSettings.StandardFont,
			                            globalSettings.font.family())
			pb.settings().setFontSize(QWebSettings.DefaultFontSize,
			                          globalSettings.font.pointSize())
			pb.setHtml(html, QUrl.fromLocalFile(self.fileNames[self.ind]))
			frame.setScrollPosition(scrollpos)

	def updateLivePreviewBox(self):
		if self.actionLivePreview.isChecked() and self.previewBlocked == False:
			self.previewBlocked = True
			QTimer.singleShot(1000, self.updatePreviewBox)

	def showInDir(self):
		if self.fileNames[self.ind]:
			path = QFileInfo(self.fileNames[self.ind]).path()
			QDesktopServices.openUrl(QUrl.fromLocalFile(path))
		else:
			QMessageBox.warning(self, '', self.tr("Please, save the file somewhere."))

	def setCurrentFile(self):
		self.setWindowTitle("")
		self.tabWidget.setTabText(self.ind, self.getDocumentTitle(baseName=True))
		self.setWindowFilePath(self.fileNames[self.ind])
		files = readListFromSettings("recentFileList")
		while self.fileNames[self.ind] in files:
			files.remove(self.fileNames[self.ind])
		files.insert(0, self.fileNames[self.ind])
		if len(files) > 10:
			del files[10:]
		writeListToSettings("recentFileList", files)
		QDir.setCurrent(QFileInfo(self.fileNames[self.ind]).dir().path())
		self.docTypeChanged()

	def createNew(self, text=None):
		self.tabWidget.addTab(self.createTab(""), self.tr("New document"))
		self.ind = self.tabWidget.count()-1
		self.tabWidget.setCurrentIndex(self.ind)
		if text:
			self.editBoxes[self.ind].textCursor().insertText(text)

	def switchTab(self, shift=1):
		self.tabWidget.setCurrentIndex((self.ind + shift) % self.tabWidget.count())

	def updateRecentFiles(self):
		self.menuRecentFiles.clear()
		self.recentFilesActions = []
		filesOld = readListFromSettings("recentFileList")
		files = []
		for f in filesOld:
			if QFile.exists(f):
				files.append(f)
				self.recentFilesActions.append(self.act(f, trig=self.openFunction(f)))
		writeListToSettings("recentFileList", files)
		for action in self.recentFilesActions:
			self.menuRecentFiles.addAction(action)

	def markupFunction(self, markup):
		return lambda: self.setDefaultMarkup(markup)

	def openFunction(self, fileName):
		return lambda: self.openFileWrapper(fileName)

	def extensionFuntion(self, data):
		return lambda: \
		self.runExtensionCommand(data['Exec'], data['FileFilter'], data['DefaultExtension'])

	def getExportExtensionsList(self):
		extensions = []
		for extsprefix in datadirs:
			extsdir = QDir(extsprefix+'/export-extensions/')
			if extsdir.exists():
				for fileInfo in extsdir.entryInfoList(['*.desktop', '*.ini'],
				QDir.Files | QDir.Readable):
					extensions.append(self.readExtension(fileInfo.filePath()))
		locale = QLocale.system().name()
		self.extensionActions = []
		for extension in extensions:
			try:
				if ('Name[%s]' % locale) in extension:
					name = extension['Name[%s]' % locale]
				elif ('Name[%s]' % locale.split('_')[0]) in extension:
					name = extension['Name[%s]' % locale.split('_')[0]]
				else:
					name = extension['Name']
				data = {}
				for prop in ('FileFilter', 'DefaultExtension', 'Exec'):
					if 'X-ReText-'+prop in extension:
						data[prop] = extension['X-ReText-'+prop]
					elif prop in extension:
						data[prop] = extension[prop]
					else:
						data[prop] = ''
				action = self.act(name, trig=self.extensionFuntion(data))
				if 'Icon' in extension:
					action.setIcon(self.actIcon(extension['Icon']))
				mimetype = extension['MimeType'] if 'MimeType' in extension else None
			except KeyError:
				print('Failed to parse extension: Name is required', file=sys.stderr)
			else:
				self.extensionActions.append((action, mimetype))

	def updateExtensionsVisibility(self):
		markupClass = self.getMarkupClass()
		for action in self.extensionActions:
			if markupClass is None:
				action[0].setEnabled(False)
				continue
			mimetype = action[1]
			if mimetype == None:
				enabled = True
			elif markupClass == markups.MarkdownMarkup:
				enabled = (mimetype in ("text/x-retext-markdown", "text/x-markdown"))
			elif markupClass == markups.ReStructuredTextMarkup:
				enabled = (mimetype in ("text/x-retext-rst", "text/x-rst"))
			else:
				enabled = False
			action[0].setEnabled(enabled)

	def readExtension(self, fileName):
		extFile = QFile(fileName)
		extFile.open(QIODevice.ReadOnly)
		extension = {}
		stream = QTextStream(extFile)
		while not stream.atEnd():
			line = stream.readLine()
			if '=' in line:
				index = line.index('=')
				extension[line[:index].rstrip()] = line[index+1:].lstrip()
		extFile.close()
		return extension

	def openFile(self):
		supportedExtensions = ['.txt']
		for markup in markups.get_all_markups():
			supportedExtensions += markup.file_extensions
		fileFilter = ' (' + str.join(' ', ['*'+ext for ext in supportedExtensions]) + ');;'
		fileNames = QFileDialog.getOpenFileNames(self,
			self.tr("Select one or several files to open"), "",
			self.tr("Supported files") + fileFilter + self.tr("All files (*)"))
		for fileName in fileNames[0]:
			self.openFileWrapper(fileName)

	def openFileWrapper(self, fileName):
		if not fileName:
			return
		fileName = QFileInfo(fileName).canonicalFilePath()
		exists = False
		for i in range(self.tabWidget.count()):
			if self.fileNames[i] == fileName:
				exists = True
				ex = i
		if exists:
			self.tabWidget.setCurrentIndex(ex)
		elif QFile.exists(fileName):
			noEmptyTab = (
				(self.ind is None) or
				self.fileNames[self.ind] or
				self.editBoxes[self.ind].toPlainText() or
				self.editBoxes[self.ind].document().isModified()
			)
			if noEmptyTab:
				self.tabWidget.addTab(self.createTab(fileName), "")
				self.ind = self.tabWidget.count()-1
				self.tabWidget.setCurrentIndex(self.ind)
			if fileName:
				self.fileSystemWatcher.addPath(fileName)
			self.fileNames[self.ind] = fileName
			self.openFileMain()

	def openFileMain(self, encoding=None):
		openfile = QFile(self.fileNames[self.ind])
		openfile.open(QIODevice.ReadOnly)
		stream = QTextStream(openfile)
		if encoding:
			stream.setCodec(encoding)
		elif globalSettings.defaultCodec:
			stream.setCodec(globalSettings.defaultCodec)
		text = stream.readAll()
		openfile.close()
		markupClass = markups.get_markup_for_file_name(
			self.fileNames[self.ind], return_class=True)
		self.highlighters[self.ind].docType = (markupClass.name if markupClass else '')
		self.markups[self.ind] = self.getMarkup()
		if self.defaultMarkup:
			self.highlighters[self.ind].docType = self.defaultMarkup.name
		editBox = self.editBoxes[self.ind]
		modified = bool(encoding) and (editBox.toPlainText() != text)
		editBox.setPlainText(text)
		self.setCurrentFile()
		editBox.document().setModified(modified)
		self.setWindowModified(modified)

	def showEncodingDialog(self):
		if not self.maybeSave(self.ind):
			return
		encoding, ok = QInputDialog.getItem(self, '',
			self.tr('Select file encoding from the list:'),
			[bytes(b).decode() for b in QTextCodec.availableCodecs()],
			0, False)
		if ok:
			self.openFileMain(encoding)

	def saveFile(self):
		self.saveFileMain(dlg=False)

	def saveFileAs(self):
		self.saveFileMain(dlg=True)

	def saveAll(self):
		oldind = self.ind
		for self.ind in range(self.tabWidget.count()):
			if self.fileNames[self.ind] and QFileInfo(self.fileNames[self.ind]).isWritable():
				self.saveFileCore(self.fileNames[self.ind])
				self.editBoxes[self.ind].document().setModified(False)
		self.ind = oldind

	def saveFileMain(self, dlg):
		if (not self.fileNames[self.ind]) or dlg:
			markupClass = self.getMarkupClass()
			if (markupClass is None) or not hasattr(markupClass, 'default_extension'):
				defaultExt = self.tr("Plain text (*.txt)")
				ext = ".txt"
			else:
				defaultExt = self.tr('%s files',
					'Example of final string: Markdown files') \
					% markupClass.name + ' (' + str.join(' ',
					('*'+extension for extension in markupClass.file_extensions)) + ')'
				if markupClass == markups.MarkdownMarkup:
					ext = globalSettings.markdownDefaultFileExtension
				elif markupClass == markups.ReStructuredTextMarkup:
					ext = globalSettings.restDefaultFileExtension
				else:
					ext = markupClass.default_extension
			newFileName = QFileDialog.getSaveFileName(self,
				self.tr("Save file"), "", defaultExt)[0]
			if newFileName:
				if not QFileInfo(newFileName).suffix():
					newFileName += ext
				if self.fileNames[self.ind]:
					self.fileSystemWatcher.removePath(self.fileNames[self.ind])
				self.fileNames[self.ind] = newFileName
				self.actionSetEncoding.setDisabled(self.autoSaveActive())
		if self.fileNames[self.ind]:
			result = self.saveFileCore(self.fileNames[self.ind])
			if result:
				self.setCurrentFile()
				self.editBoxes[self.ind].document().setModified(False)
				self.setWindowModified(False)
				return True
			else:
				QMessageBox.warning(self, '',
				self.tr("Cannot save to file because it is read-only!"))
		return False

	def saveFileCore(self, fn, addToWatcher=True):
		self.fileSystemWatcher.removePath(fn)
		savefile = QFile(fn)
		result = savefile.open(QIODevice.WriteOnly)
		if result:
			savestream = QTextStream(savefile)
			if globalSettings.defaultCodec:
				savestream.setCodec(globalSettings.defaultCodec)
			savestream << self.editBoxes[self.ind].toPlainText()
			savefile.close()
		if result and addToWatcher:
			self.fileSystemWatcher.addPath(fn)
		return result

	def saveHtml(self, fileName):
		if not QFileInfo(fileName).suffix():
			fileName += ".html"
		try:
			htmltext = self.getHtml(includeStyleSheet=False, includeMeta=True,
			webenv=True)
		except Exception:
			return self.printError()
		htmlFile = QFile(fileName)
		htmlFile.open(QIODevice.WriteOnly)
		html = QTextStream(htmlFile)
		if globalSettings.defaultCodec:
			html.setCodec(globalSettings.defaultCodec)
		html << htmltext
		htmlFile.close()

	def textDocument(self):
		td = QTextDocument()
		td.setMetaInformation(QTextDocument.DocumentTitle, self.getDocumentTitle())
		if self.ss:
			td.setDefaultStyleSheet(self.ss)
		td.setHtml(self.getHtml())
		td.setDefaultFont(globalSettings.font)
		return td

	def saveOdf(self):
		try:
			document = self.textDocument()
		except Exception:
			return self.printError()
		fileName = QFileDialog.getSaveFileName(self,
			self.tr("Export document to ODT"), "",
			self.tr("OpenDocument text files (*.odt)"))[0]
		if not QFileInfo(fileName).suffix():
			fileName += ".odt"
		writer = QTextDocumentWriter(fileName)
		writer.setFormat("odf")
		writer.write(document)

	def saveFileHtml(self):
		fileName = QFileDialog.getSaveFileName(self,
			self.tr("Save file"), "",
			self.tr("HTML files (*.html *.htm)"))[0]
		if fileName:
			self.saveHtml(fileName)

	def getDocumentForPrint(self):
		if globalSettings.useWebKit:
			return self.previewBoxes[self.ind]
		try:
			return self.textDocument()
		except Exception:
			self.printError()

	def standardPrinter(self):
		printer = QPrinter(QPrinter.HighResolution)
		printer.setDocName(self.getDocumentTitle())
		printer.setCreator('ReText %s' % app_version)
		return printer

	def savePdf(self):
		self.updatePreviewBox()
		fileName = QFileDialog.getSaveFileName(self,
			self.tr("Export document to PDF"),
			"", self.tr("PDF files (*.pdf)"))[0]
		if fileName:
			if not QFileInfo(fileName).suffix():
				fileName += ".pdf"
			printer = self.standardPrinter()
			printer.setOutputFormat(QPrinter.PdfFormat)
			printer.setOutputFileName(fileName)
			document = self.getDocumentForPrint()
			if document != None:
				document.print(printer)

	def printFile(self):
		self.updatePreviewBox()
		printer = self.standardPrinter()
		dlg = QPrintDialog(printer, self)
		dlg.setWindowTitle(self.tr("Print document"))
		if (dlg.exec() == QDialog.Accepted):
			document = self.getDocumentForPrint()
			if document != None:
				document.print(printer)

	def printPreview(self):
		document = self.getDocumentForPrint()
		if document == None:
			return
		printer = self.standardPrinter()
		preview = QPrintPreviewDialog(printer, self)
		preview.paintRequested.connect(document.print)
		preview.exec()

	def runExtensionCommand(self, command, filefilter, defaultext):
		of = ('%of' in command)
		html = ('%html' in command)
		if of:
			if defaultext and not filefilter:
				filefilter = '*'+defaultext
			fileName = QFileDialog.getSaveFileName(self,
				self.tr('Export document'), '', filefilter)[0]
			if not fileName:
				return
			if defaultext and not QFileInfo(fileName).suffix():
				fileName += defaultext
		basename = '.%s.retext-temp' % self.getDocumentTitle(baseName=True)
		if html:
			tmpname = basename+'.html'
			self.saveHtml(tmpname)
		else:
			tmpname = basename+self.getMarkupClass().default_extension
			self.saveFileCore(tmpname, addToWatcher=False)
		command = command.replace('%of', '"out'+defaultext+'"')
		command = command.replace('%html' if html else '%if', '"'+tmpname+'"')
		try:
			Popen(str(command), shell=True).wait()
		except Exception as error:
			errorstr = str(error)
			QMessageBox.warning(self, '', self.tr('Failed to execute the command:')
			+ '\n' + errorstr)
		QFile(tmpname).remove()
		if of:
			QFile('out'+defaultext).rename(fileName)

	def getDocumentTitle(self, baseName=False):
		markup = self.markups[self.ind]
		realTitle = ''
		if markup and not baseName:
			text = self.editBoxes[self.ind].toPlainText()
			try:
				realTitle = markup.get_document_title(text)
			except Exception:
				self.printError()
		if realTitle:
			return realTitle
		elif self.fileNames[self.ind]:
			fileinfo = QFileInfo(self.fileNames[self.ind])
			basename = fileinfo.completeBaseName()
			return (basename if basename else fileinfo.fileName())
		return self.tr("New document")

	def autoSaveActive(self):
		return self.autoSaveEnabled and self.fileNames[self.ind] and \
		QFileInfo(self.fileNames[self.ind]).isWritable()

	def modificationChanged(self, changed):
		if self.autoSaveActive():
			changed = False
		self.actionSave.setEnabled(changed)
		self.setWindowModified(changed)

	def clipboardDataChanged(self):
		mimeData = QApplication.instance().clipboard().mimeData()
		if mimeData is not None:
			self.actionPaste.setEnabled(mimeData.hasText())

	def insertChars(self, chars):
		tc = self.editBoxes[self.ind].textCursor()
		if tc.hasSelection():
			selection = tc.selectedText()
			if selection.startswith(chars) and selection.endswith(chars):
				if len(selection) > 2*len(chars):
					selection = selection[len(chars):-len(chars)]
					tc.insertText(selection)
			else:
				tc.insertText(chars+tc.selectedText()+chars)
		else:
			tc.insertText(chars)

	def insertTag(self, ut):
		if not ut:
			return
		if isinstance(ut, int):
			ut = self.usefulTags[ut - 1]
		arg = ' style=""' if ut == 'span' else ''
		tc = self.editBoxes[self.ind].textCursor()
		if ut == 'img':
			toinsert = ('<a href="' + tc.selectedText() +
			'" target="_blank"><img src="' + tc.selectedText() + '"/></a>')
		elif ut == 'a':
			toinsert = ('<a href="' + tc.selectedText() +
			'" target="_blank">' + tc.selectedText() + '</a>')
		else:
			toinsert = '<'+ut+arg+'>'+tc.selectedText()+'</'+ut+'>'
		tc.insertText(toinsert)
		self.tagsBox.setCurrentIndex(0)

	def insertSymbol(self, num):
		if num:
			self.editBoxes[self.ind].insertPlainText('&'+self.usefulChars[num-1]+';')
		self.symbolBox.setCurrentIndex(0)

	def fileChanged(self, fileName):
		ind = self.fileNames.index(fileName)
		self.tabWidget.setCurrentIndex(ind)
		if not QFile.exists(fileName):
			self.editBoxes[ind].document().setModified(True)
			QMessageBox.warning(self, '', self.tr(
				'This file has been deleted by other application.\n'
				'Please make sure you save the file before exit.'))
		elif not self.editBoxes[ind].document().isModified():
			# File was not modified in ReText, reload silently
			self.openFileMain()
			self.updatePreviewBox()
		else:
			text = self.tr(
				'This document has been modified by other application.\n'
				'Do you want to reload the file (this will discard all '
				'your changes)?\n')
			if self.autoSaveEnabled:
				text += self.tr(
					'If you choose to not reload the file, auto save mode will '
					'be disabled for this session to prevent data loss.')
			messageBox = QMessageBox(QMessageBox.Warning, '', text)
			reloadButton = messageBox.addButton(self.tr('Reload'), QMessageBox.YesRole)
			messageBox.addButton(QMessageBox.Cancel)
			messageBox.exec()
			if messageBox.clickedButton() is reloadButton:
				self.openFileMain()
				self.updatePreviewBox()
			else:
				self.autoSaveEnabled = False
				self.editBoxes[ind].document().setModified(True)
		if fileName not in self.fileSystemWatcher.files():
			# https://github.com/retext-project/retext/issues/137
			self.fileSystemWatcher.addPath(fileName)

	def maybeSave(self, ind):
		if self.autoSaveActive():
			self.saveFileCore(self.fileNames[self.ind])
			return True
		if not self.editBoxes[ind].document().isModified():
			return True
		self.tabWidget.setCurrentIndex(ind)
		ret = QMessageBox.warning(self, '',
			self.tr("The document has been modified.\nDo you want to save your changes?"),
			QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)
		if ret == QMessageBox.Save:
			return self.saveFileMain(False)
		elif ret == QMessageBox.Cancel:
			return False
		return True

	def closeEvent(self, closeevent):
		for self.ind in range(self.tabWidget.count()):
			if not self.maybeSave(self.ind):
				return closeevent.ignore()
		if globalSettings.saveWindowGeometry and not self.isMaximized():
			globalSettings.windowGeometry = self.saveGeometry()
		closeevent.accept()

	def viewHtml(self):
		htmlDlg = HtmlDialog(self)
		try:
			htmltext = self.getHtml(includeStyleSheet=False, includeTitle=False)
		except Exception:
			return self.printError()
		winTitle = self.getDocumentTitle(baseName=True)
		htmlDlg.setWindowTitle(winTitle+" ("+self.tr("HTML code")+")")
		htmlDlg.textEdit.setPlainText(htmltext.rstrip())
		htmlDlg.hl.rehighlight()
		htmlDlg.show()
		htmlDlg.raise_()
		htmlDlg.activateWindow()

	def openHelp(self):
		QDesktopServices.openUrl(QUrl('https://github.com/retext-project/retext/wiki'))

	def aboutDialog(self):
		QMessageBox.about(self, self.aboutWindowTitle,
		'<p><b>' + (self.tr('ReText %s (using PyMarkups %s)') % (app_version, markups.__version__))
		+'</b></p>' + self.tr('Simple but powerful editor'
		' for Markdown and reStructuredText')
		+'</p><p>'+self.tr('Author: Dmitry Shachnev, 2011').replace('2011', '2011\u2013' '2015')
		+'<br><a href="https://github.com/retext-project/retext">'+self.tr('Website')
		+'</a> | <a href="http://daringfireball.net/projects/markdown/syntax">'
		+self.tr('Markdown syntax')
		+'</a> | <a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html">'
		+self.tr('reStructuredText syntax')+'</a></p>')

	def setDefaultMarkup(self, markup):
		self.defaultMarkup = markup
		defaultName = markups.get_available_markups()[0].name
		writeToSettings('defaultMarkup', markup.name, defaultName)
		oldind = self.ind
		for self.ind in range(len(self.previewBoxes)):
			self.docTypeChanged()
		self.ind = oldind
コード例 #55
0
ファイル: ProjectBrowserModel.py プロジェクト: testmana2/test
class ProjectBrowserModel(BrowserModel):
    """
    Class implementing the project browser model.
    
    @signal vcsStateChanged(str) emitted after the VCS state has changed
    """
    vcsStateChanged = pyqtSignal(str)
    
    def __init__(self, parent):
        """
        Constructor
        
        @param parent reference to parent object (Project.Project)
        """
        super(ProjectBrowserModel, self).__init__(parent, nopopulate=True)
        
        rootData = self.tr("Name")
        self.rootItem = BrowserItem(None, rootData)
        self.rootItem.itemData.append(self.tr("VCS Status"))
        
        self.progDir = None
        self.project = parent
        
        self.watchedItems = {}
        self.watcher = QFileSystemWatcher(self)
        self.watcher.directoryChanged.connect(self.directoryChanged)
        
        self.inRefresh = False
        
        self.projectBrowserTypes = {
            "SOURCES": ProjectBrowserSourceType,
            "FORMS": ProjectBrowserFormType,
            "RESOURCES": ProjectBrowserResourceType,
            "INTERFACES": ProjectBrowserInterfaceType,
            "TRANSLATIONS": ProjectBrowserTranslationType,
            "OTHERS": ProjectBrowserOthersType,
        }
        
        self.colorNames = {
            "A": "VcsAdded",
            "M": "VcsModified",
            "O": "VcsRemoved",
            "R": "VcsReplaced",
            "U": "VcsUpdate",
            "Z": "VcsConflict",
        }
        self.itemBackgroundColors = {
            " ": QColor(),
            "A": Preferences.getProjectBrowserColour(self.colorNames["A"]),
            "M": Preferences.getProjectBrowserColour(self.colorNames["M"]),
            "O": Preferences.getProjectBrowserColour(self.colorNames["O"]),
            "R": Preferences.getProjectBrowserColour(self.colorNames["R"]),
            "U": Preferences.getProjectBrowserColour(self.colorNames["U"]),
            "Z": Preferences.getProjectBrowserColour(self.colorNames["Z"]),
        }
        
        self.highLightColor = \
            Preferences.getProjectBrowserColour("Highlighted")
        # needed by preferencesChanged()
        
        self.vcsStatusReport = {}
    
    def data(self, index, role):
        """
        Public method to get data of an item.
        
        @param index index of the data to retrieve (QModelIndex)
        @param role role of data (Qt.ItemDataRole)
        @return requested data
        """
        if not index.isValid():
            return None
        
        if role == Qt.TextColorRole:
            if index.column() == 0:
                try:
                    return index.internalPointer().getTextColor()
                except AttributeError:
                    return None
        elif role == Qt.BackgroundColorRole:
            try:
                col = self.itemBackgroundColors[
                    index.internalPointer().vcsState]
                if col.isValid():
                    return col
                else:
                    return None
            except AttributeError:
                return None
            except KeyError:
                return None
        
        return BrowserModel.data(self, index, role)
    
    def populateItem(self, parentItem, repopulate=False):
        """
        Public method to populate an item's subtree.
        
        @param parentItem reference to the item to be populated
        @param repopulate flag indicating a repopulation (boolean)
        """
        if parentItem.type() == ProjectBrowserItemSimpleDirectory:
            return  # nothing to do
        elif parentItem.type() == ProjectBrowserItemDirectory:
            self.populateProjectDirectoryItem(parentItem, repopulate)
        elif parentItem.type() == ProjectBrowserItemFile:
            self.populateFileItem(parentItem, repopulate)
        else:
            BrowserModel.populateItem(self, parentItem, repopulate)

    def populateProjectDirectoryItem(self, parentItem, repopulate=False):
        """
        Public method to populate a directory item's subtree.
        
        @param parentItem reference to the directory item to be populated
        @param repopulate flag indicating a repopulation (boolean)
        """
        self._addWatchedItem(parentItem)
        
        qdir = QDir(parentItem.dirName())
        
        if Preferences.getUI("BrowsersListHiddenFiles"):
            filter = QDir.Filters(QDir.AllEntries |
                                  QDir.Hidden |
                                  QDir.NoDotAndDotDot)
        else:
            filter = QDir.Filters(QDir.AllEntries | QDir.NoDot | QDir.NoDotDot)
        entryInfoList = qdir.entryInfoList(filter)
        
        if len(entryInfoList) > 0:
            if repopulate:
                self.beginInsertRows(self.createIndex(
                    parentItem.row(), 0, parentItem),
                    0, len(entryInfoList) - 1)
            states = {}
            if self.project.vcs is not None:
                for f in entryInfoList:
                    fname = f.absoluteFilePath()
                    states[os.path.normcase(fname)] = 0
                dname = parentItem.dirName()
                self.project.vcs.clearStatusCache()
                states = self.project.vcs.vcsAllRegisteredStates(states, dname)
            
            for f in entryInfoList:
                if f.isDir():
                    node = ProjectBrowserDirectoryItem(
                        parentItem,
                        Utilities.toNativeSeparators(f.absoluteFilePath()),
                        parentItem.getProjectTypes()[0], False)
                else:
                    node = ProjectBrowserFileItem(
                        parentItem,
                        Utilities.toNativeSeparators(f.absoluteFilePath()),
                        parentItem.getProjectTypes()[0])
                if self.project.vcs is not None:
                    fname = f.absoluteFilePath()
                    if states[os.path.normcase(fname)] == \
                            self.project.vcs.canBeCommitted:
                        node.addVcsStatus(self.project.vcs.vcsName())
                        self.project.clearStatusMonitorCachedState(
                            f.absoluteFilePath())
                    else:
                        node.addVcsStatus(self.tr("local"))
                self._addItem(node, parentItem)
            if repopulate:
                self.endInsertRows()

    def projectClosed(self):
        """
        Public method called after a project has been closed.
        """
        self.__vcsStatus = {}
        
        self.watchedItems = {}
        watchedDirs = self.watcher.directories()
        if watchedDirs:
            self.watcher.removePaths(watchedDirs)
        
        self.rootItem.removeChildren()
        self.beginResetModel()
        self.endResetModel()
        
        # reset the module parser cache
        Utilities.ModuleParser.resetParsedModules()
        
    def projectOpened(self):
        """
        Public method used to populate the model after a project has been
        opened.
        """
        self.__vcsStatus = {}
        states = {}
        keys = list(self.projectBrowserTypes.keys())[:]
        
        if self.project.vcs is not None:
            for key in keys:
                for fn in self.project.pdata[key]:
                    states[os.path.normcase(
                        os.path.join(self.project.ppath, fn))] = 0
            
            self.project.vcs.clearStatusCache()
            states = self.project.vcs.vcsAllRegisteredStates(
                states, self.project.ppath)
        
        self.inRefresh = True
        for key in keys:
            # Show the entry in bold in the others browser to make it more
            # distinguishable
            if key == "OTHERS":
                bold = True
            else:
                bold = False
            
            if key == "SOURCES":
                sourceLanguage = self.project.pdata["PROGLANGUAGE"][0]
            else:
                sourceLanguage = ""
            
            for fn in self.project.pdata[key]:
                fname = os.path.join(self.project.ppath, fn)
                parentItem, dt = self.findParentItemByName(
                    self.projectBrowserTypes[key], fn)
                if os.path.isdir(fname):
                    itm = ProjectBrowserDirectoryItem(
                        parentItem, fname, self.projectBrowserTypes[key],
                        False, bold)
                else:
                    itm = ProjectBrowserFileItem(
                        parentItem, fname, self.projectBrowserTypes[key],
                        False, bold, sourceLanguage=sourceLanguage)
                self._addItem(itm, parentItem)
                if self.project.vcs is not None:
                    if states[os.path.normcase(fname)] == \
                            self.project.vcs.canBeCommitted:
                        itm.addVcsStatus(self.project.vcs.vcsName())
                    else:
                        itm.addVcsStatus(self.tr("local"))
                else:
                    itm.addVcsStatus("")
        self.inRefresh = False
        self.beginResetModel()
        self.endResetModel()

    def findParentItemByName(self, type_, name, dontSplit=False):
        """
        Public method to find an item given its name.
        
        <b>Note</b>: This method creates all necessary parent items, if they
        don't exist.
        
        @param type_ type of the item
        @param name name of the item (string)
        @param dontSplit flag indicating the name should not be split (boolean)
        @return reference to the item found and the new display name (string)
        """
        if dontSplit:
            pathlist = []
            pathlist.append(name)
            pathlist.append("ignore_me")
        else:
            pathlist = re.split(r'/|\\', name)
        
        if len(pathlist) > 1:
            olditem = self.rootItem
            path = self.project.ppath
            for p in pathlist[:-1]:
                itm = self.findChildItem(p, 0, olditem)
                path = os.path.join(path, p)
                if itm is None:
                    itm = ProjectBrowserSimpleDirectoryItem(
                        olditem, type_, p, path)
                    self.__addVCSStatus(itm, path)
                    if self.inRefresh:
                        self._addItem(itm, olditem)
                    else:
                        if olditem == self.rootItem:
                            oldindex = QModelIndex()
                        else:
                            oldindex = self.createIndex(
                                olditem.row(), 0, olditem)
                        self.addItem(itm, oldindex)
                else:
                    if type_ and type_ not in itm.getProjectTypes():
                        itm.addProjectType(type_)
                        index = self.createIndex(itm.row(), 0, itm)
                        self.dataChanged.emit(index, index)
                olditem = itm
            return (itm, pathlist[-1])
        else:
            return (self.rootItem, name)
    
    def findChildItem(self, text, column, parentItem=None):
        """
        Public method to find a child item given some text.
        
        @param text text to search for (string)
        @param column column to search in (integer)
        @param parentItem reference to parent item
        @return reference to the item found
        """
        if parentItem is None:
            parentItem = self.rootItem
        
        for itm in parentItem.children():
            if itm.data(column) == text:
                return itm
        
        return None
        
    def addNewItem(self, typeString, name, additionalTypeStrings=[]):
        """
        Public method to add a new item to the model.
        
        @param typeString string denoting the type of the new item (string)
        @param name name of the new item (string)
        @param additionalTypeStrings names of additional types (list of string)
        """
        # Show the entry in bold in the others browser to make it more
        # distinguishable
        if typeString == "OTHERS":
            bold = True
        else:
            bold = False
        
        fname = os.path.join(self.project.ppath, name)
        parentItem, dt = self.findParentItemByName(
            self.projectBrowserTypes[typeString], name)
        if parentItem == self.rootItem:
            parentIndex = QModelIndex()
        else:
            parentIndex = self.createIndex(parentItem.row(), 0, parentItem)
        if os.path.isdir(fname):
            itm = ProjectBrowserDirectoryItem(
                parentItem, fname, self.projectBrowserTypes[typeString],
                False, bold)
        else:
            if typeString == "SOURCES":
                sourceLanguage = self.project.pdata["PROGLANGUAGE"][0]
            else:
                sourceLanguage = ""
            itm = ProjectBrowserFileItem(
                parentItem, fname, self.projectBrowserTypes[typeString],
                False, bold, sourceLanguage=sourceLanguage)
        self.__addVCSStatus(itm, fname)
        if additionalTypeStrings:
            for additionalTypeString in additionalTypeStrings:
                type_ = self.projectBrowserTypes[additionalTypeString]
                itm.addProjectType(type_)
        self.addItem(itm, parentIndex)
    
    def renameItem(self, name, newFilename):
        """
        Public method to rename an item.
        
        @param name the old display name (string)
        @param newFilename new filename of the item (string)
        """
        itm = self.findItem(name)
        if itm is None:
            return
        
        index = self.createIndex(itm.row(), 0, itm)
        itm.setName(newFilename)
        self.dataChanged.emit(index, index)
        self.repopulateItem(newFilename)
    
    def findItem(self, name):
        """
        Public method to find an item given its name.
        
        @param name name of the item (string)
        @return reference to the item found
        """
        if QDir.isAbsolutePath(name):
            name = self.project.getRelativePath(name)
        pathlist = re.split(r'/|\\', name)
        if len(pathlist) > 0:
            olditem = self.rootItem
            for p in pathlist:
                itm = self.findChildItem(p, 0, olditem)
                if itm is None:
                    return None
                olditem = itm
            return itm
        else:
            return None
    
    def itemIndexByName(self, name):
        """
        Public method to find an item's index given its name.
        
        @param name name of the item (string)
        @return index of the item found (QModelIndex)
        """
        itm = self.findItem(name)
        if itm is None:
            index = QModelIndex()
        else:
            index = self.createIndex(itm.row(), 0, itm)
        return index
    
    def itemIndexByNameAndLine(self, name, lineno):
        """
        Public method to find an item's index given its name.
        
        @param name name of the item (string)
        @param lineno one based line number of the item (integer)
        @return index of the item found (QModelIndex)
        """
        index = QModelIndex()
        itm = self.findItem(name)
        if itm is not None and \
           isinstance(itm, ProjectBrowserFileItem):
            olditem = itm
            autoPopulate = Preferences.getProject("AutoPopulateItems")
            while itm is not None:
                if not itm.isPopulated():
                    if itm.isLazyPopulated() and autoPopulate:
                        self.populateItem(itm)
                    else:
                        break
                for child in itm.children():
                    try:
                        start, end = child.boundaries()
                        if end == -1:
                            end = 1000000   # assume end of file
                        if start <= lineno <= end:
                            itm = child
                            break
                    except AttributeError:
                        pass
                else:
                    itm = None
                if itm:
                    olditem = itm
            index = self.createIndex(olditem.row(), 0, olditem)
        
        return index
    
    def directoryChanged(self, path):
        """
        Public slot to handle the directoryChanged signal of the watcher.
        
        @param path path of the directory (string)
        """
        if path not in self.watchedItems:
            # just ignore the situation we don't have a reference to the item
            return
        
        if Preferences.getUI("BrowsersListHiddenFiles"):
            filter = QDir.Filters(QDir.AllEntries |
                                  QDir.Hidden |
                                  QDir.NoDotAndDotDot)
        else:
            filter = QDir.Filters(QDir.AllEntries | QDir.NoDot | QDir.NoDotDot)
        
        for itm in self.watchedItems[path]:
            oldCnt = itm.childCount()
            
            qdir = QDir(itm.dirName())
            
            entryInfoList = qdir.entryInfoList(filter)
            
            # step 1: check for new entries
            children = itm.children()
            for f in entryInfoList:
                fpath = Utilities.toNativeSeparators(f.absoluteFilePath())
                childFound = False
                for child in children:
                    if child.name() == fpath:
                        childFound = True
                        children.remove(child)
                        break
                if childFound:
                    continue
                
                cnt = itm.childCount()
                self.beginInsertRows(
                    self.createIndex(itm.row(), 0, itm), cnt, cnt)
                if f.isDir():
                    node = ProjectBrowserDirectoryItem(
                        itm,
                        Utilities.toNativeSeparators(f.absoluteFilePath()),
                        itm.getProjectTypes()[0],
                        False)
                else:
                    node = ProjectBrowserFileItem(
                        itm,
                        Utilities.toNativeSeparators(f.absoluteFilePath()),
                        itm.getProjectTypes()[0])
                self._addItem(node, itm)
                if self.project.vcs is not None:
                    self.project.vcs.clearStatusCache()
                    state = self.project.vcs.vcsRegisteredState(node.name())
                    if state == self.project.vcs.canBeCommitted:
                        node.addVcsStatus(self.project.vcs.vcsName())
                    else:
                        node.addVcsStatus(self.tr("local"))
                self.endInsertRows()
            
            # step 2: check for removed entries
            if len(entryInfoList) != itm.childCount():
                for row in range(oldCnt - 1, -1, -1):
                    child = itm.child(row)
                    childname = Utilities.fromNativeSeparators(child.name())
                    entryFound = False
                    for f in entryInfoList:
                        if f.absoluteFilePath() == childname:
                            entryFound = True
                            entryInfoList.remove(f)
                            break
                    if entryFound:
                        continue
                    
                    self._removeWatchedItem(child)
                    self.beginRemoveRows(
                        self.createIndex(itm.row(), 0, itm), row, row)
                    itm.removeChild(child)
                    self.endRemoveRows()
    
    def __addVCSStatus(self, item, name):
        """
        Private method used to set the vcs status of a node.
        
        @param item item to work on
        @param name filename belonging to this item (string)
        """
        if self.project.vcs is not None:
            state = self.project.vcs.vcsRegisteredState(name)
            if state == self.project.vcs.canBeCommitted:
                item.addVcsStatus(self.project.vcs.vcsName())
            else:
                item.addVcsStatus(self.tr("local"))
        else:
            item.addVcsStatus("")
    
    def __updateVCSStatus(self, item, name, recursive=True):
        """
        Private method used to update the vcs status of a node.
        
        @param item item to work on
        @param name filename belonging to this item (string)
        @keyparam recursive flag indicating a recursive update (boolean)
        """
        if self.project.vcs is not None:
            self.project.vcs.clearStatusCache()
            state = self.project.vcs.vcsRegisteredState(name)
            if state == self.project.vcs.canBeCommitted:
                item.setVcsStatus(self.project.vcs.vcsName())
            else:
                item.setVcsStatus(self.tr("local"))
            if recursive:
                name = os.path.dirname(name)
                parentItem = item.parent()
                if name and parentItem is not self.rootItem:
                    self.__updateVCSStatus(parentItem, name, recursive)
        else:
            item.setVcsStatus("")
        
        index = self.createIndex(item.row(), 0, item)
        self.dataChanged.emit(index, index)
    
    def updateVCSStatus(self, name, recursive=True):
        """
        Public method used to update the vcs status of a node.
        
        @param name filename belonging to this item (string)
        @param recursive flag indicating a recursive update (boolean)
        """
        item = self.findItem(name)
        if item:
            self.__updateVCSStatus(item, name, recursive)
    
    def removeItem(self, name):
        """
        Public method to remove a named item.
        
        @param name file or directory name of the item (string).
        """
        fname = os.path.basename(name)
        parentItem = self.findParentItemByName(0, name)[0]
        if parentItem == self.rootItem:
            parentIndex = QModelIndex()
        else:
            parentIndex = self.createIndex(parentItem.row(), 0, parentItem)
        childItem = self.findChildItem(fname, 0, parentItem)
        if childItem is not None:
            self.beginRemoveRows(parentIndex, childItem.row(), childItem.row())
            parentItem.removeChild(childItem)
            self.endRemoveRows()
    
    def repopulateItem(self, name):
        """
        Public method to repopulate an item.
        
        @param name name of the file relative to the project root (string)
        """
        itm = self.findItem(name)
        if itm is None:
            return
        
        if itm.isLazyPopulated():
            if not itm.isPopulated():
                # item is not populated yet, nothing to do
                return
            
            if itm.childCount():
                index = self.createIndex(itm.row(), 0, itm)
                self.beginRemoveRows(index, 0, itm.childCount() - 1)
                itm.removeChildren()
                self.endRemoveRows()
            Utilities.ModuleParser.resetParsedModule(
                os.path.join(self.project.ppath, name))
            
            self.populateItem(itm, True)
    
    def projectPropertiesChanged(self):
        """
        Public method to react on a change of the project properties.
        """
        # nothing to do for now
        return

    def changeVCSStates(self, statesList):
        """
        Public slot to record the (non normal) VCS states.
        
        @param statesList list of VCS state entries (list of strings) giving
            the states in the first column and the path relative to the project
            directory starting with the third column. The allowed status flags
            are:
            <ul>
                <li>"A" path was added but not yet comitted</li>
                <li>"M" path has local changes</li>
                <li>"O" path was removed</li>
                <li>"R" path was deleted and then re-added</li>
                <li>"U" path needs an update</li>
                <li>"Z" path contains a conflict</li>
                <li>" " path is back at normal</li>
            </ul>
        """
        statesList.sort()
        lastHead = ""
        itemCache = {}
        if len(statesList) == 1 and statesList[0] == '--RESET--':
            statesList = []
            for name in list(self.__vcsStatus.keys()):
                statesList.append(" {0}".format(name))
        
        for name in statesList:
            state = name[0]
            name = name[1:].strip()
            if state == ' ':
                if name in self.__vcsStatus:
                    del self.__vcsStatus[name]
            else:
                self.__vcsStatus[name] = state
            
            try:
                itm = itemCache[name]
            except KeyError:
                itm = self.findItem(name)
                if itm:
                    itemCache[name] = itm
            if itm:
                itm.setVcsState(state)
                itm.setVcsStatus(self.project.vcs.vcsName())
                index1 = self.createIndex(itm.row(), 0, itm)
                index2 = self.createIndex(
                    itm.row(), self.rootItem.columnCount(), itm)
                self.dataChanged.emit(index1, index2)
            
            head, tail = os.path.split(name)
            if head != lastHead:
                if lastHead:
                    self.__changeParentsVCSState(lastHead, itemCache)
                lastHead = head
        if lastHead:
            self.__changeParentsVCSState(lastHead, itemCache)
        try:
            globalVcsStatus = sorted(self.__vcsStatus.values())[-1]
        except IndexError:
            globalVcsStatus = ' '
        self.vcsStateChanged.emit(globalVcsStatus)

    def __changeParentsVCSState(self, path, itemCache):
        """
        Private method to recursively change the parents VCS state.
        
        @param path pathname of parent item (string)
        @param itemCache reference to the item cache used to store
            references to named items
        """
        while path:
            try:
                itm = itemCache[path]
            except KeyError:
                itm = self.findItem(path)
                if itm:
                    itemCache[path] = itm
            if itm:
                state = " "
                for id_ in itm.children():
                    if state < id_.vcsState:
                        state = id_.vcsState
                if state != itm.vcsState:
                    itm.setVcsState(state)
                    index1 = self.createIndex(itm.row(), 0, itm)
                    index2 = self.createIndex(
                        itm.row(), self.rootItem.columnCount(), itm)
                    self.dataChanged.emit(index1, index2)
            path, tail = os.path.split(path)
    
    def preferencesChanged(self):
        """
        Public method used to handle a change in preferences.
        """
        for code in list(self.colorNames.keys()):
            color = Preferences.getProjectBrowserColour(self.colorNames[code])
            if color.name() == self.itemBackgroundColors[code].name():
                continue
            
            self.itemBackgroundColors[code] = color
        
        color = Preferences.getProjectBrowserColour("Highlighted")
        if self.highLightColor.name() != color.name():
            self.highLightColor = color
コード例 #56
0
ファイル: documents.py プロジェクト: mbarbon/pugdebug
    def __init__(self):
        super(PugdebugDocuments, self).__init__()

        self.watcher = QFileSystemWatcher()
        self.watcher.fileChanged.connect(self.handle_file_changed)
コード例 #57
0
ファイル: mainwindow.py プロジェクト: gitter-badger/cetech
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)

        self.centralwidget.hide()

        self.parser = argparse.ArgumentParser("playground")
        self.parser.add_argument("-d", "--data-dir", type=str, help="data dir")
        self.parser.add_argument("-a", "--console-address", type=str, help="console address", default='localhost')
        self.parser.add_argument("-p", "--console-port", type=int, help="console port", default=2222)
        self.args = self.parser.parse_args()

        self.data_dir = self.args.data_dir
        self.console_port = self.args.console_port
        self.console_address = self.args.console_address

        self.project = CetechProject()

        self.api = QtConsoleAPI(self.console_address, self.console_port)

        self.setTabPosition(Qt.AllDockWidgetAreas, QTabWidget.North)

        self.script_editor_widget = ScriptEditor(project_manager=self.project, api=self.api)
        self.script_editor_dock_widget = QDockWidget(self)
        self.script_editor_dock_widget.setWindowTitle("Script editor")
        self.script_editor_dock_widget.hide()
        self.script_editor_dock_widget.setFeatures(QDockWidget.AllDockWidgetFeatures)
        self.script_editor_dock_widget.setWidget(self.script_editor_widget)
        self.addDockWidget(Qt.TopDockWidgetArea, self.script_editor_dock_widget)

        self.log_widget = LogWidget(self.api, self.script_editor_widget)
        self.log_dock_widget = QDockWidget(self)
        self.log_dock_widget.hide()
        self.log_dock_widget.setWindowTitle("Log")
        self.log_dock_widget.setWidget(self.log_widget)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.log_dock_widget)

        self.assetb_widget = AssetBrowser()
        self.assetb_dock_widget = QDockWidget(self)
        self.assetb_dock_widget.hide()
        self.assetb_dock_widget.setWindowTitle("Asset browser")
        self.assetb_dock_widget.setFeatures(QDockWidget.AllDockWidgetFeatures)
        self.assetb_dock_widget.setWidget(self.assetb_widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.assetb_dock_widget)

        self.recorded_event_widget = RecordEventWidget(api=self.api)
        self.recorded_event_dock_widget = QDockWidget(self)
        self.recorded_event_dock_widget.setWindowTitle("Recorded events")
        self.recorded_event_dock_widget.hide()
        self.recorded_event_dock_widget.setFeatures(QDockWidget.AllDockWidgetFeatures)
        self.recorded_event_dock_widget.setWidget(self.recorded_event_widget)
        self.addDockWidget(Qt.RightDockWidgetArea, self.recorded_event_dock_widget)

        #TODO bug #114 workaround. Disable create sub engine...
        if platform.system().lower() != 'darwin':
            self.ogl_widget = CetechWidget(self, self.api)
            self.ogl_dock = QDockWidget(self)
            self.ogl_dock.hide()
            self.ogl_dock.setWidget(self.ogl_widget)
            self.addDockWidget(Qt.TopDockWidgetArea, self.ogl_dock)

        self.tabifyDockWidget(self.assetb_dock_widget, self.log_dock_widget)

        self.assetb_widget.asset_clicked.connect(self.open_asset)

        self.file_watch = QFileSystemWatcher(self)
        self.file_watch.fileChanged.connect(self.file_changed)
        self.file_watch.directoryChanged.connect(self.dir_changed)

        self.build_file_watch = QFileSystemWatcher(self)
        self.build_file_watch.fileChanged.connect(self.build_file_changed)
        self.build_file_watch.directoryChanged.connect(self.build_dir_changed)

    def open_asset(self, path, ext):
        if self.script_editor_widget.support_ext(ext):
            self.script_editor_widget.open_file(path)
            self.script_editor_dock_widget.show()
            self.script_editor_dock_widget.focusWidget()

    def open_project(self, name, dir):
        self.project.open_project(name, dir)

        # self.project.run_cetech(build_type=CetechProject.BUILD_DEBUG, compile=True, continu=True, daemon=True)

        if platform.system().lower() == 'darwin':
            wid = None
        else:
            wid = self.ogl_widget.winId()

        self.project.run_cetech(build_type=CetechProject.BUILD_DEBUG, compile_=True, continue_=True,
                                wid=wid)


        self.api.start(QThread.LowPriority)

        self.assetb_widget.open_project(self.project.project_dir)
        self.assetb_dock_widget.show()
        self.log_dock_widget.show()

        #TODO bug #114 workaround. Disable create sub engine...
        if platform.system().lower() != 'darwin':
            self.ogl_dock.show()

        self.watch_project_dir()

    def watch_project_dir(self):
        files = self.file_watch.files()
        directories = self.file_watch.directories()

        if len(files):
            self.file_watch.removePaths(files)

        if len(directories):
            self.file_watch.removePaths(directories)

        files = self.build_file_watch.files()
        directories = self.build_file_watch.directories()

        if len(files):
            self.build_file_watch.removePaths(files)

        if len(directories):
            self.build_file_watch.removePaths(directories)

        files = []
        it = QDirIterator(self.project.source_dir, QDirIterator.Subdirectories)
        while it.hasNext():
            files.append(it.next())

        self.file_watch.addPaths(files)

        files = []
        it = QDirIterator(self.project.build_dir, QDirIterator.Subdirectories)
        while it.hasNext():
            files.append(it.next())

        self.build_file_watch.addPaths(files)

    def file_changed(self, path):
        self.api.compile_all()

    def dir_changed(self, path):
        self.watch_project_dir()

    def build_file_changed(self, path):
        self.api.autocomplete_list()

    def build_dir_changed(self, path):
        pass

    def open_script_editor(self):
        self.script_editor_dock_widget.show()

    def open_recorded_events(self):
        self.recorded_event_dock_widget.show()

    def closeEvent(self, evnt):
        self.api.disconnect()

        self.project.killall_process()

        self.statusbar.showMessage("Disconnecting ...")

        while self.api.connected:
            self.api.tick()

        self.statusbar.showMessage("Disconnected")

        evnt.accept()
コード例 #58
0
    def __init__(self, **kwds):
        super(ExecuteOptionsPlugin, self).__init__(**kwds)

        self._preferences.addInt("execute/maxRecentWorkingDirs",
                "Max recent working directories",
                10,
                1,
                50,
                "Set the maximum number of recent working directories that have been used.",
                )
        self._preferences.addInt("execute/maxRecentExes",
                "Max recent executables",
                10,
                1,
                50,
                "Set the maximum number of recent executables that have been used.",
                )
        self._preferences.addInt("execute/maxRecentArgs",
                "Max recent command line arguments",
                10,
                1,
                50,
                "Set the maximum number of recent command line arguments that have been used.",
                )
        self._preferences.addBool("execute/allowTestObjects",
                "Allow using test objects",
                False,
                "Allow using test objects by default",
                )
        self._preferences.addBool("execute/mpiEnabled",
                "Enable MPI by default",
                False,
                "Set the MPI checkbox on by default",
                )
        self._preferences.addString("execute/mpiArgs",
                "Default mpi command",
                "mpiexec -n 2",
                "Set the default MPI command to run",
                )
        self._preferences.addBool("execute/threadsEnabled",
                "Enable threads by default",
                False,
                "Set the threads checkbox on by default",
                )
        self._preferences.addString("execute/threadsArgs",
                "Default threads arguments",
                "--n-threads=2",
                "Set the default threads arguments",
                )

        self.all_exe_layout = WidgetUtils.addLayout(grid=True)
        self.setLayout(self.all_exe_layout)

        self.working_label = WidgetUtils.addLabel(None, self, "Working Directory")
        self.all_exe_layout.addWidget(self.working_label, 0, 0)
        self.choose_working_button = WidgetUtils.addButton(None, self, "Choose", self._chooseWorkingDir)
        self.all_exe_layout.addWidget(self.choose_working_button, 0, 1)
        self.working_line = WidgetUtils.addLineEdit(None, self, None, readonly=True)
        self.working_line.setText(os.getcwd())
        self.all_exe_layout.addWidget(self.working_line, 0, 2)

        self.exe_label = WidgetUtils.addLabel(None, self, "Executable")
        self.all_exe_layout.addWidget(self.exe_label, 1, 0)
        self.choose_exe_button = WidgetUtils.addButton(None, self, "Choose", self._chooseExecutable)
        self.all_exe_layout.addWidget(self.choose_exe_button, 1, 1)
        self.exe_line = WidgetUtils.addLineEdit(None, self, None, readonly=True)
        self.all_exe_layout.addWidget(self.exe_line, 1, 2)

        self.args_label = WidgetUtils.addLabel(None, self, "Extra Arguments")
        self.all_exe_layout.addWidget(self.args_label, 2, 0)
        self.args_line = WidgetUtils.addLineEdit(None, self, None)
        self.all_exe_layout.addWidget(self.args_line, 2, 2)

        self.test_label = WidgetUtils.addLabel(None, self, "Allow test objects")
        self.all_exe_layout.addWidget(self.test_label, 3, 0)
        self.test_checkbox = WidgetUtils.addCheckbox(None, self, "", self._allowTestObjects)
        self.test_checkbox.setChecked(self._preferences.value("execute/allowTestObjects"))
        self.all_exe_layout.addWidget(self.test_checkbox, 3, 1, alignment=Qt.AlignHCenter)

        self.mpi_label = WidgetUtils.addLabel(None, self, "Use MPI")
        self.all_exe_layout.addWidget(self.mpi_label, 4, 0)
        self.mpi_checkbox = WidgetUtils.addCheckbox(None, self, "", None)
        self.mpi_checkbox.setChecked(self._preferences.value("execute/mpiEnabled"))
        self.all_exe_layout.addWidget(self.mpi_checkbox, 4, 1, alignment=Qt.AlignHCenter)
        self.mpi_line = WidgetUtils.addLineEdit(None, self, None)
        self.mpi_line.setText(self._preferences.value("execute/mpiArgs"))
        self.mpi_line.cursorPositionChanged.connect(self._mpiLineCursorChanged)
        self.all_exe_layout.addWidget(self.mpi_line, 4, 2)

        self.threads_label = WidgetUtils.addLabel(None, self, "Use Threads")
        self.all_exe_layout.addWidget(self.threads_label, 5, 0)
        self.threads_checkbox = WidgetUtils.addCheckbox(None, self, "", None)
        self.threads_checkbox.setChecked(self._preferences.value("execute/threadsEnabled"))
        self.all_exe_layout.addWidget(self.threads_checkbox, 5, 1, alignment=Qt.AlignHCenter)
        self.threads_line = WidgetUtils.addLineEdit(None, self, None)
        self.threads_line.setText(self._preferences.value("execute/threadsArgs"))
        self.threads_line.cursorPositionChanged.connect(self._threadsLineCursorChanged)
        self.all_exe_layout.addWidget(self.threads_line, 5, 2)

        self.csv_label = WidgetUtils.addLabel(None, self, "Postprocessor CSV Output")
        self.all_exe_layout.addWidget(self.csv_label, 6, 0)
        self.csv_checkbox = WidgetUtils.addCheckbox(None, self, "", None)
        self.all_exe_layout.addWidget(self.csv_checkbox, 6, 1, alignment=Qt.AlignHCenter)
        self.csv_checkbox.setCheckState(Qt.Checked)

        self.recover_label = WidgetUtils.addLabel(None, self, "Recover")
        self.all_exe_layout.addWidget(self.recover_label, 7, 0)
        self.recover_checkbox = WidgetUtils.addCheckbox(None, self, "", None)
        self.all_exe_layout.addWidget(self.recover_checkbox, 7, 1, alignment=Qt.AlignHCenter)

        self._recent_exe_menu = None
        self._recent_working_menu = None
        self._recent_args_menu = None
        self._exe_watcher = QFileSystemWatcher()
        self._exe_watcher.fileChanged.connect(self.setExecutablePath)

        self._loading_dialog = QMessageBox(parent=self)
        self._loading_dialog.setWindowTitle("Loading executable")
        self._loading_dialog.setStandardButtons(QMessageBox.NoButton) # get rid of the OK button
        self._loading_dialog.setWindowModality(Qt.ApplicationModal)
        self._loading_dialog.setIcon(QMessageBox.Information)
        self._loading_dialog.setText("Loading executable")

        self.setup()