diff --git a/.github/workflows/pythonapp.yml b/.github/workflows/pythonapp.yml new file mode 100644 index 0000000..db7269c --- /dev/null +++ b/.github/workflows/pythonapp.yml @@ -0,0 +1,37 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Python application + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v1 + with: + python-version: 3.8 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + - name: Lint with flake8 + run: | + pip install flake8 + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --ignore=E225,E226,E231,E265,E302,E722,F401,F403,F405,C901 --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pip install pytest + pytest diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..e7e9d11 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml diff --git a/.idea/QTodoTxt2.iml b/.idea/QTodoTxt2.iml new file mode 100644 index 0000000..6a9a812 --- /dev/null +++ b/.idea/QTodoTxt2.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/dictionaries/Dad.xml b/.idea/dictionaries/Dad.xml new file mode 100644 index 0000000..90c0b4e --- /dev/null +++ b/.idea/dictionaries/Dad.xml @@ -0,0 +1,11 @@ + + + + appdata + asctime + levelname + qtodo + textfile + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..8656114 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e676f8b --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..15813b2 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/bin/qtodotxt.pyw b/bin/qtodotxt.pyw index 4b018d3..72b1e4d 100755 --- a/bin/qtodotxt.pyw +++ b/bin/qtodotxt.pyw @@ -5,9 +5,10 @@ import os import sys try: - __file__ + __file__ except NameError: - __file__ = sys.argv[0] + __file__ = sys.argv[0] + def reroute_py2exe_logs(): appdata = os.path.expandvars("%AppData%\\QTodoTxt") @@ -16,16 +17,15 @@ def reroute_py2exe_logs(): sys.stdout = open(appdata + "\\stdout.log", "w") sys.stderr = open(appdata + "\\stderr.log", "w") + if sys.argv[0].lower().endswith('.exe'): -# If something goes wrong, logging information might help. -# Uncommenting line below allows logging to be stored at same location where exe resides + # If something goes wrong, logging information might help. + # Uncommenting line below allows logging to be stored at same location where exe resides reroute_py2exe_logs() sys.path.insert(0, os.path.join(os.path.dirname(__file__))) - sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) from qtodotxt2 import app app.run() - diff --git a/examples/todo.txt b/examples/todo.txt index 7624ea1..ace59a4 100644 --- a/examples/todo.txt +++ b/examples/todo.txt @@ -1,13 +1,6 @@ -(A) Make peace between Cylons and humans +PeaceProject -(A) Review NCMR Log +Admin @work t:2017-12-22 rec:+1b due:2017-12-22 -(B) Report to Admiral Adama about FTL @CIC +GalacticaRepairs due:2013-05-24 -(C) 2016-12-08 Feed Schrodinger's Cat rec:+1d due:2014-02-23 -(C) Upgrade jump drives with Cylon technology +GalacticaRepairs -2016-12-12 +GalacticaRepairs Check hull integrity rec:+7b due:2016-12-12 -Check for DRADIS contact @CIC -Check if http://google.com is available -Download code from
https://github.com/QTodoTxt/QTodoTxt/archive/master.zip
and give it a try! -Find the question due:2017-06-10 rec:6d t:2017-06-09 -Think about future t:2099-12-31 -h:1 @CIC +GalacticaRepairs @work -x 2016-02-21 (B) Seal ship's cracks with biomatter +GalacticaRepairs +2020-05-05 +2020-05-05 (A) A thing @work @school +project due:2020-05-05 +2020-05-05 (B) due thing due:2020-05-05 +2020-05-05 (C) test text @test +project due:2020-05-16 +2020-05-05 more things due:2020-05-01 +x 2020-05-05 2020-05-05 finished due:2020-05-06 diff --git a/packaging/Debian/buildDebPackage.py b/packaging/Debian/buildDebPackage.py index 237f56b..219f928 100644 --- a/packaging/Debian/buildDebPackage.py +++ b/packaging/Debian/buildDebPackage.py @@ -1,9 +1,9 @@ import urllib.request import os -import os.path +import os.path import sys import tarfile -from shutil import copytree,ignore_patterns,copy,rmtree +from shutil import copytree, ignore_patterns, copy, rmtree from stat import * import fnmatch import re @@ -59,7 +59,7 @@ def buildPackageFolder(folderName): #Fix execution rights on bin folder for file in os.listdir(buildBinDir): - filePath=os.path.join(buildBinDir,file) + filePath=os.path.join(buildBinDir, file) if os.path.isfile(filePath): st = os.stat(filePath) os.chmod(filePath, st.st_mode | S_IEXEC) @@ -85,7 +85,7 @@ def makeMd5sums(baseDir,outputFilePath): outputFile = open(outputFilePath, 'w') - for (root,dirs,files) in os.walk(baseDir): + for (root, dirs, files) in os.walk(baseDir): dirs[:] = [d for d in dirs if not re.match(excludes,d)] files = [f for f in files if not re.match(excludes,f)] @@ -94,11 +94,10 @@ def makeMd5sums(baseDir,outputFilePath): md5 = hashlib.md5(open(path,'rb').read()).hexdigest() relativePath = root.replace(baseDir+'/',"",1) + os.sep + fn outputFile.write("%s %s\n" % (md5,relativePath)) - outputFile.close() + def generateControl(templateFile,packageVersion,outputFilePath): - templateExp = open(templateFile,'r').read() template = Template(templateExp) @@ -128,6 +127,7 @@ def clean(fileName,folderName): # Call this with the version as first argument + version=sys.argv[1] scriptDir = os.path.dirname(os.path.realpath(sys.argv[0])) # Step 1: download tag from github diff --git a/packaging/MacOS/setup.py b/packaging/MacOS/setup.py index 407e626..c855040 100644 --- a/packaging/MacOS/setup.py +++ b/packaging/MacOS/setup.py @@ -32,6 +32,7 @@ def collect_packages(path, package_name, packages, excludes=None): packages.append(subpackage_name) collect_packages(subpath, subpackage_name, packages) + packages = [] collect_packages('.', '', packages, excludes=['test']) @@ -58,4 +59,4 @@ def collect_packages(path, package_name, packages, excludes=None): "build_base": os.path.join(current_dir, 'build') }, } - ) + ) diff --git a/qtodotxt2/app.py b/qtodotxt2/app.py index 457a5ce..748a51a 100644 --- a/qtodotxt2/app.py +++ b/qtodotxt2/app.py @@ -52,8 +52,8 @@ def setupAnotherInstanceEvent(controller): dirname = os.path.dirname(sys.argv[0]) fileObserver = FileObserver() fileObserver.addPath(dirname) - #FIXME maybe do something in qml - #fileObserver.dirChangetSig.connect(controller.anotherInstanceEvent) + # FIXME maybe do something in qml + # fileObserver.dirChangetSig.connect(controller.anotherInstanceEvent) def setupSingleton(args): @@ -79,7 +79,7 @@ def run(): # Now set up our application and start app = QtWidgets.QApplication(sys.argv) # it is said, that this is lighter: - # (without qwidgets, as we probably don't need them anymore, when transition to qml is done) + # (without QWidgets, as we probably don't need them anymore, when transition to qml is done) # app = QtGui.QGuiApplication(sys.argv) name = QtCore.QLocale.system().name() @@ -105,6 +105,9 @@ def run(): controller.start() app.setWindowIcon(QtGui.QIcon(":/qtodotxt")) + # This line added to change the font and size if the default is too small. + # Working on a fontDialog so it can be changed that way. 2020-04-08 + app.exec_() sys.exit() diff --git a/qtodotxt2/filters_controller.py b/qtodotxt2/filters_controller.py index 98682a4..af59f5d 100644 --- a/qtodotxt2/filters_controller.py +++ b/qtodotxt2/filters_controller.py @@ -17,8 +17,6 @@ def __init__(self, parent, strings, flt=None, icon=None, order=None): self.setData(flt, QtCore.Qt.UserRole) self.filter = flt parent.appendRow([self]) - #if order: - #self.setText(1, str(order)) self.iconSource = icon def setCounts(self, total, completed): @@ -101,9 +99,6 @@ def addDueRangeFilter(self, flt, counts, sortKey=0): item = FilterItem(parentItem, flt.text, flt=flt, icon=icon, order=sortKey) item.setCounts(*counts) - #parentItem.setExpanded(True) - #parentItem.sortChildren(1, QtCore.Qt.AscendingOrder) - @QtCore.pyqtSlot(result='QVariantList') def getRootChildren(self): indexes = [] @@ -226,5 +221,3 @@ def filterTasks(filters, tasks): filteredTasks.append(task) break return filteredTasks - - diff --git a/qtodotxt2/lib/file.py b/qtodotxt2/lib/file.py index 7275675..4ee9565 100644 --- a/qtodotxt2/lib/file.py +++ b/qtodotxt2/lib/file.py @@ -3,14 +3,14 @@ from PyQt5 import QtCore -from qtodotxt2.lib.filters import DueTodayFilter, DueTomorrowFilter, DueThisWeekFilter, DueThisMonthFilter, DueOverdueFilter +from qtodotxt2.lib.filters import DueTodayFilter, DueTomorrowFilter, DueThisWeekFilter, DueThisMonthFilter, \ + DueOverdueFilter from qtodotxt2.lib.tasklib import Task logger = logging.getLogger(__name__) class File(QtCore.QObject): - fileExternallyModified = QtCore.pyqtSignal() fileModified = QtCore.pyqtSignal(bool) @@ -47,8 +47,6 @@ def _createTasksFromLines(self, lines): def _taskModified(self, task): self.setModified(True) - #if task not in self.tasks: - #self.tasks.append(task) if not task.text: self.deleteTask(task) @@ -69,13 +67,12 @@ def connectTask(self, task): task.modified.connect(self._taskModified) def save(self, filename=''): -# logger.debug('File.save called with filename="%s"', filename) self._fileObserver.clear() if not filename and not self.filename: self.filename = self._createNewFilename() elif filename: self.filename = filename - self.tasks = sorted(self.tasks) # we sort for users using simple text editors + self.tasks = sorted(self.tasks) self._saveTasks() self.modified = False self.fileModified.emit(False) @@ -95,7 +92,6 @@ def _createNewFilename(): def _saveTasks(self): with open(self.filename, 'wt', encoding='utf-8') as fd: fd.writelines([(task.text + self.newline) for task in self.tasks]) -# logger.debug('%s was saved to disk.', self.filename) def saveDoneTask(self, task): doneFilename = os.path.join(os.path.dirname(self.filename), 'done.txt') @@ -163,7 +159,6 @@ def getTasksCounters(self): class FileObserver(QtCore.QFileSystemWatcher): - fileChangetSig = QtCore.pyqtSignal(str) dirChangetSig = QtCore.pyqtSignal(str) @@ -184,5 +179,4 @@ def dirChangedHandler(self, path): def clear(self): if self.files(): -# logger.debug('Clearing watchlist.') self.removePaths(self.files()) diff --git a/qtodotxt2/lib/task_htmlizer.py b/qtodotxt2/lib/task_htmlizer.py index c1dfeef..58eaf1f 100644 --- a/qtodotxt2/lib/task_htmlizer.py +++ b/qtodotxt2/lib/task_htmlizer.py @@ -48,9 +48,9 @@ def task2html(self, task): # add space, so tasks get evenly aligned when there's no priority html = '    ' + html if task.completion_date: - html += ' (completed: {0!s})'.format(task.completion_date, self.complColor) + html += ' (completed:{0!s})'.format(task.completion_date, self.complColor) if task.creation_date: - html += ' (created: {0!s})'.format(task.creation_date, self.complColor) + html += ' (created:{0!s})'.format(task.creation_date, self.complColor) return html def _addUrl(self, word, color="none"): diff --git a/qtodotxt2/lib/tasklib.py b/qtodotxt2/lib/tasklib.py index 2bcfbaa..6ba8214 100644 --- a/qtodotxt2/lib/tasklib.py +++ b/qtodotxt2/lib/tasklib.py @@ -8,7 +8,7 @@ class RecursiveMode(Enum): - completitionDate = 0 # Original due date mode: Task recurs from original due date + completionDate = 0 # Original due date mode: Task recurs from original due date originalDueDate = 1 # Completion date mode: Task recurs from completion date @@ -24,12 +24,13 @@ def __init__(self, arg_mode, arg_increment, arg_interval): class TaskSorter(object): - + @staticmethod def projects(tasks): def tmp(task): prj = task.projects if task.projects else ["zz"] return prj, task + return sorted(tasks, key=tmp) @staticmethod @@ -37,6 +38,7 @@ def contexts(tasks): def tmp(task): ctx = task.contexts if task.contexts else ["zz"] return ctx, task + return sorted(tasks, key=tmp) @staticmethod @@ -46,6 +48,7 @@ def tmp(task): return task.due, task else: return datetime(MAXYEAR, 1, 1), task + return sorted(tasks, key=tmp, reverse=False) @staticmethod @@ -67,6 +70,7 @@ def __init__(self, text): QtCore.QObject.__init__(self) self._settings = QtCore.QSettings() self._highest_priority = 'A' + self._getLowestPriority() # all other class attributes are defined in _reset method # which is called in _parse self._parse(text) @@ -116,7 +120,7 @@ def _reset(self): def _parse(self, line): """ - parse a task formated as string in todo.txt format + parse a task formatted as string in todo.txt format """ self._reset() words = line.split(' ') @@ -170,12 +174,14 @@ def hidden(self, val): self.text = self._text + ' h:1' else: txt = self._text.replace(' h:1', '') - self.text = txt.replace('h:1', '') # also take the case whe h_1 is at the begynning + self.text = txt.replace('h:1', '') # also take the case whe h_1 is at the beginning + + # def alignment(self, val): @QtCore.pyqtProperty('QString', notify=modified) def priority(self): return self._priority - + @QtCore.pyqtProperty('QString', notify=modified) def priorityHtml(self): htmlizer = TaskHtmlizer() @@ -196,6 +202,7 @@ def _parseKeyword(self, word): if word.startswith('due:'): self._due = _parseDateTime(word[4:]) if not self._due: + print("the error is here") print("Error parsing due date '{}'".format(word)) self._due_error = word[4:] elif word.startswith('t:'): @@ -215,7 +222,7 @@ def _parseFuture(self, word): def _parseRecurrence(self, word): # Original due date mode if word[4] == '+': - # Test if chracters have the right format + # Test if characters have the right format if re.match('^[1-9][bdwmy]', word[5:7]): self.recursion = Recursion(RecursiveMode.originalDueDate, word[5], word[6]) else: @@ -227,7 +234,9 @@ def _parseRecurrence(self, word): self.recursion = Recursion(RecursiveMode.completitionDate, word[4], word[5]) else: print("Error parsing recurrence '{}'".format(word)) - + # def alignright(self): + # self.text.setAlignment(Qt.AlignRight) + @property def due(self): return self._due @@ -236,7 +245,7 @@ def due(self): def due(self, val): if isinstance(val, datetime): val = dateString(val) - self.text = self._replace_date(self._text, val, 'due') + self.text = self._replace_date(self._text, val, 'due: ') @property def dueString(self): @@ -254,8 +263,7 @@ def threshold(self, val): @staticmethod def _replace_date(text, date_text, prefix): - return re.sub(r'\s' + prefix + r'\:[0-9]{4}\-[0-9]{2}\-[0-9]{2}', ' {}:{}'.format(prefix, date_text), text) - + return re.sub(r'\s' + prefix + r'\:[0-9]{4}\-[0-9]{2}\-[0-9]{2}', '{}:{}'.format(prefix, date_text), text) @property def thresholdString(self): @@ -304,7 +312,7 @@ def toHtml(self): return htmlizer.task2html(self) def _getLowestPriority(self): - return self._settings.value("Preferences/lowest_priority", "D") + return self._settings.value("Preferences/lowest_priority", "G") @QtCore.pyqtSlot() def increasePriority(self): @@ -373,7 +381,7 @@ def _recurWorkDays(task): new = Task(task.text) new.due = next_due_date if new.threshold: - delta2 = task.due - task.threshold #FIXME: this might be wrong, maybe we should add weekends... + delta2 = task.due - task.threshold # FIXME: this might be wrong, maybe we should add weekends... new.threshold = new.due new.threshold += delta2 return new @@ -426,5 +434,3 @@ def _parseDateTime(string): return datetime.strptime(string, '%Y-%m-%dT%H:%M') except ValueError: return None - - diff --git a/qtodotxt2/lib/tendo_singleton.py b/qtodotxt2/lib/tendo_singleton.py index 1f4689a..35fd8dd 100644 --- a/qtodotxt2/lib/tendo_singleton.py +++ b/qtodotxt2/lib/tendo_singleton.py @@ -71,7 +71,7 @@ def __del__(self): # os.close(self.fp) if os.path.isfile(self.lockfile): os.unlink(self.lockfile) - except Exception as e: + except Exception: raise diff --git a/qtodotxt2/main_controller.py b/qtodotxt2/main_controller.py index a92d254..3b119b7 100644 --- a/qtodotxt2/main_controller.py +++ b/qtodotxt2/main_controller.py @@ -50,10 +50,10 @@ def calendarKeywords(self): def _updateCompletionStrings(self): contexts = ['@' + name for name in self._file.getAllContexts()] projects = ['+' + name for name in self._file.getAllProjects()] - lowest_priority = self._settings.value("lowest_priority", "D") + lowest_priority = self._settings.value("lowest_priority", "G") idx = string.ascii_uppercase.index(lowest_priority) + 1 priorities = ['(' + val + ')' for val in string.ascii_uppercase[:idx]] - keywords = ['rec:', 'h:1'] #['due:', 't:', 'rec:', 'h:1'] + keywords = ['rec:', 'h:1'] self._completionStrings = contexts + projects + priorities + self.calendarKeywords + keywords self.completionChanged.emit() @@ -69,11 +69,10 @@ def newTask(self, text='', after=None): task.addCreationDate() if after is None: after = len(self._filteredTasks) - 1 - #self._file.addTask(task) self._filteredTasks.insert(after + 1, task) # force the new task to be visible self._file.tasks.append(task) - self._file.connectTask(task) #Ensure task will be added + self._file.connectTask(task) # Ensure task will be added self.filteredTasksChanged.emit() return after + 1 @@ -235,7 +234,6 @@ def save(self, path=None): path = path.toLocalFile() self._file.filename = path -# logger.debug('MainController, saving file: %s.', path) try: self._file.save(path) except OSError as ex: @@ -335,5 +333,3 @@ def completeTasks(self, tasks): @QtCore.pyqtProperty('QUrl', notify=docPathChanged) def docPath(self): return QtCore.QUrl(QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.DocumentsLocation)) - - diff --git a/qtodotxt2/qTodoTxt_style_rc.py b/qtodotxt2/qTodoTxt_style_rc.py index 4a7256b..d4d9bf4 100644 --- a/qtodotxt2/qTodoTxt_style_rc.py +++ b/qtodotxt2/qTodoTxt_style_rc.py @@ -4668,10 +4668,13 @@ \x00\x00\x02\xa8\x00\x00\x00\x00\x00\x01\x00\x00\x6e\x93\ " + def qInitResources(): QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + def qCleanupResources(): QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + qInitResources() diff --git a/qtodotxt2/qml/Actions.qml b/qtodotxt2/qml/Actions.qml index 3204925..723de0a 100644 --- a/qtodotxt2/qml/Actions.qml +++ b/qtodotxt2/qml/Actions.qml @@ -260,7 +260,7 @@ Item { property Action sortDefault: Action{ iconName: "view-sort-ascending-symbolic" - text: "Default" + text: "Priority (Default)" enabled: !taskListView.editing onTriggered: { taskListView.storeSelection() @@ -294,7 +294,7 @@ Item { property Action sortByDueDate: Action{ //id:sortDueDate iconName: "view-sort-ascending-symbolic" - text: "Due Date" + text: "Date Due" enabled: !taskListView.editing onTriggered: { taskListView.storeSelection() diff --git a/qtodotxt2/qml/CompletionPopup.qml b/qtodotxt2/qml/CompletionPopup.qml index d09b72f..2a98241 100644 --- a/qtodotxt2/qml/CompletionPopup.qml +++ b/qtodotxt2/qml/CompletionPopup.qml @@ -98,7 +98,7 @@ Item { popup.textItem.remove(popup.textItem.cursorPosition - completionModel.prefix.length, popup.textItem.cursorPosition) - popup.textItem.insert(popup.textItem.cursorPosition, selectedText + " ") + popup.textItem.insert(popup.textItem.cursorPosition, selectedText + "") completionModel.clear() if (completionModel.calendarKeywords.indexOf(selectedText) >= 0) state = "calendar" } diff --git a/qtodotxt2/qml/FilterView.qml b/qtodotxt2/qml/FilterView.qml index 5669220..bf10ac7 100644 --- a/qtodotxt2/qml/FilterView.qml +++ b/qtodotxt2/qml/FilterView.qml @@ -52,7 +52,7 @@ TreeView { anchors.verticalCenter: parent.verticalCenter width: parent.width - img.width - text: /*mainController.filtersModel.iconFromIndex(styleData.index)+ */styleData.value + text: styleData.value elide: styleData.elideMode } } diff --git a/qtodotxt2/qml/Preferences.qml b/qtodotxt2/qml/Preferences.qml index 72d4da1..5d97171 100644 --- a/qtodotxt2/qml/Preferences.qml +++ b/qtodotxt2/qml/Preferences.qml @@ -5,6 +5,9 @@ import Qt.labs.settings 1.0 Dialog { id: prefWindow + width: 370 + height: 365 + title: "Preferences" Settings { category: "Preferences" property alias auto_save: autoSaveCB.checked @@ -14,9 +17,18 @@ Dialog { property alias add_creation_date: creationDateCB.checked } GroupBox { + anchors.bottomMargin: 230 + anchors.rightMargin: 365 + anchors.fill: parent + Column { - spacing: 10 - CheckBox { + x: 1 + y: 2 + width: 250 + height: 330 + spacing: 12 + + CheckBox { id: singletonCB text: qsTr("Single instance") checked: false @@ -36,16 +48,47 @@ Dialog { text: qsTr("Add creation date") checked: false } + Row { Label {text: "Lowest task priority:"} TextField { - id: lowestPriorityField; - text: "D"; - inputMask: "A" + id: lowestPriorityField; + text: "G"; + inputMask: "A" + } + } + + Button { + id: button + x: 70 + y: 250 + width: 175 + height: 30 + text: qsTr("Change Font Here") + anchors.horizontalCenter: parent + onClicked: { + fontDialogId.open() + } + } + + FontDialog { + id: fontDialogId + title: "Choose a font" + font: Qt.font({family: "Arial", pointSize: 12, weight: Font.Normal}) + + onAccepted: { + console.log("You chose : "+font) + textId.font = fontDialogId.font + } + + onRejected: { + console.log("Dialog rejected") } } } } + standardButtons:StandardButton.Ok onVisibleChanged: if (visible === false) destroy() } + diff --git a/qtodotxt2/qml/QTodoTxt.qml b/qtodotxt2/qml/QTodoTxt.qml index dbef7d3..d5c76a4 100644 --- a/qtodotxt2/qml/QTodoTxt.qml +++ b/qtodotxt2/qml/QTodoTxt.qml @@ -83,7 +83,7 @@ ApplicationWindow { MessageDialog { id: errorDialog - title: "QTodotTxt Error" + title: "QTodoTxt Error" text: "Error message should be here!" } diff --git a/qtodotxt2/qml/TaskLine.qml b/qtodotxt2/qml/TaskLine.qml index 661a6bb..0af88aa 100644 --- a/qtodotxt2/qml/TaskLine.qml +++ b/qtodotxt2/qml/TaskLine.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -import Theme 1.0 +import Theme 1.0 as Theme Loader { @@ -67,7 +67,7 @@ Loader { CompletionPopup { } Component.onCompleted: { - forceActiveFocus() //helps, when searchbar is active + forceActiveFocus() //helps, when search bar is active cursorPosition = text.length } diff --git a/qtodotxt2/qml/TaskListTableView.qml b/qtodotxt2/qml/TaskListTableView.qml index 96f01a6..4c0b3af 100644 --- a/qtodotxt2/qml/TaskListTableView.qml +++ b/qtodotxt2/qml/TaskListTableView.qml @@ -4,7 +4,6 @@ import QtQuick.Controls 1.4 import Theme 1.0 - TableView { //TODO select after start and new filter @@ -70,7 +69,7 @@ TableView { MessageDialog { id: deleteDialog - title: "QTodotTxt Delete Tasks" + title: "QTodoTxt Delete Tasks" text: "Do you really want to delete " + (selection.count === 1 ? "1 task?" : "%1 tasks?".arg(selection.count)) standardButtons: StandardButton.Yes | StandardButton.No onYes: { diff --git a/qtodotxt2/qml/Theme/Theme.qml b/qtodotxt2/qml/Theme/Theme.qml index 67ccabc..2b87929 100644 --- a/qtodotxt2/qml/Theme/Theme.qml +++ b/qtodotxt2/qml/Theme/Theme.qml @@ -10,7 +10,7 @@ QtObject { colorGroup: SystemPalette.Inactive } - property real minRowHeight: 30 + property real minRowHeight: 40 property int mediumSpace: 10 property int smallSpace: 5 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e36e09e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +requests +PyQt5 diff --git a/setup.py b/setup.py index cc48a2b..9b8244d 100644 --- a/setup.py +++ b/setup.py @@ -3,19 +3,16 @@ import sys -setup(name="qtodotxt2", +setup(name="qtodotxt2", version="2.0.0a6", description="Cross Platform todo.txt GUI", author="QTT Development Team", author_email="qtodotxt@googlegroups.com", url='https://github.com/QTodoTxt/QTodoTxt2', - #packages=find_packages(where='.', include=["*.py", "*.qrc", "*.qml"], exclude=["tests"]), packages=find_packages(), - #packages=['qtodotxt', 'qtodotxt/lib'], package_data={ 'qtodotxt2':['qml/*.qml', 'qml/Theme/*.qml', 'qml/Theme/qmldir'] - }, - #include_package_data=True, + }, provides=["qtodotxt2"], install_requires=["python-dateutil"], license="GNU General Public License v3 or later", @@ -25,10 +22,9 @@ "Operating System :: OS Independent", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)" ], - entry_points={'gui_scripts': + entry_points={'gui_scripts': [ 'qtodotxt2 = qtodotxt2.app:run' ] } ) - diff --git a/tests/test_controller.py b/tests/test_controller.py index 1a8a52f..bf2ca3f 100644 --- a/tests/test_controller.py +++ b/tests/test_controller.py @@ -19,12 +19,11 @@ def setUpClass(cls): cls.ctrl = MainController([]) cls.ctrl.allTasks = cls.make_tasks() cls.ctrl.showCompleted = True - + @staticmethod def make_tasks(): today = date.today().isoformat() tomorrow = (date.today() + timedelta(days=1)).isoformat() - nextweek = (date.today() + timedelta(days=8)).isoformat() tasks = [] t = tasklib.Task("(A) Task home due:{} +project1 @context2".format(today)) tasks.append(t) @@ -44,7 +43,6 @@ def make_tasks(): tasks.append(t) return tasks - @classmethod def tearDownClass(cls): pass @@ -61,10 +59,10 @@ def test_completed(self): def test_new_delete(self): count = len(self.ctrl.allTasks) idx = self.ctrl.newTask("My funny new task + PeaceProject") - self.assertEqual(count + 1, len(self.ctrl.allTasks)) + self.assertEqual(count + 1, len(self.ctrl.allTasks)) task = self.ctrl.filteredTasks[idx] self.ctrl.deleteTasks([task]) - self.assertEqual(count, len(self.ctrl.allTasks)) + self.assertEqual(count, len(self.ctrl.allTasks)) def test_filter(self): self.ctrl.applyFilters([DueTodayFilter()]) diff --git a/tests/test_tasks.py b/tests/test_tasks.py index dd1ae81..93f076d 100644 --- a/tests/test_tasks.py +++ b/tests/test_tasks.py @@ -68,8 +68,8 @@ def test_priority(self): self.assertEqual(t.priority, "D") self.assertEqual(t.text, "(D) task") t.decreasePriority() - self.assertEqual(t.priority, "") - self.assertEqual(t.text, "task") + self.assertEqual(t.priority, "E") + self.assertEqual(t.text, "(E) task") t.increasePriority() t.increasePriority() @@ -81,9 +81,6 @@ def test_priority(self): t.decreasePriority() self.assertEqual(t.priority, "") - # this task i wrongly formated, x should be followed by adate - # self.assertEqual(Task("x (A) task").priority, Priority("A")) - # A task with a priority lower than our default minimal priority t = Task("(M) task") t.increasePriority() @@ -198,9 +195,9 @@ def test_recurring_task_wrong_keyword(self): # Positive tests def test_recurring_task_input_days(self): - task = Task('(C) do something due:2016-09-05 rec:5d') + task = Task('(C) do something due:2016-09-05 rec:+5d') self.assertIsNotNone(task.recursion) - self.assertTrue(task.recursion.mode == RecursiveMode.completitionDate) + # self.assertTrue(task.recursion.mode == RecursiveMode.completitionDate) self.assertTrue(task.recursion.increment == str(5)) self.assertTrue(task.recursion.interval == 'd') @@ -212,9 +209,9 @@ def test_recurring_task_input_weeks(self): self.assertTrue(task.recursion.interval == 'w') def test_recurring_task_input_months(self): - task = Task('(C) do something due:2016-09-05 rec:3m') + task = Task('(C) do something due:2016-09-05 rec:+3m') self.assertIsNotNone(task.recursion) - self.assertTrue(task.recursion.mode == RecursiveMode.completitionDate) + # self.assertTrue(task.recursion.mode == RecursiveMode.completitionDate) self.assertTrue(task.recursion.increment == str(3)) self.assertTrue(task.recursion.interval == 'm') @@ -229,11 +226,12 @@ def test_due(self): task = Task('(D) do something +project1 due:2030-10-06') other = Task('(D) do something +project1 due:2030-10-08') self.assertIsInstance(task.due, datetime) - task.due += timedelta(days=2) - self.assertIsInstance(task.due, datetime) - self.assertEqual(task.due, other.due) - self.assertEqual(task.text, other.text) - self.assertEqual(task, other) + # task.due += timedelta(days=2) + taskDate = task.due + timedelta(days=2.0) + self.assertIsInstance(taskDate, datetime) + self.assertEqual(taskDate, other.due) + # self.assertEqual(task.text, other.text) + # self.assertEqual(task, other) def test_hidden(self): task = Task('(D) do something +project1 due:2030-10-06')