diff --git a/.vscode/launch.json b/.vscode/launch.json index 624816d..0346994 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,12 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { + "name": "Python: main.py", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/main.py" + }, { "name": "Python: Current File", "type": "python", @@ -20,11 +26,5 @@ "secret": "my_secret", "host": "localhost" }, - { - "name": "Python: main.py", - "type": "python", - "request": "launch", - "program": "${workspaceFolder}/main.py" - }, ] } \ No newline at end of file diff --git a/business/project_manager.py b/business/project_manager.py index e471e94..fdbe291 100644 --- a/business/project_manager.py +++ b/business/project_manager.py @@ -4,39 +4,46 @@ class ProjectManager(object): def __init__(self, appDataStorage): self.__appDataStorage = appDataStorage - self.__recentProjects = [] + self.__recentProjects = None def getRecentProjects(self): if self.__recentProjects is None: - self.__recentProjects = list(self.__appDataStorage.readRecentProjects()) - return self.__recentProjects + self.__recentProjects = {} + for item in self.__appDataStorage.readRecentProjects(): + self.__recentProjects[item['path']] = item + + return self.__recentProjects.values() def pinRecentProject(self, entry, isPinned = True): entry['pinned'] = isPinned - self.__appDataStorage.writeRecentProjects(self.__recentProjects) + self.__appDataStorage.writeRecentProjects(self.__recentProjects.values()) + + def deleteRecentProject(self, entry): + self.__recentProjects.pop(entry['path'], None) + self.__appDataStorage.writeRecentProjects(self.__recentProjects.values()) def debug_populateRecentProjects(self): - self.__recentProjects.append({ + self.__recentProjects['/home/tibi/Videos/project.pro'] = { 'name' : 'Debug project', 'path' : '/home/tibi/Videos/project.pro', 'pinned' : True, 'date' : 1 - }) - self.__recentProjects.append({ + } + self.__recentProjects['/home/tibi/Videos/project2.pro'] = { 'name' : 'Debug project 2', 'path' : '/home/tibi/Videos/project2.pro', 'pinned' : False, 'date' : 2 - }) - self.__recentProjects.append({ + } + self.__recentProjects['/home/tibi/Videos/project3.pro'] = { 'name' : 'Debug project 3', 'path' : '/home/tibi/Videos/project3.pro', 'pinned' : False, 'date' : 3 - }) - self.__recentProjects.append({ + } + self.__recentProjects['/home/tibi/Videos/project4.pro'] = { 'name' : 'Debug project 4', 'path' : '/home/tibi/Videos/project4.pro', 'pinned' : False, 'date' : 4 - }) \ No newline at end of file + } \ No newline at end of file diff --git a/storage/appdata_storage.py b/storage/appdata_storage.py index 8eaf846..ba696ae 100644 --- a/storage/appdata_storage.py +++ b/storage/appdata_storage.py @@ -30,15 +30,20 @@ class AppDataStorage(object): def writeSettings(self, settings): pass # todo: finish this + def __parseRow(self, row): + row['date'] = int(row['date']) + row['pinned'] = row['pinned'].lower() in ['true', 'yes', '1', 'on'] + return row + def readRecentProjects(self): if (os.path.exists(self.__recentProjectsPath)): - with open(self.__recentProjectsPath, 'rb') as recentProjectsFile: + with open(self.__recentProjectsPath, 'r') as recentProjectsFile: csvreader = csv.DictReader(recentProjectsFile, fieldnames=AppDataStorage.RECENT_PROJECTS_FIELDS) for row in csvreader: - yield row + yield self.__parseRow(row) def writeRecentProjects(self, items): self.__createPath(self.__recentProjectsPath) - with open(self.__recentProjectsPath, 'wb') as recentProjectsFile: + with open(self.__recentProjectsPath, 'w') as recentProjectsFile: csvwriter = csv.DictWriter(recentProjectsFile, AppDataStorage.RECENT_PROJECTS_FIELDS) csvwriter.writerows(items) \ No newline at end of file diff --git a/ui/ember_application.py b/ui/ember_application.py index 303eb21..455834e 100644 --- a/ui/ember_application.py +++ b/ui/ember_application.py @@ -17,7 +17,7 @@ class EmberApplication(QApplication): # setup resources appDataStorage = AppDataStorage() projectManager = ProjectManager(appDataStorage) - projectManager.debug_populateRecentProjects() + #projectManager.debug_populateRecentProjects() # show main window mainwindow = MainWindow(projectManager) diff --git a/ui/welcome/recent_project.py b/ui/welcome/recent_project.py index 4c42fef..941f2ae 100644 --- a/ui/welcome/recent_project.py +++ b/ui/welcome/recent_project.py @@ -1,11 +1,20 @@ from PyQt5.QtWidgets import QWidget, QHBoxLayout, QLabel, QToolButton, QLayout +from PyQt5.QtCore import pyqtSignal from PyQt5.QtGui import QFont class RecentProjectWidget(QWidget): + + deleted = pyqtSignal() + pinned = pyqtSignal(bool) + def __init__(self, recentProject): super().__init__() + self.project = recentProject + self.__selected = False self.setupUi() - self.setProject(recentProject) + self.setupActions() + self.__setProject(recentProject) + self.setSelected(False) def setupUi(self): layout = QHBoxLayout() @@ -18,16 +27,46 @@ class RecentProjectWidget(QWidget): layout.addStretch() # pin button - self.__button = QToolButton() - self.__button.setFont(QFont("Font Awesome 5 Free")) - self.__button.setText("\uf08d") - self.__button.setCheckable(True) - layout.addWidget(self.__button) + self.__pin_button = QToolButton() + self.__pin_button.setFont(QFont("Font Awesome 5 Free")) + self.__pin_button.setText("\uf08d") + self.__pin_button.setCheckable(True) + layout.addWidget(self.__pin_button) + + # delete button + self.__del_button = QToolButton() + self.__del_button.setFont(QFont("Font Awesome 5 Free")) + self.__del_button.setText("\uf2ed") + layout.addWidget(self.__del_button) + + # pin indicator + self.__pin_indicator = QLabel() + self.__pin_indicator.setFont(QFont("Font Awesome 5 Free")) + self.__pin_indicator.setText("\uf08d") + layout.addWidget(self.__pin_indicator) # done layout.setSizeConstraint(QLayout.SetMinimumSize) self.setLayout(layout) - def setProject(self, project): + def setupActions(self): + self.__pin_button.toggled.connect(self.__pinnedToggled) + self.__del_button.pressed.connect(self.deleted) + + def setSelected(self, selected = True): + self.__selected = selected + self.__pin_button.setVisible(selected) + self.__del_button.setVisible(selected) + self.__pin_indicator.setVisible(not self.__selected and self.__pin_button.isChecked()) + + def setPinned(self, isPinned = True): + self.__pin_button.setChecked(isPinned) + + def __setProject(self, project): self.__text = project['name'] - self.__button.setChecked(project['pinned']) + self.setPinned(project['pinned']) + + def __pinnedToggled(self, isPinned): + self.__pin_indicator.setVisible(not self.__selected and isPinned) + if (isPinned != self.project['pinned']): + self.pinned.emit(isPinned) \ No newline at end of file diff --git a/ui/welcome/welcome_dialog.py b/ui/welcome/welcome_dialog.py index b519748..f7a3784 100644 --- a/ui/welcome/welcome_dialog.py +++ b/ui/welcome/welcome_dialog.py @@ -1,27 +1,21 @@ -import os -import functools -from enum import Enum +import traceback -from PyQt5.QtWidgets import QDialog, QVBoxLayout, QWidget, QCommandLinkButton, QListWidgetItem +from PyQt5.QtWidgets import QDialog, QCommandLinkButton, QListWidgetItem from PyQt5.QtGui import QPixmap from PyQt5.QtCore import Qt -from PyQt5 import uic -from util import str_compare from ui.welcome.recent_project import RecentProjectWidget from ui.welcome.welcome_dialog_ui import Ui_WelcomeDialog -class WelcomeDialogResult(Enum): - NewProject = 0 - OpenProject = 1 - OpenRecentProject = 2 - class WelcomeDialog(QDialog): + NEW_PROJECT = 0 + OPEN_PROJECT = 1 def __init__(self, projectManager): super().__init__() self.__projectManager = projectManager - self.__resultAction = None + self.resultAction = None + self.projectToOpen = None self.setResult(QDialog.Rejected) self.setupUi() self.setupActions() @@ -35,6 +29,8 @@ class WelcomeDialog(QDialog): def setupActions(self): self.ui.buttonNewProject.pressed.connect(self.newProjectPressed) self.ui.buttonOpenProject.pressed.connect(self.openProjectPressed) + self.ui.listRecentProjects.currentItemChanged.connect(self.listRecentProjectsCurrentChanged) + self.ui.listRecentProjects.itemActivated.connect(self.listRecentProjectsItemActivated) def resizeEvent(self, event): super().resizeEvent(event) @@ -48,18 +44,52 @@ class WelcomeDialog(QDialog): projects = sorted(projects, key=lambda x: (x['pinned'], x['date']), reverse=True) for project in projects: + + widget = RecentProjectWidget(project) + widget.pinned.connect(self.__projectPinned) + widget.deleted.connect(self.__projectDeleted) + item = QListWidgetItem(project['name']) item.setData(Qt.UserRole, project) - widget = RecentProjectWidget(project) item.setSizeHint(widget.sizeHint()) self.ui.listRecentProjects.addItem(item) self.ui.listRecentProjects.setItemWidget(item, widget) def newProjectPressed(self): - self.__resultAction = WelcomeDialogResult.NewProject + self.resultAction = WelcomeDialog.NEW_PROJECT self.accept() def openProjectPressed(self): - self.__resultAction = WelcomeDialogResult.OpenProject - self.accept() \ No newline at end of file + # TODO: show open dialog + self.resultAction = WelcomeDialog.OPEN_PROJECT + self.accept() + + def listRecentProjectsCurrentChanged(self, current, previous): + if not current is None: + recentProjectWidget = self.ui.listRecentProjects.itemWidget(current) + recentProjectWidget.setSelected(True) + + if not previous is None: + recentProjectWidget = self.ui.listRecentProjects.itemWidget(previous) + if not recentProjectWidget is None: + recentProjectWidget.setSelected(False) + + def listRecentProjectsItemActivated(self, item): + project = item.data(Qt.UserRole) + self.resultAction = WelcomeDialog.OPEN_PROJECT + self.projectToOpen = project['path'] + self.accept() + + def __projectPinned(self, isPinned): + project = self.ui.listRecentProjects.currentItem().data(Qt.UserRole) + self.__projectManager.pinRecentProject(project, isPinned) + + def __projectDeleted(self): + project = self.ui.listRecentProjects.currentItem().data(Qt.UserRole) + try: + self.__projectManager.deleteRecentProject(project) + self.ui.listRecentProjects.takeItem(self.ui.listRecentProjects.currentRow()) + except: + print("Error while deleting! ") + traceback.print_exc() \ No newline at end of file