def __init__(self, parent=None): super(ExplorerView, self).__init__(parent) self.controller = YueExplorerController( ) self.source = DirectorySource() self.dashboard = Dashboard(self) self.ex_main = YueExplorerModel( None, self.controller, self ) self.ex_secondary = YueExplorerModel( None, self.controller, self ) self.ex_secondary.btn_split.setIcon(QIcon(":/img/app_join.png")) self.ex_main.do_ingest.connect(self.onIngestPaths) self.ex_secondary.do_ingest.connect(self.onIngestPaths) self.ex_main.toggleSecondaryView.connect(self.onToggleSecondaryView) self.ex_secondary.toggleSecondaryView.connect(self.onToggleSecondaryView) self.ex_main.directoryChanged.connect(self.primaryDirectoryChanged) self.ex_secondary.directoryChanged.connect(self.secondaryDirectoryChanged) self.ex_main.showSplitButton(True) self.ex_secondary.hide() self.hbox = QHBoxLayout() self.hbox.setContentsMargins(0,0,0,0) self.hbox.addWidget(self.ex_main) self.hbox.addWidget(self.ex_secondary) self.vbox = QVBoxLayout(self) self.vbox.setContentsMargins(0,0,0,0) self.vbox.addLayout(self.hbox) self.vbox.addWidget(self.dashboard)
class ExplorerView(Tab): """docstring for ExplorerView""" play_file = pyqtSignal(str) ingest_finished = pyqtSignal() primaryDirectoryChanged = pyqtSignal(str) secondaryDirectoryChanged = pyqtSignal(str) submitJob = pyqtSignal(Job) def __init__(self, parent=None): super(ExplorerView, self).__init__(parent) self.controller = YueExplorerController( ) self.source = DirectorySource() self.dashboard = Dashboard(self) self.ex_main = YueExplorerModel( None, self.controller, self ) self.ex_secondary = YueExplorerModel( None, self.controller, self ) self.ex_secondary.btn_split.setIcon(QIcon(":/img/app_join.png")) self.ex_main.do_ingest.connect(self.onIngestPaths) self.ex_secondary.do_ingest.connect(self.onIngestPaths) self.ex_main.toggleSecondaryView.connect(self.onToggleSecondaryView) self.ex_secondary.toggleSecondaryView.connect(self.onToggleSecondaryView) self.ex_main.directoryChanged.connect(self.primaryDirectoryChanged) self.ex_secondary.directoryChanged.connect(self.secondaryDirectoryChanged) self.ex_main.showSplitButton(True) self.ex_secondary.hide() self.hbox = QHBoxLayout() self.hbox.setContentsMargins(0,0,0,0) self.hbox.addWidget(self.ex_main) self.hbox.addWidget(self.ex_secondary) self.vbox = QVBoxLayout(self) self.vbox.setContentsMargins(0,0,0,0) self.vbox.addLayout(self.hbox) self.vbox.addWidget(self.dashboard) def onEnter(self): # delay creating the views until the tab is entered for the first # time, this slightly improves startup performance if (self.ex_main.view is None): view1 = LazySourceListView(self.source,self.source.root()) view2 = LazySourceListView(self.source,self.source.root()) # this is a hack, source views are currently in flux view1.chdir(view1.pwd()) view2.chdir(view2.pwd()) view1.loadDirectory.connect(lambda : self.onLazyLoadDirectory(self.ex_main)) view2.loadDirectory.connect(lambda : self.onLazyLoadDirectory(self.ex_secondary)) self.ex_main.setView(view1) self.ex_secondary.setView(view2) self.ex_main.play_file.connect(self.onPlayFile) self.ex_secondary.play_file.connect(self.onPlayFile) self.ex_main.submitJob.connect(self.dashboard.startJob) self.ex_secondary.submitJob.connect(self.dashboard.startJob) self.controller.submitJob.connect(self.dashboard.startJob) self.ex_main.chdir("~") self.ex_secondary.chdir("~") def chdir(self, path): # chdir can be called from another Tab, prior to onEnter, # if that happens run the onEnter first time setup. self.onEnter() self.ex_main.chdir(path) def onLazyLoadDirectory(self,model): job = LoadDirectoryJob(model) self.dashboard.startJob(job) def refresh(self): self.ex_main.refresh() if self.ex_secondary.isVisible(): self.ex_secondary.refresh() def onToggleSecondaryView(self): if self.ex_secondary.isHidden(): self.ex_secondary.show() self.ex_main.showSplitButton(False) self.ex_secondary.showSplitButton(True) else: self.ex_secondary.hide() self.ex_main.showSplitButton(True) self.ex_secondary.showSplitButton(False) def onIngestPaths(self,paths): self.controller.dialog = IngestProgressDialog(paths,self) self.controller.dialog.finished.connect(self.onDialogFinished) self.controller.dialog.show() self.controller.dialog.start() def onDialogFinished(self): if isinstance(self.controller.dialog,IngestProgressDialog): self.ingest_finished.emit() self.controller.dialog = None self.ex_main.refresh() self.ex_secondary.refresh() def onPlayFile(self,path): self.play_file.emit(path)
def __init__(self, parent=None): super(RemoteView, self).__init__(parent) self.client = None self.current_state = STATE_DISCONNECTED self.grid_info = QGridLayout() self.hbox_search = QHBoxLayout() self.hbox_admin = QHBoxLayout() self.vbox = QVBoxLayout(self) self.dashboard = Dashboard(self) self.edit_hostname = QLineEdit(self) self.edit_username = QLineEdit(self) self.edit_apikey = QLineEdit(self) self.edit_dir = QLineEdit(self) self.tbl_remote = RemoteTable(self) self.tbl_remote.showColumnHeader(True) self.tbl_remote.showRowHeader(False) self.edit_search = LineEdit_Search(self, self.tbl_remote, "Search Remote") self.btn_connect = QPushButton("Connect", self) lbl = QLabel("Hostname:") lbl.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.grid_info.addWidget(lbl, 0, 0) self.grid_info.addWidget(self.edit_hostname, 0, 1) lbl = QLabel("User Name:") lbl.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.grid_info.addWidget(lbl, 0, 2) self.grid_info.addWidget(self.edit_username, 0, 3) lbl = QLabel("Local Directory:") lbl.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.grid_info.addWidget(lbl, 1, 0) self.grid_info.addWidget(self.edit_dir, 1, 1) lbl = QLabel("API Key:") lbl.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.grid_info.addWidget(lbl, 1, 2) self.grid_info.addWidget(self.edit_apikey, 1, 3) self.lbl_error = QLabel("") self.lbl_search = QLabel("") self.cb_remote = QComboBox(self) self.cb_remote.addItem("Show All", SONG_ALL) self.cb_remote.addItem("Show Remote", SONG_REMOTE) # index 1 self.cb_remote.addItem("Show Local", SONG_LOCAL) # index 2 self.cb_remote.addItem("Show Sync", SONG_SYNCED) # index 3 self.cb_remote.currentIndexChanged.connect(self.onRemoteIndexChanged) self.btn_push = QPushButton("Push", self) self.btn_pull = QPushButton("Pull", self) self.btn_upload = QPushButton("Upload", self) self.btn_download = QPushButton("Download", self) self.chk_mode = QCheckBox("Master", self) self.chk_path = QCheckBox("Update Path", self) self.lbl_library = QLabel("Library:") self.lbl_library.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.lbl_history = QLabel("History:") self.lbl_history.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.hbox_search.addWidget(self.btn_connect) self.hbox_search.addWidget(self.edit_search) self.hbox_search.addWidget(self.cb_remote) self.hbox_search.addWidget(self.lbl_search) self.hbox_admin.addWidget(self.chk_mode) self.hbox_admin.addWidget(self.chk_path) self.hbox_admin.addWidget(self.lbl_history) #self.hbox_admin.addWidget(self.btn_hardsync) #self.hbox_admin.addWidget(self.btn_hardpush) self.hbox_admin.addWidget(self.btn_push) self.hbox_admin.addWidget(self.btn_pull) #self.hbox_admin.addWidget(self.btn_delete) self.hbox_admin.addWidget(self.lbl_library) #self.hbox_admin.addWidget(self.btn_hardsync) #self.hbox_admin.addWidget(self.btn_hardpush) self.hbox_admin.addWidget(self.btn_upload) self.hbox_admin.addWidget(self.btn_download) #self.hbox_admin.addWidget(self.btn_delete) self.vbox.addLayout(self.grid_info) self.vbox.addLayout(self.hbox_admin) self.vbox.addLayout(self.hbox_search) self.vbox.addWidget(self.lbl_error) self.vbox.addWidget(self.tbl_remote.container) self.vbox.addWidget(self.dashboard) self.edit_hostname.setText(Settings.instance()['remote_hostname']) self.edit_username.setText(Settings.instance()['remote_username']) # "a10ddf873662f4aabd67f62c799ecfbb" self.edit_apikey.setText(Settings.instance()['remote_apikey']) self.edit_dir.setText(Settings.instance()['remote_basedir']) self.edit_search.textChanged.connect(self.onSearchTextChanged) self.btn_connect.clicked.connect(self.onConnectClicked) self.btn_pull.clicked.connect(self.onHistoryPullClicked) self.btn_push.clicked.connect(self.onHistoryPushClicked) self.btn_upload.clicked.connect(self.onLibraryUploadClicked) self.btn_download.clicked.connect(self.onLibraryDownloadClicked) self.chk_mode.stateChanged.connect(self.onModeStateChanged) #self.btn_delete.clicked.connect(self.onHistoryDeleteClicked) #self.btn_hardsync.clicked.connect(self.onHistoryHardSyncClicked) #self.btn_hardpush.clicked.connect(self.onHistoryHardPushClicked) self.tbl_remote.update_data.connect(self.refresh) # on sort... self.grammar = RemoteSongSearchGrammar() self.song_library = [] """ # generate simple library for testing purposes. songs = Library.instance().search("",limit=100) for song in songs: song['remote'] = SONG_REMOTE self.song_library = songs """ self.setSongs(self.song_library) self.chk_mode.setChecked(Qt.Checked) self.hbox_admin.setEnabled(False) self.edit_search.setEnabled(False) self.cb_remote.setEnabled(False)
class RemoteView(Tab): """docstring for RemoteView""" def __init__(self, parent=None): super(RemoteView, self).__init__(parent) self.client = None self.current_state = STATE_DISCONNECTED self.grid_info = QGridLayout() self.hbox_search = QHBoxLayout() self.hbox_admin = QHBoxLayout() self.vbox = QVBoxLayout(self) self.dashboard = Dashboard(self) self.edit_hostname = QLineEdit(self) self.edit_username = QLineEdit(self) self.edit_apikey = QLineEdit(self) self.edit_dir = QLineEdit(self) self.tbl_remote = RemoteTable(self) self.tbl_remote.showColumnHeader(True) self.tbl_remote.showRowHeader(False) self.edit_search = LineEdit_Search(self, self.tbl_remote, "Search Remote") self.btn_connect = QPushButton("Connect", self) lbl = QLabel("Hostname:") lbl.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.grid_info.addWidget(lbl, 0, 0) self.grid_info.addWidget(self.edit_hostname, 0, 1) lbl = QLabel("User Name:") lbl.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.grid_info.addWidget(lbl, 0, 2) self.grid_info.addWidget(self.edit_username, 0, 3) lbl = QLabel("Local Directory:") lbl.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.grid_info.addWidget(lbl, 1, 0) self.grid_info.addWidget(self.edit_dir, 1, 1) lbl = QLabel("API Key:") lbl.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.grid_info.addWidget(lbl, 1, 2) self.grid_info.addWidget(self.edit_apikey, 1, 3) self.lbl_error = QLabel("") self.lbl_search = QLabel("") self.cb_remote = QComboBox(self) self.cb_remote.addItem("Show All", SONG_ALL) self.cb_remote.addItem("Show Remote", SONG_REMOTE) # index 1 self.cb_remote.addItem("Show Local", SONG_LOCAL) # index 2 self.cb_remote.addItem("Show Sync", SONG_SYNCED) # index 3 self.cb_remote.currentIndexChanged.connect(self.onRemoteIndexChanged) self.btn_push = QPushButton("Push", self) self.btn_pull = QPushButton("Pull", self) self.btn_upload = QPushButton("Upload", self) self.btn_download = QPushButton("Download", self) self.chk_mode = QCheckBox("Master", self) self.chk_path = QCheckBox("Update Path", self) self.lbl_library = QLabel("Library:") self.lbl_library.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.lbl_history = QLabel("History:") self.lbl_history.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.hbox_search.addWidget(self.btn_connect) self.hbox_search.addWidget(self.edit_search) self.hbox_search.addWidget(self.cb_remote) self.hbox_search.addWidget(self.lbl_search) self.hbox_admin.addWidget(self.chk_mode) self.hbox_admin.addWidget(self.chk_path) self.hbox_admin.addWidget(self.lbl_history) #self.hbox_admin.addWidget(self.btn_hardsync) #self.hbox_admin.addWidget(self.btn_hardpush) self.hbox_admin.addWidget(self.btn_push) self.hbox_admin.addWidget(self.btn_pull) #self.hbox_admin.addWidget(self.btn_delete) self.hbox_admin.addWidget(self.lbl_library) #self.hbox_admin.addWidget(self.btn_hardsync) #self.hbox_admin.addWidget(self.btn_hardpush) self.hbox_admin.addWidget(self.btn_upload) self.hbox_admin.addWidget(self.btn_download) #self.hbox_admin.addWidget(self.btn_delete) self.vbox.addLayout(self.grid_info) self.vbox.addLayout(self.hbox_admin) self.vbox.addLayout(self.hbox_search) self.vbox.addWidget(self.lbl_error) self.vbox.addWidget(self.tbl_remote.container) self.vbox.addWidget(self.dashboard) self.edit_hostname.setText(Settings.instance()['remote_hostname']) self.edit_username.setText(Settings.instance()['remote_username']) # "a10ddf873662f4aabd67f62c799ecfbb" self.edit_apikey.setText(Settings.instance()['remote_apikey']) self.edit_dir.setText(Settings.instance()['remote_basedir']) self.edit_search.textChanged.connect(self.onSearchTextChanged) self.btn_connect.clicked.connect(self.onConnectClicked) self.btn_pull.clicked.connect(self.onHistoryPullClicked) self.btn_push.clicked.connect(self.onHistoryPushClicked) self.btn_upload.clicked.connect(self.onLibraryUploadClicked) self.btn_download.clicked.connect(self.onLibraryDownloadClicked) self.chk_mode.stateChanged.connect(self.onModeStateChanged) #self.btn_delete.clicked.connect(self.onHistoryDeleteClicked) #self.btn_hardsync.clicked.connect(self.onHistoryHardSyncClicked) #self.btn_hardpush.clicked.connect(self.onHistoryHardPushClicked) self.tbl_remote.update_data.connect(self.refresh) # on sort... self.grammar = RemoteSongSearchGrammar() self.song_library = [] """ # generate simple library for testing purposes. songs = Library.instance().search("",limit=100) for song in songs: song['remote'] = SONG_REMOTE self.song_library = songs """ self.setSongs(self.song_library) self.chk_mode.setChecked(Qt.Checked) self.hbox_admin.setEnabled(False) self.edit_search.setEnabled(False) self.cb_remote.setEnabled(False) def onSearchTextChanged(self): text = self.edit_search.text() self.run_search(text) def refresh(self): self.run_search(self.edit_search.text()) def run_search(self, text): try: rule = self.grammar.ruleFromString(text) limit = self.grammar.getMetaValue("limit", None) offset = self.grammar.getMetaValue("offset", 0) # TODO: instead of comparing index, store the # enum value with the combo box item remote = int(self.cb_remote.currentData()) if remote == SONG_SYNCED: rule = AndSearchRule.join( rule, ExactSearchRule(Song.remote, SONG_SYNCED, type_=int)) elif remote == SONG_LOCAL: rule = AndSearchRule.join( rule, ExactSearchRule(Song.remote, SONG_LOCAL, type_=int)) elif remote == SONG_REMOTE: rule = AndSearchRule.join( rule, ExactSearchRule(Song.remote, SONG_REMOTE, type_=int)) songs = naive_search(self.song_library, rule, orderby=self.tbl_remote.sort_orderby, reverse=self.tbl_remote.sort_reverse, limit=limit, offset=offset) self.setSongs(songs) except ParseError as e: self.edit_search.setStyleSheet("background: #CC0000;") self.lbl_error.setText("%s" % e) self.lbl_error.show() def setSongs(self, songs): self.tbl_remote.setData(songs) self.edit_search.setStyleSheet("") self.lbl_error.hide() self.lbl_search.setText("%d/%d" % (len(songs), len(self.song_library))) def getNewClient(self): hostname = self.edit_hostname.text().strip() apikey = self.edit_apikey.text().strip() username = self.edit_username.text().strip() if self.client is None: self.client = ApiClientWrapper(ApiClient(hostname)) self.client.setApiKey(apikey) self.client.setApiUser(username) return self.client def onConnectClicked(self): if self.current_state == STATE_DISCONNECTED: # get a new client, try to connect self.client = None client = self.getNewClient() basedir = self.edit_dir.text().strip() self.btn_connect.setEnabled(False) job = ConnectJob(client, basedir) job.newLibrary.connect(self.onNewLibrary) job.newApiKey.connect(self.onNewApiKey) job.complete.connect(self.onConnectComplete) self.dashboard.startJob(job) self.current_state = STATE_CONNECTING elif self.current_state == STATE_CONNECTED: self.onConnectComplete(False) def onConnectComplete(self, success): self.btn_connect.setEnabled(True) if success: self.btn_connect.setText("Disconnect") self.hbox_admin.setEnabled(True) self.edit_search.setEnabled(True) self.cb_remote.setEnabled(True) self.current_state = STATE_CONNECTED else: self.client = None self.btn_connect.setText("Connect") self.hbox_admin.setEnabled(False) self.edit_search.setEnabled(False) self.cb_remote.setEnabled(False) self.current_state = STATE_DISCONNECTED def onRemoteIndexChanged(self, idx): self.refresh() def onNewApiKey(self, username, apikey): self.edit_username.setText(username) self.edit_apikey.setText(apikey) def onNewLibrary(self, songs): # TODO: convert the connect button to a disconnect button self.song_library = songs self.refresh() # run the current query, update table def action_downloadSelection(self, items): client = self.getNewClient() job = DownloadJob(client, items, self.edit_dir.text()) self.dashboard.startJob(job) def action_uploadSelection(self, items): client = self.getNewClient() upload_filepath = self.chk_path.isChecked() job = UploadJob(client, items, self.edit_dir.text(), upload_filepath) job.finished.connect(self.refresh) self.dashboard.startJob(job) def onHistoryPullClicked(self): client = self.getNewClient() job = HistoryPullJob(client) self.dashboard.startJob(job) def onHistoryPushClicked(self): client = self.getNewClient() job = HistoryPushJob(client) self.dashboard.startJob(job) def onLibraryUploadClicked(self): client = self.getNewClient() upload_filepath = self.chk_path.isChecked() job = UploadJob(client, self.song_library, self.edit_dir.text(), upload_filepath) job.finished.connect(self.refresh) self.dashboard.startJob(job) def onLibraryDownloadClicked(self): client = self.getNewClient() job = DownloadMetadataJob(client, self.song_library) job.finished.connect(self.refresh) self.dashboard.startJob(job) def onModeStateChanged(self, state): checked = state == Qt.Checked self.btn_push.setEnabled(not checked) self.btn_pull.setEnabled(checked) self.btn_upload.setEnabled(checked) self.btn_download.setEnabled(not checked)
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
class MainWindow(QMainWindow): """docstring for MainWindow""" 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 def initMenuBar(self): menubar = self.menuBar() # each time the file menu is opened, invalidate # the vagrant menu. the vagrant menu results are cached # until the file menu is closed -- increasing resonse time self.invalidate_vagrant_menu = True self.file_menu = menubar.addMenu("File") self.file_menu.aboutToShow.connect(self.onAboutToShowFileMenu) act = self.file_menu.addAction("Preferences") act.triggered.connect(self.openSettings) act = self.file_menu.addAction("Edit Preferences") act.triggered.connect(self.editSettings) act = self.file_menu.addAction("Restore Previous Session") act.triggered.connect(self.onRestorePreviousSession) self.file_menu.addSeparator() act = self.file_menu.addAction("Open FTP") act.triggered.connect(self.newFtpTabTest) act = self.file_menu.addAction("Open SSH") act.triggered.connect(self.newSshTabTest) self.file_menu.addSeparator() if Settings.instance()['cmd_vagrant']: self.vagrant_menu = self.file_menu.addMenu("Vagrant SSH") self.vagrant_menu.aboutToShow.connect(self.initVagrantMenuBar) self.file_menu.addSeparator() act = self.file_menu.addAction("Sync") act.triggered.connect(self.onSyncRemoteFiles) act = self.file_menu.addAction("Clear Watch List") act.triggered.connect(self.onWatchersDelete) # act = menu.addAction("Open SSH+FTP") # act.triggered.connect(self.newSshTabTest) # act = menu.addAction("Open AWS") # act.triggered.connect(self.newSshTabTest) self.file_menu.addAction("Open SMB") self.file_menu.addSeparator() self.file_menu.addAction("Exit") self.help_menu = menubar.addMenu("&?") # sip version, qt version, python version, application version about_text = "" v = sys.version_info about_text += "Version: %s\n" % (self.version) about_text += "Commit Date:%s\n" % (self.versiondate) about_text += "Build Date:%s\n" % (self.builddate) about_text += "Python Version: %d.%d.%d-%s\n" % ( v.major, v.minor, v.micro, v.releaselevel) about_text += "Qt Version: %s\n" % QT_VERSION_STR about_text += "sip Version: %s\n" % SIP_VERSION_STR about_text += "PyQt Version: %s\n" % PYQT_VERSION_STR self.help_menu.addAction( "About", lambda: QMessageBox.about(self, "Explor", about_text)) def onAboutToShowFileMenu(self): self.invalidate_vagrant_menu = True def initVagrantMenuBar(self): if not self.invalidate_vagrant_menu: return self.vagrant_menu.clear() for dir in getVagrantInstances(): _, n = os.path.split(dir) act = self.vagrant_menu.addAction(n) act.triggered.connect(lambda: self.newVagrantTab(dir)) self.invalidate_vagrant_menu = False def initStatusBar(self): statusbar = self.statusBar() self.sbar_lbl_nsources = QLabel() #watchers self.sbar_lbl_w_nfiles = QLabel() #watchers self.sbar_lbl_p_nfiles = QLabel() # delete me self.sbar_lbl_s_nfiles = QLabel() # delete me statusbar.addWidget(self.sbar_lbl_nsources) statusbar.addWidget(self.sbar_lbl_w_nfiles) statusbar.addWidget(self.sbar_lbl_p_nfiles) statusbar.addWidget(self.sbar_lbl_s_nfiles) def openSettings(self): dlg = SettingsDialog(self) dlg.exec_() def editSettings(self): cmdstr = Settings.instance()['cmd_edit_text'] path = YmlSettings.instance().path() proc_exec(cmdstr % (path), os.getcwd()) def newFtpTabTest(self): url = "ftp://*****:*****@192.168.1.9:2121//" #url = "ftp://*****:*****@e-ftp-02.bbn.com//" p = parseFTPurl(url) p['hostname'] = p['hostname'].replace("/", "") print(p) try: print("enter") source = FTPSource(p['hostname'], p['port'], p['username'], p['password']) print("exit") except ConnectionRefusedError as e: sys.stderr.write("error: %s\n" % e) else: view = self._newTab(source) view.chdir(p['path']) def newVagrantTab(self, vagrant_dir): job = NewVagrantTabJob(self, vagrant_dir) job.newSource.connect(self.newTabFromSource) self.dashboard.startJob(job) def newTabFromSource(self, src): self.sources.add(src) self.onUpdateSources() # todo: need a proper icon, and need # to update the icons whent he source changes. icon_path = ':/img/app_folder.png' if not isinstance(src, DirectorySource): icon_path = ':/img/app_archive.png' view = self._newTab(src, icon_path) view.chdir(src.root()) def newSshTabTest(self): dlg = SshCredentialsDialog() dlg.setConfig({ "hostname": "192.168.1.9", "port": 2222, "username": "******", "password": "******", }) if not dlg.exec_(): return cfg = dlg.getConfig() job = NewRemoteTabJob(self) job.newSource.connect(self.newTabFromSource) job.setConfig(cfg) self.dashboard.startJob(job) def newArchiveTab(self, view, path): name = view.split(path)[1] #zfs = ZipFS(view.open(path,"rb"),name) zfs = ZipFS(path, name) view = self._newTab(zfs, ':/img/app_archive.png') view.chdir("/") def newTab(self, defaultpath="~", defaultpath_r=""): view = self._newTab(self.source) view.ex_main.clearHistory() if defaultpath: view.chdir(defaultpath) else: view.chdir("~") if defaultpath_r: view.chdir_r(defaultpath_r) else: view.ex_secondary.chdir(view.pwd_r()) def _newTab(self, source, icon_path=':/img/app_folder.png'): view = ExplorerView(source, self.controller, self) view.primaryDirectoryChanged.connect( lambda path: self.onDirectoryChanged(view, path)) view.submitJob.connect(self.dashboard.startJob) view.openAsTab.connect(self.newArchiveTab) view.openRemote.connect( lambda model, path: self.onOpenRemote(view, model, path)) view.directoryInfo.connect(self.onUpdateStatus) view.selectionChanged.connect(self.onSelectionChanged) self.tabview.addTab(view, QIcon(icon_path), "temp name") self.tabview.setTabsClosable(self.tabview.count() > 1) self.tabview.setCurrentWidget(view) self.sources.add(source) self.onUpdateSources() return view def showWindow(self): geometry = QDesktopWidget().screenGeometry() sw = geometry.width() sh = geometry.height() # calculate default values dw = int(sw * .6) dh = int(sh * .6) dx = sw // 2 - dw // 2 dy = sh // 2 - dh // 2 # use stored values if they exist cw = 0 #s.getDefault("window_width",dw) ch = 0 #s.getDefault("window_height",dh) cx = -1 #s.getDefault("window_x",dx) cy = -1 #s.getDefault("window_y",dy) # the application should start wholly on the screen # otherwise, default its position to the center of the screen if cx < 0 or cx + cw > sw: cx = dx cw = dw if cy < 0 or cy + ch > sh: cy = dy ch = dh if cw <= 0: cw = dw if ch <= 0: ch = dh self.resize(cw, ch) self.move(cx, cy) self.show() # somewhat arbitrary # set the width of the quick access view to something # reasonable lw = 200 if cw > lw * 2: self.splitter.setSizes([lw, cw - lw]) def onDirectoryChanged(self, view, path): index = self.tabview.indexOf(view) _, name = view.source.split(path) if name: self.tabview.setTabText(index, name) else: self.tabview.setTabText(index, "root") def onChangeDirectory(self, path): w = self.tabview.currentWidget() if not isinstance(w.source, DirectorySource): # open a new tab to display the given path # TODO consider passing a source allong with the path in the signal self.newTab(path) else: w.chdir(path) def onChangeDirectoryRight(self, path): w = self.tabview.currentWidget() if not isinstance(w.source, DirectorySource): # open a new tab to display the given path # TODO consider passing a source allong with the path in the signal self.newTab("~", path) else: w.chdir_r(path) def setTabCloseable(self, idx, bCloseable): """ QTabBar *tabBar = ui->tabWidget->findChild<QTabBar *>(); tabBar->setTabButton(0, QTabBar::RightSide, 0); tabBar->setTabButton(0, QTabBar::LeftSide, 0); tabWidget->tabBar()->tabButton(0, QTabBar::RightSide)->resize(0, 0); """ btn1 = self.tabview.tabBar().tabButton(0, QTabBar.RightSide) btn2 = self.tabview.tabBar().tabButton(0, QTabBar.LeftSide) if btn1: btn1.setHidden(not bCloseable) if btn2: btn2.setHidden(not bCloseable) def getActiveSources(self): sources = set() for i in range(self.tabview.count()): widget = self.tabview.widget(i) if isinstance(widget, ExplorerView): mdl1 = widget.ex_main mdl2 = widget.ex_secondary sources.add(mdl1.view.source) sources.add(mdl2.view.source) return sources def closeInactiveSources(self): sources = self.getActiveSources() # get the set of sources that are no longer connected to a tab orphaned = self.sources - sources for src in orphaned: # todo: sources need to check for sources that depend on them # and cannot be closed until the dependencies are closed # add them to `sources` instead of closing # do not close the default source, it is needed for new tabs if src is not self.source: src.close() else: # add sources that cannot be closed to the set of sources sources.add(src) # update the set of opened sources self.sources = sources self.onUpdateSources() def onTabCloseRequest(self, idx): if 0 <= idx < self.tabview.count(): self.tabview.removeTab(idx) self.tabview.setTabsClosable(self.tabview.count() > 1) self.closeInactiveSources() def refresh(self): w = self.tabview.currentWidget() w.refresh() def onShowSecondaryWindow(self, bShow): w = self.tabview.currentWidget() if bShow: w.ex_secondary.show() w.ex_main.showSplitButton(False) w.ex_secondary.showSplitButton(True) else: w.ex_secondary.hide() w.ex_main.showSplitButton(True) w.ex_secondary.showSplitButton(False) def onUpdateStatus(self, onLeft, nFiles): if onLeft: self.sbar_lbl_p_nfiles.setText("nfiles: %d" % nFiles) else: self.sbar_lbl_s_nfiles.setText("nfiles: %d" % nFiles) def onUpdateSources(self): if len(self.sources) == 1: self.sbar_lbl_nsources.setText("1 source") else: self.sbar_lbl_nsources.setText("%d sources" % len(self.sources)) def onViewImage(self, view, path): """ Open a dialog to display an image given by path for the source """ path = view.realpath(path) # if it already exists, reuse the existing dialog if self.imgview_dialog is None: self.imgview_dialog = ImageDisplayDialog(self) self.imgview_dialog.finished.connect(self.onViewImageDialogClosed) self.imgview_dialog.setAttribute(Qt.WA_DeleteOnClose) self.imgview_dialog.setSource(view.source, path) self.imgview_dialog.show() def onViewImageDialogClosed(self): if self.imgview_dialog: self.imgview_dialog.setParent(None) self.imgview_dialog = None def onOpenRemote(self, tab, display, path): src = DirectorySource() view = display.view dtemp = src.join(Settings.instance()['database_directory'], "remote") src.mkdir(dtemp) remote_dname, remote_fname = view.split(path) ftemp = src.join(dtemp, remote_fname) with src.open(ftemp, "wb") as wb: view.getfo(path, wb) display._action_open_file_local(src, ftemp) self.wfctrl.addFile(ftemp, view, path) def onWatchersChanged(self, nfiles): self.sbar_lbl_w_nfiles.setText("watching: %d" % nfiles) def onWatchersDelete(self): self.wfctrl.clear() def onSyncRemoteFiles(self): self.wfctrl.onPostAll() def onRestorePreviousSession(self): base, _ = os.path.split(YmlSettings.instance().path()) path = os.path.join(base, "session.yml") yml = YmlSettings(path) paths = yml.getKey("explor", "active_views", []) self.controller.restoreActiveViews(paths) def saveCurrentSession(self): paths = self.controller.stashActiveViews() base, _ = os.path.split(YmlSettings.instance().path()) path = os.path.join(base, "session.yml") yml = YmlSettings(path) yml.setKey("explor", "active_views", paths) yml.save() print("saved yml session\n") def closeEvent(self, event): self.saveCurrentSession() print("Closing Application\n") super(MainWindow, self).closeEvent(event) def onSelectionChanged(self, src, paths): if len(paths) == 1: self.image_view.setPath(paths[0]) else: self.image_view.setPath(None)