예제 #1
0
def main(script_file=__file__,version="",commitdate="",builddate=""):

    if os.name == 'nt':
        path_base = os.path.join(os.getenv('APPDATA'),"explor")
    else:
        path_base = os.path.expanduser("~/.config/explor")

    initSettings(path_base)
    args = parse_args(script_file)

    initYmlSettings(path_base)

    app = QApplication(sys.argv)
    app.setApplicationName("explor")

    app.setQuitOnLastWindowClosed(True)
    app_icon = QIcon(':/img/icon_explor.png')
    app.setWindowIcon(app_icon)

    installExceptionHook()

    ResourceManager.instance().load()

    version_info = (version,commitdate,builddate)
    window = MainWindow(version_info,args.path,args.path_r)
    window.showWindow()

    sys.exit(app.exec_())
예제 #2
0
    def item2img(self,item):

        l = ResourceManager.LINK if item['isLink'] else 0
        if item['isDir']:
            return ResourceManager.instance().get(l|ResourceManager.DIRECTORY)

        _,ext = self.view.splitext(item['name'])
        return ResourceManager.instance().get(l|ResourceManager.instance().getExtType(ext))
예제 #3
0
    def initColumns(self):
        """
        self.columns.append( TableColumnImage(self,'isDir',"Icon") )
        self.columns[-1].setShortName("")
        self.columns[-1].setTextTransform( lambda item,_ : self.item2img(item) )
        self.columns[-1].width = ResourceManager.instance().width() + 4 # arbitrary pad, image is centered

        self.columns.append( TableDualColumn(self,'name',"File Name") )
        self.columns[-1].setSecondaryTextTransform(lambda r,item : format_bytes(r['size']))
        """
        self.columns.append(TableColumnImage(self, 'type', "Icon"))
        self.columns[-1].setShortName("")
        self.columns[-1].setTextTransform(lambda item, _: self.item2img(item))
        self.columns[-1].width = ResourceManager.instance().width(
        ) + 4  # arbitrary pad, image is centered

        self.columns.append(EditTextColumn(self, 'name', "File Name"))
        self.columns[-1].setWidthByCharCount(35)
        self.columns[-1].commitText.connect(self._onCommitText)
        self.columns[-1].createFile.connect(self._onCreateFile)
        self.columns[-1].createDirectory.connect(self._onCreateDirectory)
        self.columns[-1].editorStart.connect(self.onEditorStart)
        self.columns[-1].editorFinished.connect(self.onEditorFinished)

        _rule1 = lambda item: "isHidden" in item or self.data.hidden(item[
            'name'])
        rule1 = lambda row: exception_guard(_rule1, self.data, row,
                                            "is item hidden")
        self.addRowTextColorComplexRule(rule1, QColor(0, 0, 200))

        _rule2 = lambda item: item['isLink'] == DataSource.IS_LNK_BROKEN
        rule2 = lambda row: exception_guard(_rule2, self.data, row,
                                            "is item link")
        self.addRowTextColorComplexRule(rule2, QColor(200, 0, 0))

        _rule3 = lambda item: 'mode' in item and stat.S_IXUSR & item[
            'mode'] and not item['isDir']
        rule3 = lambda row: exception_guard(_rule3, self.data, row,
                                            "is item dir")
        self.addRowTextColorComplexRule(rule3, QColor(30, 125, 45))

        self.columns.append(TableColumn(self, 'size', "Size"))
        self.columns[-1].setTextTransform(
            lambda item, _: format_bytes(item['size']))
        self.columns[-1].setTextAlign(Qt.AlignRight)
        self.columns[-1].setWidthByCharCount(7)

        self.columns.append(TableColumn(self, 'mtime', "Modified Date"))
        self.columns[-1].setTextTransform(
            lambda item, _: self.getFormatedDate(item))
        self.columns[-1].setShortName("Date")
        self.columns[-1].setDefaultSortReversed(True)
        self.columns[-1].setTextAlign(Qt.AlignRight)
        self.columns[-1].setWidthByCharCount(13)

        self.columns.append(TableColumn(self, 'mode', "Permissions"))
        self.columns[-1].setTextTransform(lambda _, v: format_mode(v))
        self.columns[-1].setShortName("Mode")
        self.columns[-1].setTextAlign(Qt.AlignRight)
        self.columns[-1].setWidthByCharCount(10)
예제 #4
0
    def load_resource(self, path):
        """return a in-memory representation of path"""

        ext = os.path.splitext(path)[1]
        kind = ResourceManager.instance().getExtType(ext)
        # todo read the first few bytes to check the kind
        source = self.parent.getSource()

        # this actually speeds up  DirectorySource>EBFSSource>ZipSource
        # cases. I believe because there are more sequence points for
        # the threading system to preempt this thread.
        data = b""
        with source.open(path, "rb") as rb:
            buf = rb.read(32 * 1024)
            while buf:
                data += buf
                buf = rb.read(32 * 1024)

        if kind == ResourceManager.GIF:
            return QByteArray(data)
        elif kind == ResourceManager.IMAGE:
            img = QImage.fromData(data)

            # note:
            # return (img, None, (0,0,0))
            # to disable pre-scaling
            return (img, None, (0, 0, 0))

            # prescale the image
            #w,h = self.parent.getScaleSize()
            #mode = self.parent.getScaleMode()
            #map = scale_image_to_map(img,w,h,mode)
            #params = (w,h,mode)
            # if img.width()*img.height() > 1920*1080:
            #    img = scale_image(img,1920,1080)
            #map = QPixmap.fromImage(img)
            # return (img,map,params)
        else:
            return None
예제 #5
0
 def validateResource(self, path):
     ext = self.source.splitext(path)[1]
     kind = ResourceManager.instance().getExtType(ext)
     return kind in (ResourceManager.IMAGE, ResourceManager.GIF)
예제 #6
0
    def contextMenu(self, event, model, items):

        is_files = all(not item['isDir'] for item in items)
        is_dirs = all(item['isDir'] for item in items)

        ctxtmenu = QMenu(model)

        # file manipulation options
        menu = ctxtmenu.addMenu("New")
        menu.addAction("Empty File", lambda: model.action_touch_begin())
        menu.addAction("Folder", lambda: model.action_mkdir_begin())

        if len(items) > 0:
            menu = ctxtmenu.addMenu("Archive")
            menu.addAction("Add to 7z")
            menu.addAction("Add to zip")
            if len(items) == 1 and extract_supported(items[0]['name']):
                menu.addAction("Extract to *")
                menu.addAction("Extract to <named>")

        if len(items) == 1:
            # TODO: someday I should have a way to enable "default programs"
            # by file extension, and open alternatives
            # for now, there are only three classes I care about

            # todo:
            #   Open as ...
            #       Image (edit)  -- paint
            #       Image (view)  -- irfanview
            #       Internet      -- firefox
            # create a tab in the settings for managing context menus
            # the tab should be a table with the following values
            #   Name       -- displayed in the open as context menu
            #   executable -- path to program
            # possible option, each row in the table contains an ENUM value
            #   define Text, Audio, Vido, Image etc and the first defined
            #   of each type in the table iss considered "primary"
            #   and used by the model
            # possible option : finally implementing per extension
            #   handlers -- with some handlers that are "default" and always
            #   show for any extention, and another "default"  -- which
            #   is just open native for files with no known extension
            # this information should be stored in the database so that
            # the command line interface can access it
            menu = ctxtmenu.addMenu("Open As ...")
            menu.addAction("Text", lambda: model.action_edit(items[0]))
            menu.addAction("Audio",
                           lambda: model.action_openas_audio(items[0]))
            menu.addAction("Video",
                           lambda: model.action_openas_video(items[0]))
            menu.addAction("Native",
                           lambda: model.action_openas_native(items[0]))

            # add a menu option for opening the selected image in a
            # pop up window
            ext = model.view.splitext(items[0]['name'])[1]
            kind = ResourceManager.instance().getExtType(ext)
            if kind in (ResourceManager.IMAGE, ResourceManager.GIF):
                ctxtmenu.addAction("View Image",lambda : \
                    self.viewImage.emit(model.view, items[0]['name']))

        self._ctxtMenu_addFileOperations1(ctxtmenu, model, items)

        ctxtmenu.addSeparator()

        if model.view.islocal():
            if len(items) == 1:

                if not items[0]['isDir'] and items[0][
                        'isLink'] != DataSource.IS_LNK_BROKEN:
                    ctxtmenu.addAction("Edit",
                                       lambda: model.action_edit(items[0]))

                elif items[0]['isLink']:
                    ctxtmenu.addAction(
                        "Edit Link", lambda: model.action_edit_link(items[0]))

        ctxtmenu.addSeparator()

        if model.view.islocal() and Settings.instance()['cmd_diff_files']:
            ctxtmenu.addSeparator()

            if len(items) == 1:
                if self.act_diff_left_path is None:
                    ctxtmenu.addAction(
                        "Compare: Set Left",
                        lambda: self.action_compare_set_left(model, items[0]))
                else:
                    name = model.view.split(self.act_diff_left_path)[1]

                    ctxtmenu.addAction(
                        "Compare: Set Left",
                        lambda: self.action_compare_set_left(model, items[0]))
                    ctxtmenu.addAction(
                        "Compare to: %s" % name,
                        lambda: self.action_compare(model, items[0]))
            elif len(items) == 2:
                ctxtmenu.addAction("Compare 2 Items",
                                   lambda: self.action_compare_2(model, items))

        self._ctxtMenu_addFileOperations2(ctxtmenu, model, items)

        if model.view.islocal():
            ctxtmenu.addAction(QIcon(":/img/app_open.png"), "Open in Explorer",
                               model.action_open_directory)
            ctxtmenu.addAction("Open in Terminal", model.action_open_term)

        ctxtmenu.addAction("Refresh", model.action_refresh)

        action = ctxtmenu.exec_(event.globalPos())
예제 #7
0
def initSettings(path_base):

    if not os.path.exists(path_base):
        os.makedirs(path_base)

    settings_db_path = os.path.join(path_base,"settings.db")

    sqlstore = SQLStore(settings_db_path)
    Settings.init( sqlstore )

    Settings.instance()['database_directory']=path_base

    data = {}

    # basic associations by extension
    # TODO: pull the defaults out the resource manager,
    # settings menu can modify these (and update resource manager)
    fAssoc = ResourceManager.instance().getFileAssociation

    # TODO: resource manager doesnt keep track of text files, should it?
    data['ext_text'] = [".txt",".log",".md",]

    data['ext_archive']  = fAssoc(ResourceManager.ARCHIVE)
    data['ext_image']    = fAssoc(ResourceManager.IMAGE)
    data['ext_audio']    = fAssoc(ResourceManager.SONG);
    data['ext_movie']    = fAssoc(ResourceManager.MOVIE)
    data['ext_document'] = fAssoc(ResourceManager.DOCUMENT)
    data['ext_code']     = fAssoc(ResourceManager.CODE)

    if sys.platform == 'darwin':
        cmd_edit_text = "\"/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl\" \"%s\""
        cmd_edit_image = ""
        cmd_open_native = "open \"%s\""
        cmd_launch_terminal = "open -b com.apple.terminal \"%s\""
        cmd_diff_files = "\"/Applications/Beyond Compare.app/Contents/MacOS/bcomp\" \"%s\" \"%s\""
        cmd_play_audio = "/Applications/VLC.app/Contents/MacOS/VLC \"%s\""
        cmd_play_video = "/Applications/VLC.app/Contents/MacOS/VLC \"%s\""
        cmd_vagrant = "vagrant"
    elif sys.platform=="win32":

        cmd_edit_text = "\"C:\\Program Files\\Sublime Text 3\\subl.exe\" \"%s\""
        #cmd_edit_image = "mspaint.exe \"%s\""
        cmd_edit_image = "pythonw \"D:\\Dropbox\\Code\\packages\\PyPaint\\PyPaint.py\" \"%s\""
        cmd_open_native = "explorer \"%s\""
        cmd_launch_terminal = "start /D \"%s\""
        cmd_diff_files = ""
        cmd_play_audio = ""
        cmd_play_video = ""
        cmd_vagrant = ""
    else:
        cmd_edit_text = "subl3 \"%s\""
        cmd_edit_image = ""
        # nemo caja thunar dolphin
        cmd_open_native = "nemo \"%s\""
        cmd_launch_terminal = "xterm -e \"cd %s; bash\""
        cmd_diff_files = ""
        cmd_play_audio = ""
        cmd_play_video = ""
        cmd_vagrant = ""

    data["cmd_edit_text"] = cmd_edit_text
    data["cmd_edit_image"] = cmd_edit_image
    data["cmd_open_native"] = cmd_open_native
    data["cmd_launch_terminal"] = cmd_launch_terminal
    data["cmd_diff_files"] = cmd_diff_files
    data["cmd_play_audio"] = cmd_play_audio
    data["cmd_play_video"] = cmd_play_video
    data["cmd_vagrant"] = cmd_vagrant

    # view_show_hidden is the default value for new tabs
    # each widget supports an individual setting, which can be toggled.
    data['view_show_hidden'] = True

    Settings.instance().setMulti(data,False)
예제 #8
0
    def __init__(self, version_info, defaultpath, defaultpath_r=""):
        """
        defaultpath: if empty default to the users home
        """
        super(MainWindow, self).__init__()

        self.sources = set()

        self.version, self.versiondate, self.builddate = version_info

        self.initMenuBar()
        self.initStatusBar()

        self.splitter = QSplitter(self)

        self.pain_main = Pane(self)

        self.dashboard = Dashboard(self)

        # controller maintains state between tabs
        self.source = DirectorySource()
        self.controller = ExplorController(self)
        self.controller.forceReload.connect(self.refresh)
        self.controller.submitJob.connect(self.dashboard.startJob)
        self.controller.viewImage.connect(self.onViewImage)

        self.btn_newTab = QToolButton(self)
        self.btn_newTab.clicked.connect(self.newTab)
        self.btn_newTab.setIcon(QIcon(":/img/app_plus.png"))

        self.quickview = QuickAccessTable(self)
        self.quickview.changeDirectory.connect(self.onChangeDirectory)
        self.quickview.changeDirectoryRight.connect(
            self.onChangeDirectoryRight)

        self.wfctrl = WatchFileController(self.source)
        self.wfctrl.watchersChanged.connect(self.onWatchersChanged)

        self.wfview = WatchFileTable(self.wfctrl, self)
        self.wfview.changeDirectory.connect(self.onChangeDirectory)

        self.tabview = TabWidget(self)
        self.tabview.tabBar().setMovable(True)
        self.tabview.setCornerWidget(self.btn_newTab)
        self.tabview.tabCloseRequested.connect(self.onTabCloseRequest)
        self.tabview.setSizePolicy(QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)
        self.tabview.tabBar().setUsesScrollButtons(True)
        self.tabview.tabBar().setElideMode(Qt.ElideNone)

        self.pain_main.addWidget(self.tabview)
        self.pain_main.addWidget(self.dashboard)

        self.calculator = Calculator(self)
        self.clock = Clock(self)

        self.image_view = ImageView(self)
        self.image_view.image_extensions = ResourceManager.instance(). \
            getFileAssociation(ResourceManager.IMAGE)

        self.wview = QWidget()
        self.vbox_view = QVBoxLayout(self.wview)
        self.vbox_view.addWidget(self.clock)
        self.vbox_view.setContentsMargins(0, 0, 0, 0)
        self.vbox_view.addWidget(self.quickview.container)
        self.vbox_view.addWidget(self.wfview.container)
        self.vbox_view.addWidget(self.image_view)
        self.vbox_view.addWidget(self.calculator)
        self.splitter.addWidget(self.wview)
        self.splitter.addWidget(self.pain_main)

        self.setCentralWidget(self.splitter)

        # create the first tab
        self.newTab(defaultpath, defaultpath_r)

        self.xcut_refresh = QShortcut(QKeySequence(Qt.Key_Escape), self)
        self.xcut_refresh.activated.connect(self.refresh)

        self.imgview_dialog = None