def __restoreGuiState(self): self._model.restoreRecentState() #TODO: move resoring of recent repo and user to the MainWindowModel try: #Try to open and login recent repository with recent user login tmp = UserConfig().get("recent_repo.base_path") self._model.repo = repo.RepoMgr(tmp) self._model.loginRecentUser() except errors.CannotOpenRepoError: self.ui.statusbar.showMessage( self.tr("Cannot open recent repository."), consts.STATUSBAR_TIMEOUT) self._model.repo = None except errors.LoginError: self.ui.statusbar.showMessage( self.tr("Cannot login recent repository."), consts.STATUSBAR_TIMEOUT) self._model.user = None except Exception: self.ui.statusbar.showMessage( self.tr("Cannot open/login recent repository."), consts.STATUSBAR_TIMEOUT) #Restoring main window size width = int(UserConfig().get("main_window.width", 640)) height = int(UserConfig().get("main_window.height", 480)) self.resize(width, height) #Restoring all dock widgets position and size state = UserConfig().get("main_window.state") if state: state = eval(state) self.restoreState(state)
def __init__(self, parent=None, repo=None): super(TagCloudTextEdit, self).__init__(parent) #Current word in tag cloud under the mouse cursor self.word = None self.keywordAll = False #This is a list of tuples (tag_name, count_of_items_with_this_tag) self.tag_count = None self.setMouseTracking(True) self.setReadOnly(True) self.tags = set() self.not_tags = set() self._repo = repo self.menu = None # TODO: rename to contextMenu try: self._limit = int(UserConfig().get("tag_cloud.limit", 0)) if self._limit < 0: raise ValueError() except: self._limit = 0 palette = QtGui.QApplication.palette() self.bg_color = UserConfig().get("tag_cloud.tag_background_color", QtGui.QColor(230, 230, 230).name()) self.text_color = UserConfig().get("tag_cloud.tag_text_color", palette.text().color().name()) self.hl_text_color = UserConfig().get( "tag_cloud.tag_highlighted_text_color", QtGui.QColor("blue"))
def __storeGuiState(self): #Store all dock widgets position and size byte_arr = self.saveState() UserConfig().store("main_window.state", str(byte_arr.data())) UserConfig().storeAll({ "main_window.width": self.width(), "main_window.height": self.height() })
def removeRepoFromFavorites(self, userLogin, repoBasePath): favoriteReposPropValue = UserConfig().get("favorite_repos." + userLogin) repos = self.__decodeFavoriteReposFromStr(favoriteReposPropValue) foundRepos = [x for x in repos if x[0] == repoBasePath] if len(foundRepos) == 0: return for repo in foundRepos: repos.remove(repo) favoriteReposPropValue = self.__encodeFavoriteReposToStr(repos) UserConfig().store("favorite_repos." + userLogin, favoriteReposPropValue)
def __init__(self, parent, itemsTableTool): super(ItemsTableGui, self).__init__(parent) self.ui = Ui_ItemsTableGui() self.ui.setupUi(self) self._itemsTableView = UnivTableView(self) self.ui.tableViewContainer.addWidget(self._itemsTableView) self.__itemsTableTool = itemsTableTool #Widgets for text queries self.ui.lineEdit_query = TextEdit(self, one_line=True) tmp = QtGui.QHBoxLayout(self.ui.widget_lineEdit_query) tmp.addWidget(self.ui.lineEdit_query) self.connect(self.ui.pushButton_query_exec, QtCore.SIGNAL("clicked()"), self.query_exec) self.connect(self.ui.lineEdit_query, QtCore.SIGNAL("returnPressed()"), self.ui.pushButton_query_exec.click) self.connect(self.ui.pushButton_query_reset, QtCore.SIGNAL("clicked()"), self.query_reset) self.connect(self._itemsTableView, QtCore.SIGNAL("doubleClicked(const QModelIndex&)"), self.__onTableDoubleClicked) #TODO limit page function sometimes works not correct!!! It sometimes shows less items, than specified in limit spinbox! #Initialization of limit and page spinboxes self.ui.spinBox_limit.setValue( int(UserConfig().get("spinBox_limit.value", 0))) self.ui.spinBox_limit.setSingleStep( int(UserConfig().get("spinBox_limit.step", 5))) self.connect(self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"), self.query_exec) self.connect( self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"), lambda: UserConfig().store("spinBox_limit.value", self.ui.spinBox_limit.value())) self.connect(self.ui.spinBox_limit, QtCore.SIGNAL("valueChanged(int)"), lambda val: self.ui.spinBox_page.setEnabled(val > 0)) self.connect(self.ui.spinBox_page, QtCore.SIGNAL("valueChanged(int)"), self.query_exec) self.ui.spinBox_page.setEnabled(self.ui.spinBox_limit.value() > 0) self._itemsTableView.setSortingEnabled(True) self.__table_model = None self.__context_menu = None self.__initContextMenu()
def handle(self): try: self._tool.checkActiveRepoIsNotNone() self._tool.checkActiveUserIsNotNone() rows = self._tool.gui.selectedRows() if len(rows) == 0: raise errors.MsgException( self.tr("There are no selected items.")) tmpDir = UserConfig().get("tmp_dir", consts.DEFAULT_TMP_DIR) if not os.path.exists(tmpDir): os.makedirs(tmpDir) m3uFilename = str(os.getpid()) + self._tool.user.login + str( time.time()) + ".m3u" with open(os.path.join(tmpDir, m3uFilename), "wt") as m3uFile: for row in rows: item = self._tool.gui.itemAtRow(row) if item.data_ref is None: continue m3uFile.write( os.path.join(self._tool.repo.base_path, item.data_ref.url) + os.linesep) self._extAppMgr.openFileWithExtApp( os.path.join(tmpDir, m3uFilename)) self._emitHandlerSignal(HandlerSignals.STATUS_BAR_MESSAGE, self.tr("Done."), consts.STATUSBAR_TIMEOUT) stats.sendEvent("items_table.export_items_to_m3u_and_open_it") except Exception as ex: show_exc_info(self._tool.gui, ex)
def addRepoToFavorites(self, userLogin, repoBasePath, repoAlias): favoriteReposPropValue = UserConfig().get("favorite_repos." + userLogin) repos = self.__decodeFavoriteReposFromStr(favoriteReposPropValue) foundRepos = [x for x in repos if x[0] == repoBasePath] if len(foundRepos) > 0: assert len(foundRepos) == 1 #TODO: Maybe replace assert with removing extra elements?.. return repos.append((repoBasePath, repoAlias)) favoriteReposPropValue = self.__encodeFavoriteReposToStr(repos) UserConfig().store("favorite_repos." + userLogin, favoriteReposPropValue)
def saveColumnsVisibility(self, keyPrefix): if self._model is None: return visibleColumnIds = [] for i in range(self._model.columnCount()): c = self._model.column(i) visibleColumnIds.append(c.id) UserConfig().store(keyPrefix + ".visible_columns", visibleColumnIds)
def _onSetLimitActionTriggered(self): i, ok = QtGui.QInputDialog.getInteger(self, self.tr("Reggata input dialog"), \ self.tr("Enter new value for maximum number of tags in the cloud (0 - unlimited)."), \ value=self.limit, min=0, max=1000000000) if ok: self.limit = i UserConfig().store("tag_cloud.limit", i) stats.sendEvent("tag_cloud.ctx_menu.set_limit")
def saveColumnsWidth(self, keyPrefix): if self._model is None: return for i in range(self._model.columnCount()): c = self._model.column(i) width = self.columnWidth(i) if width > 0: UserConfig().store(keyPrefix + "." + c.id + ".width", str(width))
def favoriteRepos(self, userLogin): ''' Returns list of tuples (repoBasePath, repoAliasName). Every tuple represents a single favorite repository of a user with given userLogin. ''' favoriteReposPropValue = UserConfig().get("favorite_repos." + userLogin) repos = self.__decodeFavoriteReposFromStr(favoriteReposPropValue) return repos
def __putItemStateToArchive(self, item, archive): encoder = memento.Encoder() itemState = encoder.encode(item) itemStateFilename = "id=" + str(item.id) + "_title=" + item.title tmpDir = UserConfig().get("tmp_dir", consts.DEFAULT_TMP_DIR) tmpFileName = os.path.join(tmpDir, "item_state.json") with open(tmpFileName, "w") as f: f.write(itemState) archive.add(tmpFileName, arcname=os.path.join(".reggata/items", itemStateFilename))
def restoreColumnsWidth(self, keyPrefix): if self._model is None: return columnIds = self._model.registeredColumnIds() for columnId in columnIds: columnIndex = self._model.columnVisibleIndexById(columnId) if columnIndex is None: continue self.setColumnWidth( columnIndex, int(UserConfig().get(keyPrefix + "." + columnId + ".width", 100)))
def onCurrentUserChanged(self): user = self._model.user if user is None: self.ui.label_user.setText("") else: UserConfig().storeAll({ "recent_user.login": user.login, "recent_user.password": user.password }) self.ui.label_user.setText("<b>" + user.login + "</b>") self.__rebuildFavoriteReposMenu()
def configureTranslations(app): qtr = QtCore.QTranslator(app) language = UserConfig().get("language") if language: qm_filename = "reggata_{}.qm".format(language) reggataDir = reggata.reggata_dir_locator.modulePath() logger.debug("reggataDir is " + reggataDir) isQmLoaded = qtr.load(qm_filename, os.path.join(reggataDir, "reggata", "locale")) if not isQmLoaded: isQmLoaded = qtr.load(qm_filename, os.path.join(reggataDir, "locale")) if isQmLoaded: QtCore.QCoreApplication.installTranslator(qtr) else: logger.warning("Cannot find translation file {}.".format(qm_filename))
def __init__(self, path_to_repo): ''' Opens an existing repository at given path. ''' try: self._base_path = path_to_repo if not os.path.exists(self.base_path + os.sep + consts.METADATA_DIR): raise Exception("Directory {} is not a repository base path." .format(self.base_path)) engine_echo = stringToBool(UserConfig().get("sqlalchemy.engine_echo")) self.__engine = sqa.create_engine(\ "sqlite:///" + self.base_path + os.sep + consts.METADATA_DIR + os.sep + \ consts.DB_FILE, echo=engine_echo) self.Session = sessionmaker(bind=self.__engine) except Exception as ex: raise CannotOpenRepoError(ex)
def onCurrentRepoChanged(self): repo = self._model.repo try: if repo is not None: UserConfig().store("recent_repo.base_path", repo.base_path) self.ui.label_repo.setText("<b>" + os.path.basename(repo.base_path) + "</b>") self.ui.label_repo.setToolTip(repo.base_path) self.ui.statusbar.showMessage( self.tr("Opened repository from {}.").format( repo.base_path), consts.STATUSBAR_TIMEOUT) else: self.ui.label_repo.setText("") self.ui.label_repo.setToolTip("") except Exception as ex: raise errors.CannotOpenRepoError(str(ex), ex)
def registerReggataInstance(): try: timeoutSec = 5 with urllib.request.urlopen( consts.STATISTICS_SERVER + "/register_app?app_version={}&sys_platform={}".format( reggata.__version__, sys.platform), None, timeoutSec) as f: response = f.read() instanceId = response.decode("utf-8") mobj = re.match( r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", instanceId) if mobj is None: raise Exception( "Server returned bad instance id, it doesn't look like UUID: " + instanceId) UserConfig().store("reggata_instance_id", mobj.group(0)) except Exception as ex: logger.warning("Could not register Reggata instance, reason: " + str(ex))
def restoreColumnsVisibility(self, keyPrefix): if self._model is None: return visibleColumns = eval(UserConfig().get( keyPrefix + ".visible_columns", "None")) # None - would mean all columns are visible if visibleColumns is None: visibleColumns = self._model.registeredColumnIds() columnIds = self._model.registeredColumnIds() for columnId in columnIds: self._model.setColumnVisible(columnId, columnId in visibleColumns) i = 0 for columnId in visibleColumns: self._model.setColumnIndex(columnId, i) c = self._model.columnById(columnId) if c.delegate is not None: self.setItemDelegateForColumn(i, c.delegate) else: self.setItemDelegateForColumn(i, QtGui.QStyledItemDelegate(self)) i += 1
def __init__(self, parent, widgetsUpdateManager, repo, userLogin, items, startItemIndex=0): ''' parent --- parent of this widget. widgetsUpdateManager --- object that would inform other widgets that some Item has changed after edit action. items --- a list of items to show. startItemIndex --- index of the first item to show. be able to edit items. ''' super(ImageViewer, self).__init__(parent) self.ui = Ui_ImageViewer() self.ui.setupUi(self) self.setWindowModality(Qt.WindowModal) self.__widgetsUpdateManager = widgetsUpdateManager self.connect(self, QtCore.SIGNAL("handlerSignal"), self.__widgetsUpdateManager.onHandlerSignal) self.connect(self, QtCore.SIGNAL("handlerSignals"), self.__widgetsUpdateManager.onHandlerSignals) self.items = items self.i_current = startItemIndex if 0 <= startItemIndex < len( items) else 0 self.repo = repo self.user_login = userLogin self.ui.canvas = Canvas(self) self.setCentralWidget(self.ui.canvas) self.__renderCurrentItemFile() self.connect(self.ui.action_prev, QtCore.SIGNAL("triggered()"), self.action_prev) self.connect(self.ui.action_next, QtCore.SIGNAL("triggered()"), self.action_next) self.connect(self.ui.action_zoom_in, QtCore.SIGNAL("triggered()"), self.action_zoom_in) self.connect(self.ui.action_zoom_out, QtCore.SIGNAL("triggered()"), self.action_zoom_out) self.connect(self.ui.action_fit_window, QtCore.SIGNAL("triggered(bool)"), self.action_fit_window) self.ui.action_fit_window.setChecked(self.ui.canvas.fit_window) self.connect(self.ui.action_edit_item, QtCore.SIGNAL("triggered()"), self.action_edit_item) self.connect(self.ui.canvas, QtCore.SIGNAL("fit_window_changed"), \ lambda x: self.ui.action_fit_window.setChecked(x)) # Trying to restore window size try: width = int(UserConfig().get("image_viewer.width", 640)) height = int(UserConfig().get("image_viewer.height", 480)) self.resize(width, height) except: pass # This code stores window size (after window resizing) self.save_state_timer = QtCore.QTimer(self) self.save_state_timer.setSingleShot(True) self.connect(self.save_state_timer, QtCore.SIGNAL("timeout()"), self.save_window_state) #Context menu self.menu = QtGui.QMenu() self.menu.addAction(self.ui.action_edit_item) self.ui.canvas.setContextMenuPolicy(Qt.CustomContextMenu) self.connect(self.ui.canvas, QtCore.SIGNAL("customContextMenuRequested(const QPoint &)"), \ lambda pos: self.menu.exec_(self.ui.canvas.mapToGlobal(pos)))
def save_window_state(self): UserConfig().storeAll({ "image_viewer.width": self.width(), "image_viewer.height": self.height() })
def setSendStatistics(sendStatistics): UserConfig().store("send_statistics", sendStatistics)
def doWork(self): uow = self.repo.createUnitOfWork() try: thumbnail_size = int(UserConfig().get( "thumbnail_size", consts.THUMBNAIL_DEFAULT_SIZE)) for i in range(len(self.items)): item = self.items[i] if self.interrupt: logger.info("ThumbnailBuilderThread interrupted!") break if not item.data_ref or not item.data_ref.is_image(): continue if self.rebuild == False and len(item.data_ref.thumbnails) > 0: continue elif self.rebuild: #Delete ALL existing thumbnails linked with current item.data_ref from database uow.session.query(Thumbnail).filter(Thumbnail.data_ref_id==item.data_ref.id)\ .delete(synchronize_session=False) uow.session.flush() #Clear item.data_ref.thumbnails collection try: self.lock.lockForWrite() item.data_ref.thumbnails[:] = [] finally: self.lock.unlock() try: #Read image from file pixmap = QtGui.QImage( os.path.join(self.repo.base_path, item.data_ref.url)) if pixmap.isNull(): continue #Scale image to thumbnail size if (pixmap.height() > pixmap.width()): pixmap = pixmap.scaledToHeight(thumbnail_size) else: pixmap = pixmap.scaledToWidth(thumbnail_size) buffer = QtCore.QBuffer() buffer.open(QtCore.QIODevice.WriteOnly) pixmap.save(buffer, "JPG") th = Thumbnail() th.data = buffer.buffer().data() th.size = thumbnail_size uow.executeCommand( cmds.SaveThumbnailCommand(item.data_ref.id, th)) #Update items collection try: self.lock.lockForWrite() item.data_ref.thumbnails.append(th) finally: self.lock.unlock() self.emit( QtCore.SIGNAL("progress"), int(100.0 * float(i) / len(self.items)), item.table_row if hasattr(item, 'table_row') else i) except: if self.rebuild: #Stop thumbnails rebuilding raise else: #Continue generating thumbnails in this case logger.error(traceback.format_exc()) finally: uow.close()
def isSendStatisticsAllowed(): sendStatistics = UserConfig().get("send_statistics") return hlp.stringToBool(sendStatistics)
def loginRecentUser(self): login = UserConfig().get("recent_user.login") password = UserConfig().get("recent_user.password") self.loginUser(login, password)
def reggataInstanceId(): return UserConfig().get("reggata_instance_id")
def __getUntaggedItems(self, limit, page, order_by): order_by_1 = "" order_by_2 = "" for col, direction in order_by: if order_by_1: order_by_1 += ", " if order_by_2: order_by_2 += ", " order_by_2 += col + " " + direction + " " if col == "title": order_by_1 += col + " " + direction + " " if order_by_1: order_by_1 = " ORDER BY " + order_by_1 if order_by_2: order_by_2 = " ORDER BY " + order_by_2 thumbnail_default_size = UserConfig().get( "thumbnail_size", consts.THUMBNAIL_DEFAULT_SIZE) if page < 1: raise ValueError("Page number cannot be negative or zero.") if limit < 0: raise ValueError("Limit cannot be negative number.") limit_offset = "" if limit > 0: offset = (page - 1) * limit limit_offset += "LIMIT {0} OFFSET {1}".format(limit, offset) sql = ''' select sub.*, ''' + \ db.Item_Tag._sql_from() + ", " + \ db.Tag._sql_from() + ", " + \ db.Item_Field._sql_from() + ", " + \ db.Field._sql_from() + \ ''' from (select i.*, ''' + \ db.DataRef._sql_from() + ", " + \ db.Thumbnail._sql_from() + \ ''' from items i left join items_tags it on i.id = it.item_id left join data_refs on i.data_ref_id = data_refs.id left join thumbnails on data_refs.id = thumbnails.data_ref_id and thumbnails.size = ''' + \ str(thumbnail_default_size) + ''' where it.item_id is null AND i.alive ''' + order_by_1 + " " + limit_offset + ''' ) as sub left join items_tags on sub.id = items_tags.item_id left join tags on tags.id = items_tags.tag_id left join items_fields on sub.id = items_fields.item_id left join fields on fields.id = items_fields.field_id ''' + order_by_2 items = [] try: items = self._session.query(db.Item)\ .options(contains_eager("data_ref"), \ contains_eager("data_ref.thumbnails"), \ contains_eager("item_tags"), \ contains_eager("item_tags.tag"), \ contains_eager("item_fields"),\ contains_eager("item_fields.field"))\ .from_statement(sql).all() for item in items: self._session.expunge(item) except ResourceClosedError: pass return items
def _buttonAccept(self): res = [] for columnId, title in self._visibleIds: res.append(columnId) UserConfig().store(self._keyPrefix + ".visible_columns", res) self.accept()
def __queryItemsByParseTree(self, query_tree, limit, page, order_by): order_by_1 = "" order_by_2 = "" for col, direction in order_by: if order_by_1: order_by_1 += ", " if order_by_2: order_by_2 += ", " order_by_2 += col + " " + direction + " " if col == "title": order_by_1 += col + " " + direction + " " if order_by_1: order_by_1 = " ORDER BY " + order_by_1 if order_by_2: order_by_2 = " ORDER BY " + order_by_2 sub_sql = query_tree.interpret() if page < 1: raise ValueError("Page number cannot be negative or zero.") if limit < 0: raise ValueError("Limit cannot be negative number.") limit_offset = "" if limit > 0: offset = (page - 1) * limit limit_offset += "LIMIT {0} OFFSET {1}".format(limit, offset) sql = ''' select sub.*, ''' + db.Item_Tag._sql_from() + ''', ''' + db.Tag._sql_from() + ''', ''' + db.Thumbnail._sql_from() + ''', ''' + db.Item_Field._sql_from() + ''', ''' + db.Field._sql_from() + ''' from (''' + sub_sql + " " + order_by_1 + " " + limit_offset + ''') as sub left join items_tags on sub.id = items_tags.item_id left join tags on tags.id = items_tags.tag_id left join items_fields on sub.id = items_fields.item_id left join fields on fields.id = items_fields.field_id left join thumbnails on thumbnails.data_ref_id = sub.data_refs_id and thumbnails.size = ''' + str(UserConfig().get( "thumbnail_size", consts.THUMBNAIL_DEFAULT_SIZE)) + ''' where sub.alive ''' + order_by_2 items = [] try: items = self._session.query(db.Item)\ .options(contains_eager("data_ref"), \ contains_eager("data_ref.thumbnails"), \ contains_eager("item_tags"), \ contains_eager("item_tags.tag"), \ contains_eager("item_fields"),\ contains_eager("item_fields.field"))\ .from_statement(sql).all() for item in items: self._session.expunge(item) except ResourceClosedError: pass return items
def isUserGaveTheAnswerAboutSendStatistics(): sendStatistics = UserConfig().get("send_statistics") return False if hlp.is_none_or_empty(sendStatistics) else True