class MainWindow(QWidget, Ui_Form): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.appname = "poliBeePsync" self.settings_fname = 'pbs-settings.ini' self.data_fname = 'pbs.data' self.setupUi(self) self.w = QWidget() self.about_text() self.timer = QTimer(self) # settings_path is a string containing the path to settings self.settings_path = None # settings is a dictionary of settings self.settings = None # load_settings() sets settings_path and settings self.load_settings() self.load_data() self.timer.timeout.connect(self.syncfiles) self.timer.start(1000 * 60 * int(self.settings['UpdateEvery'])) self.loginthread = LoginThread(self.user) self.loginthread.signal_error.sig.connect(self.myStream_message) self.loginthread.signal_error.sig.connect(self.loginstatus) self.loginthread.signal_ok.sig.connect(self.myStream_message) self.loginthread.signal_ok.sig.connect(self.loginstatus) self.refreshcoursesthread = RefreshCoursesThread(self.user) self.refreshcoursesthread.dumpuser.sig.connect(self.dumpUser) self.refreshcoursesthread.newcourses.sig.connect(self.addtocoursesview) self.refreshcoursesthread.newcourses.sig.connect(self.syncnewcourses) self.refreshcoursesthread.refreshed.sig.connect(self.myStream_message) self.refreshcoursesthread.removable.sig.connect(self.rmfromcoursesview) self.downloadthread = DownloadThread(self.user, self.settings['RootFolder']) self.downloadthread.download_signal.connect( self.update_course_download) #self.downloadthread.download_signal.connect(self._resizeview) self.downloadthread.initial_sizes.connect(self.setinizialsizes) self.downloadthread.data_signal.connect(self.update_file_localtime) self.userCode.setText(str(self.user.username)) self.userCode.textEdited.connect(self.setusercode) self.password.setText(self.user.password) self.password.textEdited.connect(self.setpassword) self.trylogin.clicked.connect(self.testlogin) self.courses_model = CoursesListModel(self.user.available_courses) self.coursesView.setModel(self.courses_model) self._resizeview() self.refreshCourses.clicked.connect(self.refreshcourses) self.courses_model.dataChanged.connect(self.dumpUser) self.syncNow.clicked.connect(self.syncfiles) #self.pushButton.clicked.connect(self.syncfiles) #self.pushButton.clicked.connect(self.inittextincourses) if self.settings['SyncNewCourses'] == str(True): self.sync_new = Qt.Checked else: self.sync_new = Qt.Unchecked self.rootfolder.setText(self.settings['RootFolder']) self.rootfolder.textChanged.connect(self.rootfolderslot) self.addSyncNewCourses.setCheckState(self.sync_new) self.addSyncNewCourses.stateChanged.connect(self.syncnewslot) self.timerMinutes.setValue(int(self.settings['UpdateEvery'])) self.timerMinutes.valueChanged.connect(self.updateminuteslot) self.changeRootFolder.clicked.connect(self.chooserootdir) #self.version_label.setText("Current version: {}.".format(__version__)) #self.pushButton_2.clicked.connect(self.checknewversion) self.trayIconMenu = QMenu() self.trayIcon = QSystemTrayIcon(self.icon, self.w) self.trayIcon.activated.connect(self._activate_traymenu) self.createTray() def _resizeview(self, **kwargs): self.coursesView.setColumnWidth(3, 160) self.coursesView.resizeColumnToContents(1) self.coursesView.setColumnWidth(0, 320) def inittextincourses(self): self.statusLabel.setText('Started syncing.') def checknewversion(self): rawdata = requests.get( 'https://pypi.python.org/pypi/poliBeePsync/json') latest = json.loads(rawdata.text)['info']['version'] self.version_label.setTextFormat(Qt.RichText) self.version_label.setOpenExternalLinks(True) self.version_label.setLocale( QLocale(QLocale.English, QLocale.UnitedStates)) self.version_label.setScaledContents(True) self.version_label.setWordWrap(True) if latest != __version__: newtext = """<p>Current version: {}.<br> Latest version: {}. </p> <p>Visit <a href='http://www.davideolianas.com/polibeepsync/index.html#how-to\ -install-upgrade-remove'>here</a> to find out how to upgrade. """.format(__version__, latest) else: newtext = "Current version: {} up-to-date.".format(__version__) self.version_label.setText(newtext) def _update_time(self, folder, file, path_list): print('inside ', folder.name) print('path_list: ', path_list) while len(path_list) > 0: namegoto = path_list.pop(0) print('namegoto: ', namegoto) # perché a volte è vuoto? if namegoto != "": fakefolder = Folder(namegoto, 'fake') print('contained folders: ', folder.folders) ind = folder.folders.index(fakefolder) goto = folder.folders[ind] self._update_time(goto, file, path_list) if file in folder.files: ind = folder.files.index(file) thisfile = folder.files[ind] thisfile.local_creation_time = file.local_creation_time self.dumpUser() def update_file_localtime(self, data, **kwargs): course, coursefile, path = data rootpath = os.path.join(self.settings['RootFolder'], course.save_folder_name) if path.startswith(rootpath): partial = path[len(rootpath):] path_list = partial.split(os.path.sep) self._update_time(course.documents, coursefile, path_list) def update_course_download(self, course, **kwargs): logger.info('download size updated') if course in self.user.available_courses: updating = self.user.available_courses[course.name] updating.downloaded_size = course.downloaded_size row = self.courses_model.courses.index(updating) where = self.courses_model.index(row, 3) self.courses_model.dataChanged.emit(where, where) self.dumpUser() def setinizialsizes(self, course, **kwargs): if course in self.user.available_courses: updating = self.user.available_courses[course.name] updating.downloaded_size = course.downloaded_size updating.total_file_size = course.total_file_size row = self.courses_model.courses.index(updating) where = self.courses_model.index(row, 3) self.courses_model.dataChanged.emit(where, where) self.dumpUser() def syncnewcourses(self, newlist): if self.settings['SyncNewCourses'] == 'True': for elem in newlist: elem.sync = True def load_settings(self): for path in [ user_config_dir(self.appname), user_data_dir(self.appname) ]: try: os.makedirs(path, exist_ok=True) except OSError: logger.critical('OSError while calling os.makedirs.', exc_info=True) self.myStream_message("I couldn't create {}.\nStart" " poliBeePsync with --debug " "error to get more details.") self.settings_path = os.path.join(user_config_dir(self.appname), self.settings_fname) defaults = { 'UpdateEvery': '60', 'RootFolder': os.path.join(os.path.expanduser('~'), self.appname), 'SyncNewCourses': 'False' } self.settings = filesettings.settingsFromFile(self.settings_path, defaults) def load_data(self): try: with open( os.path.join(user_data_dir(self.appname), self.data_fname), 'rb') as f: self.user = pickle.load(f) self.myStream_message("Data has been loaded successfully.") except FileNotFoundError: logger.error('Settings file not found.', exc_info=True) self.user = User('', '') self.myStream_message("I couldn't find data in the" " predefined directory. Ignore this" "message if you're using poliBeePsync" " for the first time.") def loginstatus(self, status): self.login_attempt.setText(status) # @Slot(int) # def notifynew(self, state): # if state == 2: # self.settings['NotifyNewCourses'] = 'True' # else: # self.settings['NotifyNewCourses'] = 'False' # filesettings.settingsToFile(self.settings, self.settings_path) @Slot(int) def syncnewslot(self, state): if state == 2: self.settings['SyncNewCourses'] = 'True' else: self.settings['SyncNewCourses'] = 'False' filesettings.settingsToFile(self.settings, self.settings_path) @Slot(int) def updateminuteslot(self, minutes): self.settings['UpdateEvery'] = str(minutes) filesettings.settingsToFile(self.settings, self.settings_path) self.timer.start(1000 * 60 * int(self.settings['UpdateEvery'])) @Slot(str) def rootfolderslot(self, path): self.settings['RootFolder'] = path filesettings.settingsToFile(self.settings, self.settings_path) def chooserootdir(self): currentdir = self.settings['RootFolder'] flags = QFileDialog.DontResolveSymlinks | QFileDialog.ShowDirsOnly newroot = QFileDialog.getExistingDirectory(None, "Open Directory", currentdir, flags) if newroot != "" and str(newroot) != currentdir: self.settings['RootFolder'] = str(newroot) filesettings.settingsToFile(self.settings, self.settings_path) self.rootfolder.setText(newroot) # we delete the already present downloadthread and recreate it # because otherwise it uses the old download folder. I don't know # if there's a cleaner approach del self.downloadthread self.downloadthread = DownloadThread(self.user, self.settings['RootFolder']) self.downloadthread.dumpuser.sig.connect(self.dumpUser) self.downloadthread.course_finished.sig.connect( self.myStream_message) self.downloadthread.signal_error.sig.connect(self.myStream_message) def setusercode(self): newcode = self.userCode.text() self.user.username = newcode try: self.dumpUser() if len(newcode) == 8: self.myStream_message( "User code changed to {}.".format(newcode)) except OSError: self.myStream_message("I couldn't save data to disk. Run" " poliBeePsync with option --debug" " error to get more details.") logger.error( 'OSError raised while trying to write the User' 'instance to disk.', exc_info=True) def setpassword(self): newpass = self.password.text() self.user.password = newpass try: self.dumpUser() self.myStream_message("Password changed.") except OSError: self.myStream_message("I couldn't save data to disk. Run" " poliBeePsync with option --debug" " error to get more details.") logger.error( 'OSError raised while trying to write the User' 'instance to disk.', exc_info=True) def testlogin(self): if not self.loginthread.isRunning(): self.loginthread.exiting = False self.loginthread.start() self.login_attempt.setStyleSheet("color: rgba(0, 0, 0, 255);") self.login_attempt.setText("Logging in, please wait.") def addtocoursesview(self, addlist): for elem in addlist: self.courses_model.insertRows(0, 1, elem) def rmfromcoursesview(self, removelist): for elem in removelist: index = self.courses_model.courses.index(elem) self.courses_model.removeRows(index, 1) def dumpUser(self): # we don't use the message... with open(os.path.join(user_data_dir(self.appname), self.data_fname), 'wb') as f: pickle.dump(self.user, f) def refreshcourses(self): self.statusLabel.setText( 'Searching for online updates...this may take a' ' while.') if not self.loginthread.isRunning(): self.loginthread.exiting = False self.loginthread.signal_ok.sig.connect(self.do_refreshcourses) self.loginthread.start() def do_refreshcourses(self): self.loginthread.signal_ok.sig.disconnect(self.do_refreshcourses) if not self.refreshcoursesthread.isRunning(): self.refreshcoursesthread.exiting = False self.refreshcoursesthread.start() @Slot() def syncfiles(self): self.refreshcoursesthread.finished.connect(self.do_syncfiles) self.refreshcourses() def do_syncfiles(self): self.refreshcoursesthread.finished.disconnect(self.do_syncfiles) self.inittextincourses() self.downloadthread.start() @Slot(str) def myStream_message(self, message): self.status.moveCursor(QTextCursor.End) self.status.insertPlainText(message + "\n\n") def createTray(self): restoreAction = QAction("&Restore", self, triggered=self.showNormal) quitAction = QAction("&Quit", self, triggered=qApp.quit) self.trayIconMenu.addAction(restoreAction) self.trayIconMenu.addAction(quitAction) self.trayIcon.setContextMenu(self.trayIconMenu) self.trayIcon.show() def _activate_traymenu(self, reason): if reason == QSystemTrayIcon.ActivationReason.Trigger: self.showNormal() else: self.trayIconMenu.activateWindow() self.trayIconMenu.popup(QCursor.pos()) def closeEvent(self, event): self.hide() event.ignore() def about_text(self): self.label_3 = QLabel() self.label_3.setTextFormat(Qt.RichText) self.label_3.setOpenExternalLinks(True) self.label_3.setLocale(QLocale(QLocale.English, QLocale.UnitedStates)) self.label_3.setScaledContents(True) self.label_3.setWordWrap(True) text = """ <html> <head/> <body> <p>poliBeePsync is a program written by Davide Olianas, released under GNU GPLv3+.</p> <p>Feel free to contact me at <a href=\"mailto:[email protected]\">[email protected]</a> for suggestions and bug reports.</p> <p>More information is available on the <a href=\"http://www.davideolianas.com/polibeepsync\"> <span style=\" text-decoration: underline; color:#0000ff;\"> official website</span></a>. </p> </body> </html> """ if pysideVersion == '1.2.2': self.label_3.setText( QApplication.translate("Form", text, None, QApplication.UnicodeUTF8)) else: self.label_3.setText(QApplication.translate("Form", text, None))