Repository: mjdescy/TodoTxtMac
Branch: master
Commit: a2655cf4e1f7
Files: 266
Total size: 1.5 MB
Directory structure:
gitextract_uzrkr__8/
├── .gitignore
├── LICENSE.md
├── README.md
├── Sparkle.framework/
│ └── Versions/
│ └── A/
│ ├── Headers/
│ │ ├── SUAppcast.h
│ │ ├── SUAppcastItem.h
│ │ ├── SUErrors.h
│ │ ├── SUExport.h
│ │ ├── SUStandardVersionComparator.h
│ │ ├── SUUpdater.h
│ │ ├── SUVersionComparisonProtocol.h
│ │ ├── SUVersionDisplayProtocol.h
│ │ └── Sparkle.h
│ ├── Modules/
│ │ └── module.modulemap
│ ├── PrivateHeaders/
│ │ └── SUUnarchiver.h
│ ├── Resources/
│ │ ├── Autoupdate.app/
│ │ │ └── Contents/
│ │ │ ├── Info.plist
│ │ │ ├── MacOS/
│ │ │ │ └── Autoupdate
│ │ │ ├── PkgInfo
│ │ │ └── Resources/
│ │ │ ├── AppIcon.icns
│ │ │ ├── SUStatus.nib
│ │ │ ├── ar.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── ca.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── cs.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── da.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── de.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── el.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── en.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── es.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── fi.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── fr.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── he.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── is.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── it.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── ja.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── ko.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── nb.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── nl.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── pl.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── pt_BR.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── pt_PT.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── ro.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── ru.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── sk.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── sl.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── sv.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── th.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── tr.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── uk.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ ├── zh_CN.lproj/
│ │ │ │ └── Sparkle.strings
│ │ │ └── zh_TW.lproj/
│ │ │ └── Sparkle.strings
│ │ ├── Info.plist
│ │ ├── SUModelTranslation.plist
│ │ ├── SUStatus.nib
│ │ ├── ar.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── ca.lproj/
│ │ │ └── Sparkle.strings
│ │ ├── cs.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── da.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── de.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── el.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── en.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── es.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── fi.lproj/
│ │ │ └── Sparkle.strings
│ │ ├── fr.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── he.lproj/
│ │ │ └── Sparkle.strings
│ │ ├── is.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── it.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── ja.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── ko.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── nb.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── nl.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── pl.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── pt_BR.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── pt_PT.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── ro.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── ru.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── sk.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── sl.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── sv.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── th.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── tr.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── uk.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ ├── zh_CN.lproj/
│ │ │ ├── SUAutomaticUpdateAlert.nib
│ │ │ ├── SUUpdateAlert.nib
│ │ │ ├── SUUpdatePermissionPrompt.nib
│ │ │ └── Sparkle.strings
│ │ └── zh_TW.lproj/
│ │ ├── SUAutomaticUpdateAlert.nib
│ │ ├── SUUpdateAlert.nib
│ │ ├── SUUpdatePermissionPrompt.nib
│ │ └── Sparkle.strings
│ └── Sparkle
├── TodoTxtMac/
│ ├── Base.lproj/
│ │ ├── MainMenu.xib
│ │ ├── RelativeDates.strings
│ │ └── TTMDocument.xib
│ ├── FontNameTransformer.h
│ ├── FontNameTransformer.m
│ ├── Images.xcassets/
│ │ └── AppIcon.appiconset/
│ │ └── Contents.json
│ ├── NSDate+RelativeDates.h
│ ├── NSDate+RelativeDates.m
│ ├── NSMutableAttributableString+ColorRegExMatches.h
│ ├── NSMutableAttributableString+ColorRegExMatches.m
│ ├── NSUserDefaults+myColorSupport.h
│ ├── NSUserDefaults+myColorSupport.m
│ ├── RegExCategories.h
│ ├── RegExCategories.m
│ ├── RelativeDates.strings
│ ├── TTMAppController.h
│ ├── TTMAppController.m
│ ├── TTMAppDelegate.h
│ ├── TTMAppDelegate.m
│ ├── TTMDateUtility.h
│ ├── TTMDateUtility.m
│ ├── TTMDocument.h
│ ├── TTMDocument.m
│ ├── TTMDocumentStatusBarText.h
│ ├── TTMDocumentStatusBarText.m
│ ├── TTMFieldEditor.h
│ ├── TTMFieldEditor.m
│ ├── TTMFilterPredicates.h
│ ├── TTMFilterPredicates.m
│ ├── TTMFilters.xib
│ ├── TTMFiltersController.h
│ ├── TTMFiltersController.m
│ ├── TTMFindReplace.xib
│ ├── TTMPredicateEditorCompletedRowTemplate.h
│ ├── TTMPredicateEditorCompletedRowTemplate.m
│ ├── TTMPredicateEditorDateRowTemplate.h
│ ├── TTMPredicateEditorDateRowTemplate.m
│ ├── TTMPredicateEditorDueRowTemplate.h
│ ├── TTMPredicateEditorDueRowTemplate.m
│ ├── TTMPredicateEditorHiddenRowTemplate.h
│ ├── TTMPredicateEditorHiddenRowTemplate.m
│ ├── TTMPredicateEditorTextRowTemplate.h
│ ├── TTMPredicateEditorTextRowTemplate.m
│ ├── TTMPredicateEditorThresholdRowTemplate.h
│ ├── TTMPredicateEditorThresholdRowTemplate.m
│ ├── TTMPreferences.xib
│ ├── TTMPreferencesController.h
│ ├── TTMPreferencesController.m
│ ├── TTMTableView.h
│ ├── TTMTableView.m
│ ├── TTMTableViewDelegate.h
│ ├── TTMTableViewDelegate.m
│ ├── TTMTask.h
│ ├── TTMTask.m
│ ├── TTMTasklistMetadata.h
│ ├── TTMTasklistMetadata.m
│ ├── TTMTasklistMetadata.xib
│ ├── TodoTxtMac-Info.plist
│ ├── TodoTxtMac-Prefix.pch
│ ├── TodoTxtMac.entitlements
│ ├── en.lproj/
│ │ ├── Credits.rtf
│ │ ├── InfoPlist.strings
│ │ └── RelativeDates.strings
│ └── main.m
├── TodoTxtMac.xcodeproj/
│ ├── project.pbxproj
│ └── project.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ └── TodoTxtMac.xccheckout
├── TodoTxtMacTests/
│ ├── TTMDateUtility_UnitTests.m
│ ├── TTMTask_AppendText_UnitTests.m
│ ├── TTMTask_CompletionDate_UnitTests.m
│ ├── TTMTask_Contexts_UnitTests.m
│ ├── TTMTask_CreationDate_UnitTests.m
│ ├── TTMTask_DecreasePriority_UnitTests.m
│ ├── TTMTask_DecrementDueDate_UnitTests.m
│ ├── TTMTask_DecrementThresholdDate_UnitTests.m
│ ├── TTMTask_DueDate_UnitTests.m
│ ├── TTMTask_DueState_UnitTests.m
│ ├── TTMTask_IncreasePriority_UnitTests.m
│ ├── TTMTask_IncrementDueDate_UnitTests.m
│ ├── TTMTask_IncrementThresholdDate_UnitTests.m
│ ├── TTMTask_Init_UnitTests.m
│ ├── TTMTask_IsCompleted_UnitTests.m
│ ├── TTMTask_IsHidden_UnitTests.m
│ ├── TTMTask_MarkComplete_UnitTests.m
│ ├── TTMTask_MarkIncomplete_UnitTests.m
│ ├── TTMTask_Postpone_UnitTests.m
│ ├── TTMTask_PrependText_UnitTests.m
│ ├── TTMTask_Priority_UnitTests.m
│ ├── TTMTask_Projects_UnitTests.m
│ ├── TTMTask_RemoveDueDate_UnitTests.m
│ ├── TTMTask_RemovePriority_UnitTests.m
│ ├── TTMTask_RemoveThresholdDate_UnitTests.m
│ ├── TTMTask_ReplaceText_UnitTests.m
│ ├── TTMTask_SetDueDate_UnitTests.m
│ ├── TTMTask_SetThresholdDate_UnitTests.m
│ ├── TTMTask_ThresholdDate_UnitTests.m
│ ├── TTMTask_ThresholdState_UnitTests.m
│ ├── TTMTask_ToggleCompletion_UnitTests.m
│ ├── TTMTasklistMetadata_UnitTests.m
│ ├── TodoTxtMacTests-Info.plist
│ └── en.lproj/
│ └── InfoPlist.strings
└── dsa_pub.pem
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# taken from http://blog.illuminex.com/2009/10/better-sample-gitignore-file-for-xcode.html
# Mac OS X Finder and whatnot
.DS_Store
# Sparkle distribution Private Key (Don't check me in!)
dsa_priv.pem
# XCode (and ancestors) per-user config (very noisy, and not relevant)
*.mode1
*.mode1v3
*.mode2v3
*.perspective
*.perspectivev3
*.pbxuser
# Xcode 4 http://stackoverflow.com/questions/49478/git-ignore-file-for-xcode-projects
xcuserdata
# Generated files
VersionX-revision.h
# build products
build/
*.[oa]
# Other source repository archive directories (protects when importing)
.hg
.svn
CVS
# automatic backup files
*~.nib
*.swp
*~
*(Autosaved).rtfd/
Backup[ ]of[ ]*.pages/
Backup[ ]of[ ]*.key/
Backup[ ]of[ ]*.numbers/
================================================
FILE: LICENSE.md
================================================
TodoTxtMac: A Todo.txt todo manager for Mac OS X
Copyright (C) 2014 Michael Descy
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
The MIT License (MIT)
Copyright (C) 2014 Michael Descy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: README.md
================================================
# TodoTxtMac
# Overview
TodoTxtMac is a minimalist, keyboard-driven to-do manager for Mac OS X that conforms to the todo.txt format spec. Version 2.0.0 and up are supported only on Mac OS X 10.11 (El Capitan). Version 1.6.1 can be used on lower versions of Mac OS X, down to Mac OS X 10.8, though support is not guaranteed.
# Goals
This application is inspired by the [Todotxt.net][] application for Microsoft Windows with numerous improvements and modifications specific to the Mac OS X platform. It is designed to pair well with other todo.txt applications, such as [SwiftoDo][], [Todotxt.net][], [SimpleTask][], [topydo][], and [many others][].
From a design perspective the goal is to be the fastest, simplest, and cleanest implementation possible.
[todotxt.net]: http://benrhughes.github.io/todotxt.net/
[SwiftoDo]: https://itunes.apple.com/us/app/swiftodo-task-list-for-todo.txt/id1073798440?ls=1&mt=8
[SimpleTask]: https://play.google.com/store/apps/details?id=nl.mpcjanssen.todotxtholo
[topydo]: https://github.com/bram85/topydo
[many others]: http://todotxt.com
# Features
## General features
- Full compliance with the todo.txt format spec.
- Fully keyboard-driven, with one-key bindings for commonly-used commands.
- Multiple selection in the task list.
- Support for due dates, which are formatted "due:YYYY-MM-DD".
- Shortcuts to toggle completion, change priority, set due dates, and delete all selected tasks.
- Archive completed tasks (to done.txt), either on command or automatically.
- Preserves Windows or Unix line endings in the todo.txt file for cross-platform compatability.
- Automatic update checking.
- Displays general metadata (task counts, etc.) about the task list.
- Undo/redo support.
## Adding/removing tasks
- Paste one or more tasks into the task list from the clipboard.
- Import one or more tasks into the task list via drag-and-drop.
- Optionally prepend the task creation task on newly created tasks (including those pasted in from the clipboard).
- Copy selected tasks to the clipboard.
- Cut selected tasks to the clipboard.
- Reload file on command.
## Sorting and filtering
- Sort task list by priority, project, context, due date, etc.
- Filter task list.
- Quick filters: preset filters mapped to number keys.
- Search field for quick, ad-hoc filtering of the task list.
## Due dates
- Set arbitrary due dates on selected tasks.
- Increment, decrement, or remove due dates.
- Postpone tasks by X (user-entered) days.
- Supports relative due dates, such as "due:tomorrow" and "due:Saturday" for new tasks. These strings can be localized.
## Fonts and colors
- User-customizable font for the task list.
- Bold priorities in task list.
- Colors completed tasks in light gray and applies strikethrough.
- Colors overdue tasks in purple and tasks due today in red. Both these colors are user customizable.
- User-customizable colors for projects, contexts, due dates, threshold dates, creation dates, and arbitrary tags in task list.
## Mac-specific user interface features
- Autosave on change (Note that the title bar will say "Edited" even after autosaving, because this is the Mac's default behavior).
- Autocomplete project names.
- Autocomplete context names.
- Multiple document interface.
- Full screen mode.
- Open todo.txt files by dragging and dropping them onto the application icon.
# Keyboard Shortcuts
## Working with tasks
- N: new task
- J: move down to next task
- K: move up to previous task
- X: toggle task completion
- D or Backspace: delete task (with confirmation)
- U or Enter: update task
- P: postpone task by X (user-entered) days
- S: set due date
- Option+S: set threshold date
- I: set priority to user-entered value (A-Z)
- T: append text to end of selected tasks
- R: prepend text to beginning of selected tasks (after priority and creation date if they exist)
- A: archive completed tasks (archive file done.txt must be set)
- Command+Up: Increase priority
- Command+Down: Decrease priority
- Command+Left or Command+Right: Remove priority
- Command+C: Copy selected tasks to the clipboard
- Command+X: Cut selected tasks (copy to the clipboard and delete from task list)
- Command+Shift+V: Paste tasks into the task list from the clipboard
- Command+Option+Up: Increase due date by 1 day
- Command+Option+Down: Decrease due date by 1 day
- Command+Option+Left or Command+Option+Right: Remove due date
## Undo/redo
- Command+Z: Undo
- Command+Shift+Z: Redo
## Working with files
- Command+N: new file
- Command+O: open file
- Command+S: save file (forces the file to save immediately)
- .: reload file
- Command+I: view task list metadata (task counts, etc.)
- Command+W: close file
- Command+Option+W: close all files
## Sorting the task list
- Command+0: order in file
- Command+1: priority
- Command+2: project
- Command+3: context
- Command+4: due date
- Command+5: creation date
- Command+6: completion date
- Command+7: threshold date
- Command+8: alphabetical
## Filtering the task list
- Command+F: find within displayed tasks (moves focus to the search field)
- F: define quick filters
- 1: apply quick filter 1
- 2: apply quick filter 2
- 3: apply quick filter 3
- 4: apply quick filter 4
- 5: apply quick filter 5
- 6: apply quick filter 6
- 7: apply quick filter 7
- 8: apply quick filter 8
- 9: apply quick filter 9
- 0: remove applied filter
# Features Not Planned
- This application is not meant for direct reordering of tasks in the todo.txt file.
- This application does not retain blank lines in the todo.txt file.
- This application does not support line breaks, long-form notes, attachments, or other features not part of the todo.txt format specification.
# Frequently Asked Questions (FAQ)
## Is there a preference to re-open my todo.txt file on launch?
Yes, but most people will not need such a preference, because the default behavior of TodoTxtMac is to reopen whatever todo.txt files were open when you last quit the app. To enjoy this behavior, do not close your todo.txt file's window prior to quitting the app.
If the TodoTxtMac is not reopening your files, or keeping a list of them in the "File > Open Recent" menu, then you should check the following preferences under System Preferences > General:
1. "Close windows when quitting an app" must be unchecked.
2. "Recent items" must not be "None".
If you need to force TodoTxtMac to open a particular todo file on launch, you may set a default todo.txt file in TodoTxtMac's Preferences > Startup.
You may also force TodoTxtMac to open a particular todo file on launch, you may launch the app with the command-line argument "todo-file", in the Terminal, as follows:
$ open /Applications/TodoTxtMac.app --args -todo-file ~/Documents/todo.txt
## Is this application Dropbox-enabled?
No. Unlike the official Todo.txt iOS application, this application does not call Dropbox's API. You can sync your file outside of TodoTxtMac via Dropbox or other services.
## TodoTxtMac says my todo.txt file cannot be autosaved. The file has been changed by another application.
Your todo.txt file can get modified outside of TodoTxtMac, especially if you are syncing the file via Dropbox or a similar service. TodoTxtMac uses Cocoa's default document object model to handle the file interactions. This means that the application will warn you of file changes that came from outside the application when you try to make changes to the file, not at the moment the file was changed. To avoid file conflicts, try the following strategies:
1. Reload your TodoTxtMac file manually (press `.`) before making changes to it, if you believe the file was updated (by Dropbox for example) recently.
2. Close TodoTxtMac when not using it for extended periods.
3. When presented with the option to "Save Anyway" or "Revert" changes, always revert changes. You will have to re-do your last action in TodoTxtMac, but you will not lose the changes that originated outside the application.
## Will this project be ported from Objective C to Swift?
When Apple officially deprecates Objective C, the plan is to migrate this project to Swift.
# License
This application is dual-licensed under the GNU General Public License and the MIT License. See LICENSE.txt for full license information.
# For Contributors
## Source Code Conventions
I am striving for very clean code. I am following the following general coding conventions:
- For clarity, limit nesting of brackets to two sets per line, as in: `[[thisString stringValue] isEqualToString:@"otherStringValue"]`.
- Maximum line length of 100 characters.
- Indent with spaces rather than tabs.
- Always use curly braces for conditionals and loops.
- Use descriptive variable and method names.
## Pull Requests
The project uses [git-flow] to implement Vincent Driessen's [branching model]. All pull requests should be directed at the "develop" branch.
[git-flow]: https://github.com/nvie/gitflow
[branching model]: http://nvie.com/posts/a-successful-git-branching-model/
# Credits/Thanks
Thanks to Gina Trapani who created the [Todo.txt][] format and the community of developers who created the command line tools and iOS/Android apps.
Thanks to Ben Hughes whose Windows application [todotxt.net][] formed the basis of this application's design and feature set. Todotxt.net is a fantastic program and did not have an analog on the Mac. After starting my application, I contributed some patches to todotxt.net and am happy to be a contributor on such a great project.
Thanks to Josh Wright <@BendyTree> for his [RegExCategories][] library.
Thanks to Sam Daitzman <@sdaitzman> for the application icon.
Thanks to Andy Matuschak and the other contributors for the [Sparkle framework].
[Todo.txt]: http://www.todotxt.com
[RegExCategories]: https://github.com/bendytree/Objective-C-RegEx-Categories
[OK Icon]: http://vector.me/browse/329308/ok_icon
[Vector.me]: http://vector.me/
[Sparkle framework]: http://sparkle.andymatuschak.org/
================================================
FILE: Sparkle.framework/Versions/A/Headers/SUAppcast.h
================================================
//
// SUAppcast.h
// Sparkle
//
// Created by Andy Matuschak on 3/12/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUAPPCAST_H
#define SUAPPCAST_H
#import
#import "SUExport.h"
@class SUAppcastItem;
SU_EXPORT @interface SUAppcast : NSObject
@property (copy) NSString *userAgentString;
@property (copy) NSDictionary *httpHeaders;
- (void)fetchAppcastFromURL:(NSURL *)url completionBlock:(void (^)(NSError *))err;
- (SUAppcast *)copyWithoutDeltaUpdates;
@property (readonly, copy) NSArray *items;
@end
#endif
================================================
FILE: Sparkle.framework/Versions/A/Headers/SUAppcastItem.h
================================================
//
// SUAppcastItem.h
// Sparkle
//
// Created by Andy Matuschak on 3/12/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUAPPCASTITEM_H
#define SUAPPCASTITEM_H
#import
#import "SUExport.h"
SU_EXPORT @interface SUAppcastItem : NSObject
@property (copy, readonly) NSString *title;
@property (copy, readonly) NSDate *date;
@property (copy, readonly) NSString *itemDescription;
@property (strong, readonly) NSURL *releaseNotesURL;
@property (copy, readonly) NSString *DSASignature;
@property (copy, readonly) NSString *minimumSystemVersion;
@property (copy, readonly) NSString *maximumSystemVersion;
@property (strong, readonly) NSURL *fileURL;
@property (copy, readonly) NSString *versionString;
@property (copy, readonly) NSString *displayVersionString;
@property (copy, readonly) NSDictionary *deltaUpdates;
@property (strong, readonly) NSURL *infoURL;
// Initializes with data from a dictionary provided by the RSS class.
- (instancetype)initWithDictionary:(NSDictionary *)dict;
- (instancetype)initWithDictionary:(NSDictionary *)dict failureReason:(NSString **)error;
@property (getter=isDeltaUpdate, readonly) BOOL deltaUpdate;
@property (getter=isCriticalUpdate, readonly) BOOL criticalUpdate;
@property (getter=isInformationOnlyUpdate, readonly) BOOL informationOnlyUpdate;
// Returns the dictionary provided in initWithDictionary; this might be useful later for extensions.
@property (readonly, copy) NSDictionary *propertiesDictionary;
- (NSURL *)infoURL;
@end
#endif
================================================
FILE: Sparkle.framework/Versions/A/Headers/SUErrors.h
================================================
//
// SUErrors.h
// Sparkle
//
// Created by C.W. Betts on 10/13/14.
// Copyright (c) 2014 Sparkle Project. All rights reserved.
//
#ifndef SUERRORS_H
#define SUERRORS_H
#import
#import "SUExport.h"
/**
* Error domain used by Sparkle
*/
SU_EXPORT extern NSString *const SUSparkleErrorDomain;
typedef NS_ENUM(OSStatus, SUError) {
// Appcast phase errors.
SUAppcastParseError = 1000,
SUNoUpdateError = 1001,
SUAppcastError = 1002,
SURunningFromDiskImageError = 1003,
// Downlaod phase errors.
SUTemporaryDirectoryError = 2000,
// Extraction phase errors.
SUUnarchivingError = 3000,
SUSignatureError = 3001,
// Installation phase errors.
SUFileCopyFailure = 4000,
SUAuthenticationFailure = 4001,
SUMissingUpdateError = 4002,
SUMissingInstallerToolError = 4003,
SURelaunchError = 4004,
SUInstallationError = 4005,
SUDowngradeError = 4006,
// System phase errors
SUSystemPowerOffError = 5000
};
#endif
================================================
FILE: Sparkle.framework/Versions/A/Headers/SUExport.h
================================================
//
// SUExport.h
// Sparkle
//
// Created by Jake Petroules on 2014-08-23.
// Copyright (c) 2014 Sparkle Project. All rights reserved.
//
#ifndef SUEXPORT_H
#define SUEXPORT_H
#ifdef BUILDING_SPARKLE
#define SU_EXPORT __attribute__((visibility("default")))
#else
#define SU_EXPORT
#endif
#endif
================================================
FILE: Sparkle.framework/Versions/A/Headers/SUStandardVersionComparator.h
================================================
//
// SUStandardVersionComparator.h
// Sparkle
//
// Created by Andy Matuschak on 12/21/07.
// Copyright 2007 Andy Matuschak. All rights reserved.
//
#ifndef SUSTANDARDVERSIONCOMPARATOR_H
#define SUSTANDARDVERSIONCOMPARATOR_H
#import
#import "SUExport.h"
#import "SUVersionComparisonProtocol.h"
/*!
Sparkle's default version comparator.
This comparator is adapted from MacPAD, by Kevin Ballard.
It's "dumb" in that it does essentially string comparison,
in components split by character type.
*/
SU_EXPORT @interface SUStandardVersionComparator : NSObject
/*!
Returns a singleton instance of the comparator.
*/
+ (SUStandardVersionComparator *)defaultComparator;
/*!
Compares version strings through textual analysis.
See the implementation for more details.
*/
- (NSComparisonResult)compareVersion:(NSString *)versionA toVersion:(NSString *)versionB;
@end
#endif
================================================
FILE: Sparkle.framework/Versions/A/Headers/SUUpdater.h
================================================
//
// SUUpdater.h
// Sparkle
//
// Created by Andy Matuschak on 1/4/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUUPDATER_H
#define SUUPDATER_H
#import
#import "SUExport.h"
#import "SUVersionComparisonProtocol.h"
#import "SUVersionDisplayProtocol.h"
@class SUAppcastItem, SUAppcast;
@protocol SUUpdaterDelegate;
/*!
The main API in Sparkle for controlling the update mechanism.
This class is used to configure the update paramters as well as manually
and automatically schedule and control checks for updates.
*/
SU_EXPORT @interface SUUpdater : NSObject
@property (unsafe_unretained) IBOutlet id delegate;
+ (SUUpdater *)sharedUpdater;
+ (SUUpdater *)updaterForBundle:(NSBundle *)bundle;
- (instancetype)initForBundle:(NSBundle *)bundle;
@property (readonly, strong) NSBundle *hostBundle;
@property (strong, readonly) NSBundle *sparkleBundle;
@property BOOL automaticallyChecksForUpdates;
@property NSTimeInterval updateCheckInterval;
/*!
* The URL of the appcast used to download update information.
*
* This property must be called on the main thread.
*/
@property (copy) NSURL *feedURL;
@property (nonatomic, copy) NSString *userAgentString;
@property (copy) NSDictionary *httpHeaders;
@property BOOL sendsSystemProfile;
@property BOOL automaticallyDownloadsUpdates;
@property (nonatomic, copy) NSString *decryptionPassword;
/*!
Explicitly checks for updates and displays a progress dialog while doing so.
This method is meant for a main menu item.
Connect any menu item to this action in Interface Builder,
and Sparkle will check for updates and report back its findings verbosely
when it is invoked.
*/
- (IBAction)checkForUpdates:(id)sender;
/*!
Checks for updates, but does not display any UI unless an update is found.
This is meant for programmatically initating a check for updates. That is,
it will display no UI unless it actually finds an update, in which case it
proceeds as usual.
If the fully automated updating is turned on, however, this will invoke that
behavior, and if an update is found, it will be downloaded and prepped for
installation.
*/
- (void)checkForUpdatesInBackground;
/*!
Checks for updates and, if available, immediately downloads and installs them.
A progress dialog is shown but the user will never be prompted to read the
release notes.
You may want to respond to the userDidCancelDownload delegate method in case
the user clicks the "Cancel" button while the update is downloading.
*/
- (void)installUpdatesIfAvailable;
/*!
Returns the date of last update check.
\returns \c nil if no check has been performed.
*/
@property (readonly, copy) NSDate *lastUpdateCheckDate;
/*!
Begins a "probing" check for updates which will not actually offer to
update to that version.
However, the delegate methods
SUUpdaterDelegate::updater:didFindValidUpdate: and
SUUpdaterDelegate::updaterDidNotFindUpdate: will be called,
so you can use that information in your UI.
*/
- (void)checkForUpdateInformation;
/*!
Appropriately schedules or cancels the update checking timer according to
the preferences for time interval and automatic checks.
This call does not change the date of the next check,
but only the internal NSTimer.
*/
- (void)resetUpdateCycle;
@property (readonly) BOOL updateInProgress;
@end
// -----------------------------------------------------------------------------
// SUUpdater Notifications for events that might be interesting to more than just the delegate
// The updater will be the notification object
// -----------------------------------------------------------------------------
SU_EXPORT extern NSString *const SUUpdaterDidFinishLoadingAppCastNotification;
SU_EXPORT extern NSString *const SUUpdaterDidFindValidUpdateNotification;
SU_EXPORT extern NSString *const SUUpdaterDidNotFindUpdateNotification;
SU_EXPORT extern NSString *const SUUpdaterWillRestartNotification;
#define SUUpdaterWillRelaunchApplicationNotification SUUpdaterWillRestartNotification;
#define SUUpdaterWillInstallUpdateNotification SUUpdaterWillRestartNotification;
// Key for the SUAppcastItem object in the SUUpdaterDidFindValidUpdateNotification userInfo
SU_EXPORT extern NSString *const SUUpdaterAppcastItemNotificationKey;
// Key for the SUAppcast object in the SUUpdaterDidFinishLoadingAppCastNotification userInfo
SU_EXPORT extern NSString *const SUUpdaterAppcastNotificationKey;
// -----------------------------------------------------------------------------
// SUUpdater Delegate:
// -----------------------------------------------------------------------------
/*!
Provides methods to control the behavior of an SUUpdater object.
*/
@protocol SUUpdaterDelegate
@optional
/*!
Returns whether to allow Sparkle to pop up.
For example, this may be used to prevent Sparkle from interrupting a setup assistant.
\param updater The SUUpdater instance.
*/
- (BOOL)updaterMayCheckForUpdates:(SUUpdater *)updater;
/*!
Returns additional parameters to append to the appcast URL's query string.
This is potentially based on whether or not Sparkle will also be sending along the system profile.
\param updater The SUUpdater instance.
\param sendingProfile Whether the system profile will also be sent.
\return An array of dictionaries with keys: "key", "value", "displayKey", "displayValue", the latter two being specifically for display to the user.
*/
- (NSArray *)feedParametersForUpdater:(SUUpdater *)updater sendingSystemProfile:(BOOL)sendingProfile;
/*!
Returns a custom appcast URL.
Override this to dynamically specify the entire URL.
\param updater The SUUpdater instance.
*/
- (NSString *)feedURLStringForUpdater:(SUUpdater *)updater;
/*!
Returns whether Sparkle should prompt the user about automatic update checks.
Use this to override the default behavior.
\param updater The SUUpdater instance.
*/
- (BOOL)updaterShouldPromptForPermissionToCheckForUpdates:(SUUpdater *)updater;
/*!
Called after Sparkle has downloaded the appcast from the remote server.
Implement this if you want to do some special handling with the appcast once it finishes loading.
\param updater The SUUpdater instance.
\param appcast The appcast that was downloaded from the remote server.
*/
- (void)updater:(SUUpdater *)updater didFinishLoadingAppcast:(SUAppcast *)appcast;
/*!
Returns the item in the appcast corresponding to the update that should be installed.
If you're using special logic or extensions in your appcast,
implement this to use your own logic for finding a valid update, if any,
in the given appcast.
\param appcast The appcast that was downloaded from the remote server.
\param updater The SUUpdater instance.
*/
- (SUAppcastItem *)bestValidUpdateInAppcast:(SUAppcast *)appcast forUpdater:(SUUpdater *)updater;
/*!
Called when a valid update is found by the update driver.
\param updater The SUUpdater instance.
\param item The appcast item corresponding to the update that is proposed to be installed.
*/
- (void)updater:(SUUpdater *)updater didFindValidUpdate:(SUAppcastItem *)item;
/*!
Called when a valid update is not found.
\param updater The SUUpdater instance.
*/
- (void)updaterDidNotFindUpdate:(SUUpdater *)updater;
/*!
Called immediately before downloading the specified update.
\param updater The SUUpdater instance.
\param item The appcast item corresponding to the update that is proposed to be downloaded.
\param request The mutable URL request that will be used to download the update.
*/
- (void)updater:(SUUpdater *)updater willDownloadUpdate:(SUAppcastItem *)item withRequest:(NSMutableURLRequest *)request;
/*!
Called after the specified update failed to download.
\param updater The SUUpdater instance.
\param item The appcast item corresponding to the update that failed to download.
\param error The error generated by the failed download.
*/
- (void)updater:(SUUpdater *)updater failedToDownloadUpdate:(SUAppcastItem *)item error:(NSError *)error;
/*!
Called when the user clicks the cancel button while and update is being downloaded.
\param updater The SUUpdater instance.
*/
- (void)userDidCancelDownload:(SUUpdater *)updater;
/*!
Called immediately before installing the specified update.
\param updater The SUUpdater instance.
\param item The appcast item corresponding to the update that is proposed to be installed.
*/
- (void)updater:(SUUpdater *)updater willInstallUpdate:(SUAppcastItem *)item;
/*!
Returns whether the relaunch should be delayed in order to perform other tasks.
This is not called if the user didn't relaunch on the previous update,
in that case it will immediately restart.
\param updater The SUUpdater instance.
\param item The appcast item corresponding to the update that is proposed to be installed.
\param invocation The invocation that must be completed before continuing with the relaunch.
\return \c YES to delay the relaunch until \p invocation is invoked.
*/
- (BOOL)updater:(SUUpdater *)updater shouldPostponeRelaunchForUpdate:(SUAppcastItem *)item untilInvoking:(NSInvocation *)invocation;
/*!
Returns whether the application should be relaunched at all.
Some apps \b cannot be relaunched under certain circumstances.
This method can be used to explicitly prevent a relaunch.
\param updater The SUUpdater instance.
*/
- (BOOL)updaterShouldRelaunchApplication:(SUUpdater *)updater;
/*!
Called immediately before relaunching.
\param updater The SUUpdater instance.
*/
- (void)updaterWillRelaunchApplication:(SUUpdater *)updater;
/*!
Returns an object that compares version numbers to determine their arithmetic relation to each other.
This method allows you to provide a custom version comparator.
If you don't implement this method or return \c nil,
the standard version comparator will be used.
\sa SUStandardVersionComparator
\param updater The SUUpdater instance.
*/
- (id)versionComparatorForUpdater:(SUUpdater *)updater;
/*!
Returns an object that formats version numbers for display to the user.
If you don't implement this method or return \c nil,
the standard version formatter will be used.
\sa SUUpdateAlert
\param updater The SUUpdater instance.
*/
- (id)versionDisplayerForUpdater:(SUUpdater *)updater;
/*!
Returns the path which is used to relaunch the client after the update is installed.
The default is the path of the host bundle.
\param updater The SUUpdater instance.
*/
- (NSString *)pathToRelaunchForUpdater:(SUUpdater *)updater;
/*!
Called before an updater shows a modal alert window,
to give the host the opportunity to hide attached windows that may get in the way.
\param updater The SUUpdater instance.
*/
- (void)updaterWillShowModalAlert:(SUUpdater *)updater;
/*!
Called after an updater shows a modal alert window,
to give the host the opportunity to hide attached windows that may get in the way.
\param updater The SUUpdater instance.
*/
- (void)updaterDidShowModalAlert:(SUUpdater *)updater;
/*!
Called when an update is scheduled to be silently installed on quit.
\param updater The SUUpdater instance.
\param item The appcast item corresponding to the update that is proposed to be installed.
\param invocation Can be used to trigger an immediate silent install and relaunch.
*/
- (void)updater:(SUUpdater *)updater willInstallUpdateOnQuit:(SUAppcastItem *)item immediateInstallationInvocation:(NSInvocation *)invocation;
/*!
Calls after an update that was scheduled to be silently installed on quit has been canceled.
\param updater The SUUpdater instance.
\param item The appcast item corresponding to the update that was proposed to be installed.
*/
- (void)updater:(SUUpdater *)updater didCancelInstallUpdateOnQuit:(SUAppcastItem *)item;
/*!
Called after an update is aborted due to an error.
\param updater The SUUpdater instance.
\param error The error that caused the abort
*/
- (void)updater:(SUUpdater *)updater didAbortWithError:(NSError *)error;
@end
#endif
================================================
FILE: Sparkle.framework/Versions/A/Headers/SUVersionComparisonProtocol.h
================================================
//
// SUVersionComparisonProtocol.h
// Sparkle
//
// Created by Andy Matuschak on 12/21/07.
// Copyright 2007 Andy Matuschak. All rights reserved.
//
#ifndef SUVERSIONCOMPARISONPROTOCOL_H
#define SUVERSIONCOMPARISONPROTOCOL_H
#import
#import "SUExport.h"
/*!
Provides version comparison facilities for Sparkle.
*/
@protocol SUVersionComparison
/*!
An abstract method to compare two version strings.
Should return NSOrderedAscending if b > a, NSOrderedDescending if b < a,
and NSOrderedSame if they are equivalent.
*/
- (NSComparisonResult)compareVersion:(NSString *)versionA toVersion:(NSString *)versionB; // *** MAY BE CALLED ON NON-MAIN THREAD!
@end
#endif
================================================
FILE: Sparkle.framework/Versions/A/Headers/SUVersionDisplayProtocol.h
================================================
//
// SUVersionDisplayProtocol.h
// EyeTV
//
// Created by Uli Kusterer on 08.12.09.
// Copyright 2009 Elgato Systems GmbH. All rights reserved.
//
#import
#import "SUExport.h"
/*!
Applies special display formatting to version numbers.
*/
@protocol SUVersionDisplay
/*!
Formats two version strings.
Both versions are provided so that important distinguishing information
can be displayed while also leaving out unnecessary/confusing parts.
*/
- (void)formatVersion:(NSString **)inOutVersionA andVersion:(NSString **)inOutVersionB;
@end
================================================
FILE: Sparkle.framework/Versions/A/Headers/Sparkle.h
================================================
//
// Sparkle.h
// Sparkle
//
// Created by Andy Matuschak on 3/16/06. (Modified by CDHW on 23/12/07)
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SPARKLE_H
#define SPARKLE_H
#import
// This list should include the shared headers. It doesn't matter if some of them aren't shared (unless
// there are name-space collisions) so we can list all of them to start with:
#import "SUAppcast.h"
#import "SUAppcastItem.h"
#import "SUStandardVersionComparator.h"
#import "SUUpdater.h"
#import "SUVersionComparisonProtocol.h"
#import "SUVersionDisplayProtocol.h"
#import "SUErrors.h"
#endif
================================================
FILE: Sparkle.framework/Versions/A/Modules/module.modulemap
================================================
framework module Sparkle {
umbrella header "Sparkle.h"
export *
module * { export * }
}
================================================
FILE: Sparkle.framework/Versions/A/PrivateHeaders/SUUnarchiver.h
================================================
//
// SUUnarchiver.h
// Sparkle
//
// Created by Andy Matuschak on 3/16/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUUNARCHIVER_H
#define SUUNARCHIVER_H
#import
@class SUHost;
@protocol SUUnarchiverDelegate;
@interface SUUnarchiver : NSObject
@property (copy, readonly) NSString *archivePath;
@property (copy, readonly) NSString *updateHostBundlePath;
@property (copy, readonly) NSString *decryptionPassword;
@property (weak) id delegate;
+ (SUUnarchiver *)unarchiverForPath:(NSString *)path updatingHostBundlePath:(NSString *)host withPassword:(NSString *)decryptionPassword;
- (void)start;
@end
@protocol SUUnarchiverDelegate
- (void)unarchiverDidFinish:(SUUnarchiver *)unarchiver;
- (void)unarchiverDidFail:(SUUnarchiver *)unarchiver;
@optional
- (void)unarchiver:(SUUnarchiver *)unarchiver extractedProgress:(double)progress;
@end
#endif
================================================
FILE: Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Info.plist
================================================
BuildMachineOSBuild
15E49a
CFBundleDevelopmentRegion
English
CFBundleExecutable
Autoupdate
CFBundleIconFile
AppIcon
CFBundleIdentifier
org.sparkle-project.Sparkle.Autoupdate
CFBundleInfoDictionaryVersion
6.0
CFBundlePackageType
APPL
CFBundleShortVersionString
1.14.0
CFBundleSignature
????
CFBundleSupportedPlatforms
MacOSX
CFBundleVersion
1.14.0
DTCompiler
com.apple.compilers.llvm.clang.1_0
DTPlatformBuild
7C1002
DTPlatformVersion
GM
DTSDKBuild
15C43
DTSDKName
macosx10.11
DTXcode
0721
DTXcodeBuild
7C1002
LSBackgroundOnly
1
LSMinimumSystemVersion
10.7
LSUIElement
1
NSMainNibFile
MainMenu
NSPrincipalClass
NSApplication
================================================
FILE: Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/PkgInfo
================================================
APPL????
================================================
FILE: Sparkle.framework/Versions/A/Resources/Info.plist
================================================
BuildMachineOSBuild
15E49a
CFBundleDevelopmentRegion
en
CFBundleExecutable
Sparkle
CFBundleIdentifier
org.sparkle-project.Sparkle
CFBundleInfoDictionaryVersion
6.0
CFBundleName
Sparkle
CFBundlePackageType
FMWK
CFBundleShortVersionString
1.14.0
CFBundleSignature
????
CFBundleSupportedPlatforms
MacOSX
CFBundleVersion
1.14.0
DTCompiler
com.apple.compilers.llvm.clang.1_0
DTPlatformBuild
7C1002
DTPlatformVersion
GM
DTSDKBuild
15C43
DTSDKName
macosx10.11
DTXcode
0721
DTXcodeBuild
7C1002
================================================
FILE: Sparkle.framework/Versions/A/Resources/SUModelTranslation.plist
================================================
ADP2,1
Developer Transition Kit
iMac1,1
iMac G3 (Rev A-D)
iMac4,1
iMac (Core Duo)
iMac4,2
iMac for Education (17 inch, Core Duo)
iMac5,1
iMac (Core 2 Duo, 17 or 20 inch, SuperDrive)
iMac5,2
iMac (Core 2 Duo, 17 inch, Combo Drive)
iMac6,1
iMac (Core 2 Duo, 24 inch, SuperDrive)
iMac7,1
iMac Intel Core 2 Duo (aluminum enclosure)
iMac8,1
iMac (Core 2 Duo, 20 or 24 inch, Early 2008 )
iMac9,1
iMac (Core 2 Duo, 20 or 24 inch, Early or Mid 2009 )
iMac10,1
iMac (Core 2 Duo, 21.5 or 27 inch, Late 2009 )
iMac11,1
iMac (Core i5 or i7, 27 inch Late 2009)
iMac11,2
21.5" iMac (mid 2010)
iMac11,3
iMac (Core i5 or i7, 27 inch Mid 2010)
iMac12,1
iMac (Core i3 or i5 or i7, 21.5 inch Mid 2010 or Late 2011)
iMac12,2
iMac (Core i5 or i7, 27 inch Mid 2011)
iMac13,1
iMac (Core i3 or i5 or i7, 21.5 inch Late 2012 or Early 2013)
iMac13,2
iMac (Core i5 or i7, 27 inch Late 2012)
iMac14,1
iMac (Core i5, 21.5 inch Late 2013)
iMac14,2
iMac (Core i5 or i7, 27 inch Late 2013)
iMac14,3
iMac (Core i5 or i7, 21.5 inch Late 2013)
iMac14,4
iMac (Core i5, 21.5 inch Mid 2014)
iMac15,1
iMac (Retina 5K Core i5 or i7, 27 inch Late 2014 or Mid 2015)
iMac16,1
iMac (Core i5, 21,5 inch Late 2015)
iMac16,2
iMac (Retina 4K Core i5 or i7, 21.5 inch Late 2015)
iMac17,1
iMac (Retina 5K Core i5 or i7, 27 inch Late 2015)
MacBook1,1
MacBook (Core Duo)
MacBook2,1
MacBook (Core 2 Duo)
MacBook4,1
MacBook (Core 2 Duo Feb 2008)
MacBook5,1
MacBook (Core 2 Duo, Late 2008, Unibody)
MacBook5,2
MacBook (Core 2 Duo, Early 2009, White)
MacBook6,1
MacBook (Core 2 Duo, Late 2009, Unibody)
MacBook7,1
MacBook (Core 2 Duo, Mid 2010, White)
MacBook8,1
MacBook (Core M, 12 inch, Early 2015)
MacBookAir1,1
MacBook Air (Core 2 Duo, 13 inch, Early 2008)
MacBookAir2,1
MacBook Air (Core 2 Duo, 13 inch, Mid 2009)
MacBookAir3,1
MacBook Air (Core 2 Duo, 11 inch, Late 2010)
MacBookAir3,2
MacBook Air (Core 2 Duo, 13 inch, Late 2010)
MacBookAir4,1
MacBook Air (Core i5 or i7, 11 inch, Mid 2011)
MacBookAir4,2
MacBook Air (Core i5 or i7, 13 inch, Mid 2011)
MacBookAir5,1
MacBook Air (Core i5 or i7, 11 inch, Mid 2012)
MacBookAir5,2
MacBook Air (Core i5 or i7, 13 inch, Mid 2012)
MacBookAir6,1
MacBook Air (Core i5 or i7, 11 inch, Mid 2013 or Early 2014)
MacBookAir6,2
MacBook Air (Core i5 or i7, 13 inch, Mid 2013 or Early 2014)
MacBookAir7,1
MacBook Air (Core i5 or i7, 11 inch, Early 2015)
MacBookAir7,2
MacBook Air (Core i5 or i7, 13 inch, Early 2015)
MacBookPro1,1
MacBook Pro Core Duo (15-inch)
MacBookPro1,2
MacBook Pro Core Duo (17-inch)
MacBookPro2,1
MacBook Pro Core 2 Duo (17-inch)
MacBookPro2,2
MacBook Pro Core 2 Duo (15-inch)
MacBookPro3,1
MacBook Pro Core 2 Duo (15-inch LED, Core 2 Duo)
MacBookPro3,2
MacBook Pro Core 2 Duo (17-inch HD, Core 2 Duo)
MacBookPro4,1
MacBook Pro (Core 2 Duo Feb 2008)
MacBookPro5,1
MacBook Pro Intel Core 2 Duo (aluminum unibody)
MacBookPro5,2
MacBook Pro Intel Core 2 Duo (aluminum unibody)
MacBookPro5,3
MacBook Pro Intel Core 2 Duo (aluminum unibody)
MacBookPro5,4
MacBook Pro Intel Core 2 Duo (aluminum unibody)
MacBookPro5,5
MacBook Pro Intel Core 2 Duo (aluminum unibody)
MacBookPro6,1
MacBook Pro Intel Core i5, Intel Core i7 (mid 2010)
MacBookPro6,2
MacBook Pro Intel Core i5, Intel Core i7 (mid 2010)
MacBookPro7,1
MacBook Pro Intel Core 2 Duo (mid 2010)
MacBookPro8,1
MacBook Pro Intel Core i5, Intel Core i7, 13" (early 2011)
MacBookPro8,2
MacBook Pro Intel Core i7, 15" (early 2011)
MacBookPro8,3
MacBook Pro Intel Core i7, 17" (early 2011)
MacBookPro9,1
MacBook Pro (15-inch, Mid 2012)
MacBookPro9,2
MacBook Pro (13-inch, Mid 2012)
MacBookPro10,1
MacBook Pro (Retina, Mid 2012)
MacBookPro10,2
MacBook Pro (Retina, 13-inch, Late 2012)
MacBookPro11,1
MacBook Pro (Retina, 13-inch, Late 2013)
MacBookPro11,2
MacBook Pro (Retina, 15-inch, Late 2013)
MacBookPro11,3
MacBook Pro (Retina, 15-inch, Late 2013)
MacbookPro11,4
MacBook Pro (Retina, 15-inch, Mid 2015)
MacbookPro11,5
MacBook Pro (Retina, 15-inch, Mid 2015)
MacbookPro12,1
MacBook Pro (Retina, 13-inch, Early 2015)
Macmini1,1
Mac Mini (Core Solo/Duo)
Macmini2,1
Mac mini Intel Core
Macmini3,1
Mac mini Intel Core
Macmini4,1
Mac mini Intel Core (Mid 2010)
Macmini5,1
Mac mini (Core i5, Mid 2011)
Macmini5,2
Mac mini (Core i5 or Core i7, Mid 2011)
Macmini5,3
Mac mini (Core i7, Server, Mid 2011)
Macmini6,1
Mac mini (Core i5, Late 2012)
Macmini6,2
Mac mini (Core i7, Normal or Server, Late 2012)
Macmini7,1
Mac mini (Core i5 or Core i7, Late 2014)
MacPro1,1,Quad
Mac Pro
MacPro1,1
Mac Pro (four-core)
MacPro2,1
Mac Pro (eight-core)
MacPro3,1
Mac Pro (January 2008 4- or 8- core "Harpertown")
MacPro4,1
Mac Pro (March 2009)
MacPro5,1
Mac Pro (2010 or 2012)
MacPro6,1
Mac Pro (Late 2013)
PowerBook1,1
PowerBook G3
PowerBook2,1
iBook G3
PowerBook2,2
iBook G3 (FireWire)
PowerBook2,3
iBook G3
PowerBook2,4
iBook G3
PowerBook3,1
PowerBook G3 (FireWire)
PowerBook3,2
PowerBook G4
PowerBook3,3
PowerBook G4 (Gigabit Ethernet)
PowerBook3,4
PowerBook G4 (DVI)
PowerBook3,5
PowerBook G4 (1GHz / 867MHz)
PowerBook4,1
iBook G3 (Dual USB, Late 2001)
PowerBook4,2
iBook G3 (16MB VRAM)
PowerBook4,3
iBook G3 Opaque 16MB VRAM, 32MB VRAM, Early 2003)
PowerBook5,1
PowerBook G4 (17 inch)
PowerBook5,2
PowerBook G4 (15 inch FW 800)
PowerBook5,3
PowerBook G4 (17-inch 1.33GHz)
PowerBook5,4
PowerBook G4 (15 inch 1.5/1.33GHz)
PowerBook5,5
PowerBook G4 (17-inch 1.5GHz)
PowerBook5,6
PowerBook G4 (15 inch 1.67GHz/1.5GHz)
PowerBook5,7
PowerBook G4 (17-inch 1.67GHz)
PowerBook5,8
PowerBook G4 (Double layer SD, 15 inch)
PowerBook5,9
PowerBook G4 (Double layer SD, 17 inch)
PowerBook6,1
PowerBook G4 (12 inch)
PowerBook6,2
PowerBook G4 (12 inch, DVI)
PowerBook6,3
iBook G4
PowerBook6,4
PowerBook G4 (12 inch 1.33GHz)
PowerBook6,5
iBook G4 (Early-Late 2004)
PowerBook6,7
iBook G4 (Mid 2005)
PowerBook6,8
PowerBook G4 (12 inch 1.5GHz)
PowerMac1,1
Power Macintosh G3 (Blue & White)
PowerMac1,2
Power Macintosh G4 (PCI Graphics)
PowerMac2,1
iMac G3 (Slot-loading CD-ROM)
PowerMac2,2
iMac G3 (Summer 2000)
PowerMac3,1
Power Macintosh G4 (AGP Graphics)
PowerMac3,2
Power Macintosh G4 (AGP Graphics)
PowerMac3,3
Power Macintosh G4 (Gigabit Ethernet)
PowerMac3,4
Power Macintosh G4 (Digital Audio)
PowerMac3,5
Power Macintosh G4 (Quick Silver)
PowerMac3,6
Power Macintosh G4 (Mirrored Drive Door)
PowerMac4,1
iMac G3 (Early/Summer 2001)
PowerMac4,2
iMac G4 (Flat Panel)
PowerMac4,4
eMac
PowerMac4,5
iMac G4 (17-inch Flat Panel)
PowerMac5,1
Power Macintosh G4 Cube
PowerMac5,2
Power Mac G4 Cube
PowerMac6,1
iMac G4 (USB 2.0)
PowerMac6,3
iMac G4 (20-inch Flat Panel)
PowerMac6,4
eMac (USB 2.0, 2005)
PowerMac7,2
Power Macintosh G5
PowerMac7,3
Power Macintosh G5
PowerMac8,1
iMac G5
PowerMac8,2
iMac G5 (Ambient Light Sensor)
PowerMac9,1
Power Macintosh G5 (Late 2005)
PowerMac10,1
Mac Mini G4
PowerMac10,2
Mac Mini (Late 2005)
PowerMac11,2
Power Macintosh G5 (Late 2005)
PowerMac12,1
iMac G5 (iSight)
RackMac1,1
Xserve G4
RackMac1,2
Xserve G4 (slot-loading, cluster node)
RackMac3,1
Xserve G5
Xserve1,1
Xserve (Intel Xeon)
Xserve2,1
Xserve (January 2008 quad-core)
Xserve3,1
Xserve (early 2009)
================================================
FILE: TodoTxtMac/Base.lproj/MainMenu.xib
================================================
================================================
FILE: TodoTxtMac/Base.lproj/TTMDocument.xib
================================================
predicate
rawText contains[cd] $value
================================================
FILE: TodoTxtMac/FontNameTransformer.h
================================================
/*
File: FontNameTransformer.h
Abstract: Value transformer that turns fonts into a human-readable string with the font's name and size. This is used in the preferences window.
Version: 1.9
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
Inc. ("Apple") in consideration of your agreement to the following
terms, and your use, installation, modification or redistribution of
this Apple software constitutes acceptance of these terms. If you do
not agree with these terms, please do not use, install, modify or
redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a personal, non-exclusive
license, under Apple's copyrights in this original Apple software (the
"Apple Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following
text and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may
be used to endorse or promote products derived from the Apple Software
without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyright (C) 2013 Apple Inc. All Rights Reserved.
*/
#import
@interface FontNameTransformer : NSValueTransformer {
}
@end
================================================
FILE: TodoTxtMac/FontNameTransformer.m
================================================
/*
File: FontNameTransformer.m
Abstract: Value transformer that turns fonts into a human-readable string with the font's name and size. This is used in the preferences window.
Version: 1.9
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
Inc. ("Apple") in consideration of your agreement to the following
terms, and your use, installation, modification or redistribution of
this Apple software constitutes acceptance of these terms. If you do
not agree with these terms, please do not use, install, modify or
redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a personal, non-exclusive
license, under Apple's copyrights in this original Apple software (the
"Apple Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following
text and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may
be used to endorse or promote products derived from the Apple Software
without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyright (C) 2013 Apple Inc. All Rights Reserved.
*/
#import "FontNameTransformer.h"
@implementation FontNameTransformer
+ (Class)tranformedValueClass {
return [NSString class];
}
+ (BOOL)allowsReverseTransformation {
return NO;
}
- (id)transformedValue:(id)value {
if (value && [value isKindOfClass:[NSFont class]]) {
return [NSString stringWithFormat:@"%@ %g", [value displayName], [value pointSize]];
} else {
return @"";
}
}
@end
================================================
FILE: TodoTxtMac/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "icon_16x16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "icon_16x16@2x.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "icon_32x32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "icon_32x32@2x.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "icon_128x128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "icon_128x128@2x.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "icon_256x256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "icon_256x256@2x.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "icon_512x512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "icon_512x512@2x.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: TodoTxtMac/NSDate+RelativeDates.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2016 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@interface NSDate (RelativeDates)
- (NSDate*)advanceDateByWeekdays:(NSInteger)numberOfWeekdays;
- (NSDate*)advanceDateByNumberOfCalendarUnits:(NSInteger)numberOfCalendarUnits
calendarUnit:(NSCalendarUnit)calendarUnit;
- (BOOL)isWeekendDay;
- (BOOL)isWeekday;
@end
================================================
FILE: TodoTxtMac/NSDate+RelativeDates.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "NSDate+RelativeDates.h"
@implementation NSDate (RelativeDates)
- (NSCalendar*)currentCalendar {
return [NSCalendar currentCalendar];
}
- (NSDate*)advanceDateByWeekdays:(NSInteger)numberOfWeekdays {
NSDate *relativeDate = self;
NSInteger weekdaysLeft = numberOfWeekdays;
while (weekdaysLeft > 0) {
NSDate *newDate = [relativeDate advanceDateByNumberOfCalendarUnits:1 calendarUnit:NSCalendarUnitDay];
if (newDate == nil) {
return relativeDate;
}
relativeDate = newDate;
if ([relativeDate isWeekday]) {
weekdaysLeft -= 1;
}
}
return relativeDate;
}
- (NSDate*)advanceDateByNumberOfCalendarUnits:(NSInteger)numberOfCalendarUnits
calendarUnit:(NSCalendarUnit)calendarUnit {
return [[self currentCalendar] dateByAddingUnit:calendarUnit
value:numberOfCalendarUnits
toDate:self
options:NSCalendarMatchFirst];
}
- (BOOL)isWeekendDay {
long weekday = [[self currentCalendar] component:NSCalendarUnitWeekday fromDate:self];
return (weekday == 1 || weekday == 7);
}
- (BOOL)isWeekday {
return ![self isWeekendDay];
}
@end
================================================
FILE: TodoTxtMac/NSMutableAttributableString+ColorRegExMatches.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@interface NSMutableAttributedString (ColorRegExMatches)
/*!
* @method applyColor:toRegexPatternMatches:
* @abstract Adds foreground color attributes to a mutable attributed string based for all regular
* epxression matches.
* @param color Color to apply
* @param regExPattern Regular expression pattern to apply colors to matches
*/
- (void)applyColor:(NSColor*)color toRegexPatternMatches:(NSString*)regExPattern;
/*!
* @method applyColorToFullStringRange:
* @abstract Adds foreground color attributes to the entire mutable attributed string.
* @param color Color to apply
*/
- (void)applyColorToFullStringRange:(NSColor*)color;
@end
================================================
FILE: TodoTxtMac/NSMutableAttributableString+ColorRegExMatches.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "NSMutableAttributableString+ColorRegExMatches.h"
#import "RegExCategories.h"
@implementation NSMutableAttributedString (ColorRegExMatches)
- (void)applyColor:(NSColor*)color toRegexPatternMatches:(NSString*)regExPattern {
NSArray *matches = [self.string matchesWithDetails:RX(regExPattern)];
for (RxMatch *match in matches) {
[self addAttribute:NSForegroundColorAttributeName
value:color
range:match.range];
}
}
- (void)applyColorToFullStringRange:(NSColor*)color {
[self addAttribute:NSForegroundColorAttributeName
value:color
range:NSMakeRange(0, [self.string length])];
}
@end
================================================
FILE: TodoTxtMac/NSUserDefaults+myColorSupport.h
================================================
// This code is lifted from Apple's Developer Documenation.
// Source: https://developer.apple.com/library/mac/documentation/cocoa/conceptual/DrawColor/Tasks/StoringNSColorInDefaults.html
#import
@interface NSUserDefaults(myColorSupport)
- (void)setColor:(NSColor *)aColor forKey:(NSString *)aKey;
- (NSColor *)colorForKey:(NSString *)aKey;
@end
================================================
FILE: TodoTxtMac/NSUserDefaults+myColorSupport.m
================================================
// This code is lifted from Apple's Developer Documenation.
// Source: https://developer.apple.com/library/mac/documentation/cocoa/conceptual/DrawColor/Tasks/StoringNSColorInDefaults.html
#import "NSUserDefaults+myColorSupport.h"
@implementation NSUserDefaults(myColorSupport)
- (void)setColor:(NSColor *)aColor forKey:(NSString *)aKey {
NSData *theData=[NSArchiver archivedDataWithRootObject:aColor];
[self setObject:theData forKey:aKey];
}
- (NSColor *)colorForKey:(NSString *)aKey {
NSColor *theColor=nil;
NSData *theData=[self dataForKey:aKey];
if (theData != nil)
theColor=(NSColor *)[NSUnarchiver unarchiveObjectWithData:theData];
return theColor;
}
@end
================================================
FILE: TodoTxtMac/RegExCategories.h
================================================
//
// RegExCategories.h
//
// https://github.com/bendytree/Objective-C-RegEx-Categories
//
//
// The MIT License (MIT)
//
// Copyright (c) 2013 Josh Wright <@BendyTree>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#import
/********************************************************/
/*********************** MACROS *************************/
/********************************************************/
/*
* By default, we create an alias for NSRegularExpression
* called `Rx` and creates a macro `RX()` for quick regex creation.
*
* If you don't want these macros, add the following statement
* before you include this library:
*
* #define DisableRegExCategoriesMacros
*/
/**
* Creates a macro (alias) for NSRegularExpression named `Rx`.
*
* ie.
* NSRegularExpression* rx = [[Rx alloc] initWithPattern:@"\d+" options:0 error:nil];
*/
#ifndef DisableRegExCategoriesMacros
#define Rx NSRegularExpression
#endif
/**
* Creates a macro (alias) for NSRegularExpression named `Rx`.
*
* ie.
* NSRegularExpression* rx = [[Rx alloc] initWithPattern:@"\d+" options:0 error:nil];
*/
#ifndef DisableRegExCategoriesMacros
#define RX(pattern) [[NSRegularExpression alloc] initWithPattern:pattern]
#endif
/********************************************************/
/******************* MATCH OBJECTS **********************/
/********************************************************/
/**
* RxMatch represents a single match. It contains the
* matched value, range, sub groups, and the original
* string.
*/
@interface RxMatch : NSObject
@property (retain) NSString* value; /* The substring that matched the expression. */
@property (assign) NSRange range; /* The range of the original string that was matched. */
@property (retain) NSArray* groups; /* Each object is an RxMatchGroup. */
@property (retain) NSString* original; /* The full original string that was matched against. */
@end
@interface RxMatchGroup : NSObject
@property (retain) NSString* value;
@property (assign) NSRange range;
@end
/**
* Extend NSRegularExpression.
*/
@interface NSRegularExpression (ObjectiveCRegexCategories)
/*******************************************************/
/******************* INITIALIZATION ********************/
/*******************************************************/
/**
* Initialize an Rx object from a string.
*
* ie.
* Rx* rx = [[Rx alloc] initWithString:@"\d+"];
*/
- (NSRegularExpression*) initWithPattern:(NSString*)pattern;
/**
* Initialize an Rx object from a string.
*
* ie.
* Rx* rx = [Rx rx:@"\d+"];
*/
+ (NSRegularExpression*) rx:(NSString*)pattern;
/**
* Initialize an Rx object from a string. By default, NSRegularExpression
* is case sensitive, but this signature allows you to change that.
*
* ie.
* Rx* rx = [Rx rx:@"\d+" ignoreCase:YES];
*/
+ (NSRegularExpression*) rx:(NSString*)pattern ignoreCase:(BOOL)ignoreCase;
/**
* Initialize an Rx object from a string and options.
*
* ie.
* Rx* rx = [Rx rx:@"\d+" options:NSRegularExpressionCaseInsensitive];
*/
+ (NSRegularExpression*) rx:(NSString*)pattern options:(NSRegularExpressionOptions)options;
/*******************************************************/
/********************** IS MATCH ***********************/
/*******************************************************/
/**
* Returns true if the string matches the regex. May also
* be called on NSString as [@"\d" isMatch:rx].
*
* ie.
* Rx* rx = RX(@"\d+");
* BOOL isMatch = [rx isMatch:@"Dog #1"]; // => true
*/
- (BOOL) isMatch:(NSString*)matchee;
/**
* Returns the index of the first match of the passed string.
*
* ie.
* int i = [RX(@"\d+") indexOf:@"Buy 1 dog or buy 2?"]; // => 4
*/
- (int) indexOf:(NSString*)str;
/**
* Splits a string using the regex to identify delimeters. Returns
* an NSArray of NSStrings.
*
* ie.
* NSArray* pieces = [RX(@"[ ,]") split:@"A dog,cat"];
* => @[@"A", @"dog", @"cat"]
*/
- (NSArray*) split:(NSString*)str;
/**
* Replaces all occurances in a string with a replacement string.
*
* ie.
* NSString* result = [RX(@"ruf+") replace:@"ruf ruff!" with:@"meow"];
* => @"meow meow!"
*/
- (NSString*) replace:(NSString*)string with:(NSString*)replacement;
/**
* Replaces all occurances of a regex using a block. The block receives the match
* and should return the replacement.
*
* ie.
* NSString* result = [RX(@"[A-Z]+") replace:@"i love COW" withBlock:^(NSString*){ return @"lamp"; }];
* => @"i love lamp"
*/
- (NSString*) replace:(NSString*)string withBlock:(NSString*(^)(NSString* match))replacer;
/**
* Replaces all occurances of a regex using a block. The block receives a RxMatch object
* that contains all the details of the match and should return a string
* which is what the match is replaced with.
*
* ie.
* NSString* result = [RX(@"\\w+") replace:@"hi bud" withDetailsBlock:^(RxMatch* match){ return [NSString stringWithFormat:@"%i", match.value.length]; }];
* => @"2 3"
*/
- (NSString*) replace:(NSString *)string withDetailsBlock:(NSString*(^)(RxMatch* match))replacer;
/**
* Returns an array of matched root strings with no other match information.
*
* ie.
* NSString* str = @"My email is me@example.com and yours is you@example.com";
* NSArray* matches = [RX(@"\\w+[@]\\w+[.](\\w+)") matches:str];
* => @[ @"me@example.com", @"you@example.com" ]
*/
- (NSArray*) matches:(NSString*)str;
/**
* Returns a string which is the first match of the NSRegularExpression.
*
* ie.
* NSString* str = @"My email is me@example.com and yours is you@example.com";
* NSString* match = [RX(@"\\w+[@]\\w+[.](\\w+)") firstMatch:str];
* => @"me@example.com"
*/
- (NSString*) firstMatch:(NSString*)str;
/**
* Returns an NSArray of RxMatch* objects. Each match contains the matched
* value, range, groups, etc.
*
* ie.
* NSString* str = @"My email is me@example.com and yours is you@example.com";
* NSArray* matches = [str matchesWithDetails:RX(@"\\w+[@]\\w+[.](\\w+)")];
*/
- (NSArray*) matchesWithDetails:(NSString*)str;
/**
* Returns the first match as an RxMatch* object.
*
* ie.
* NSString* str = @"My email is me@example.com and yours is you@example.com";
* Rx* rx = RX(@"\\w+[@]\\w+[.](\\w+)");
* RxMatch* match = [rx firstMatchWithDetails:str];
*/
- (RxMatch*) firstMatchWithDetails:(NSString*)str;
@end
/**
* A category on NSString to make it easy to use
* Rx in simple operations.
*/
@interface NSString (ObjectiveCRegexCategories)
/**
* Initialize an NSRegularExpression object from a string.
*
* ie.
* NSRegularExpression* rx = [@"\d+" toRx];
*/
- (NSRegularExpression*) toRx;
/**
* Initialize an NSRegularExpression object from a string with
* a flag denoting case-sensitivity. By default, NSRegularExpression
* is case sensitive.
*
* ie.
* NSRegularExpression* rx = [@"\d+" toRxIgnoreCase:YES];
*/
- (NSRegularExpression*) toRxIgnoreCase:(BOOL)ignoreCase;
/**
* Initialize an NSRegularExpression object from a string with options.
*
* ie.
* NSRegularExpression* rx = [@"\d+" toRxWithOptions:NSRegularExpressionCaseInsensitive];
*/
- (NSRegularExpression*) toRxWithOptions:(NSRegularExpressionOptions)options;
/**
* Returns true if the string matches the regex. May also
* be called as on Rx as [rx isMatch:@"some string"].
*
* ie.
* BOOL isMatch = [@"Dog #1" isMatch:RX(@"\d+")]; // => true
*/
- (BOOL) isMatch:(NSRegularExpression*)rx;
/**
* Returns the index of the first match according to
* the regex passed in.
*
* ie.
* int i = [@"Buy 1 dog or buy 2?" indexOf:RX(@"\d+")]; // => 4
*/
- (int) indexOf:(NSRegularExpression*)rx;
/**
* Splits a string using the regex to identify delimeters. Returns
* an NSArray of NSStrings.
*
* ie.
* NSArray* pieces = [@"A dog,cat" split:RX(@"[ ,]")];
* => @[@"A", @"dog", @"cat"]
*/
- (NSArray*) split:(NSRegularExpression*)rx;
/**
* Replaces all occurances of a regex with a replacement string.
*
* ie.
* NSString* result = [@"ruf ruff!" replace:RX(@"ruf+") with:@"meow"];
* => @"meow meow!"
*/
- (NSString*) replace:(NSRegularExpression*)rx with:(NSString*)replacement;
/**
* Replaces all occurances of a regex using a block. The block receives the match
* and should return the replacement.
*
* ie.
* NSString* result = [@"i love COW" replace:RX(@"[A-Z]+") withBlock:^(NSString*){ return @"lamp"; }];
* => @"i love lamp"
*/
- (NSString*) replace:(NSRegularExpression *)rx withBlock:(NSString*(^)(NSString* match))replacer;
/**
* Replaces all occurances of a regex using a block. The block receives an RxMatch
* object which contains all of the details for each match and should return a string
* which is what the match is replaced with.
*
* ie.
* NSString* result = [@"hi bud" replace:RX(@"\\w+") withDetailsBlock:^(RxMatch* match){ return [NSString stringWithFormat:@"%i", match.value.length]; }];
* => @"2 3"
*/
- (NSString*) replace:(NSRegularExpression *)rx withDetailsBlock:(NSString*(^)(RxMatch* match))replacer;
/**
* Returns an array of matched root strings with no other match information.
*
* ie.
* NSString* str = @"My email is me@example.com and yours is you@example.com";
* NSArray* matches = [str matches:RX(@"\\w+[@]\\w+[.](\\w+)")];
* => @[ @"me@example.com", @"you@example.com" ]
*/
- (NSArray*) matches:(NSRegularExpression*)rx;
/**
* Returns a string which is the first match of the NSRegularExpression.
*
* ie.
* NSString* str = @"My email is me@example.com and yours is you@example.com";
* NSString* match = [str firstMatch:RX(@"\\w+[@]\\w+[.](\\w+)")];
* => @"me@example.com"
*/
- (NSString*) firstMatch:(NSRegularExpression*)rx;
/**
* Returns an NSArray of RxMatch* objects. Each match contains the matched
* value, range, groups, etc.
*
* ie.
* NSString* str = @"My email is me@example.com and yours is you@example.com";
* NSArray* matches = [str matchesWithDetails:RX(@"\\w+[@]\\w+[.](\\w+)")];
*/
- (NSArray*) matchesWithDetails:(NSRegularExpression*)rx;
/**
* Returns an the first match as an RxMatch* object.
*
* ie.
* NSString* str = @"My email is me@example.com and yours is you@example.com";
* RxMatch* match = [str firstMatchWithDetails:RX(@"\\w+[@]\\w+[.](\\w+)")];
*/
- (RxMatch*) firstMatchWithDetails:(NSRegularExpression*)rx;
@end
================================================
FILE: TodoTxtMac/RegExCategories.m
================================================
//
// RegExCategories.m
//
// https://github.com/bendytree/Objective-C-RegEx-Categories
//
//
// The MIT License (MIT)
//
// Copyright (c) 2013 Josh Wright <@BendyTree>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#import "RegExCategories.h"
@implementation NSRegularExpression (ObjectiveCRegexCategories)
- (id) initWithPattern:(NSString*)pattern
{
return [self initWithPattern:pattern options:0 error:nil];
}
+ (NSRegularExpression*) rx:(NSString*)pattern
{
return [[self alloc] initWithPattern:pattern];
}
+ (NSRegularExpression*) rx:(NSString*)pattern ignoreCase:(BOOL)ignoreCase
{
return [[self alloc] initWithPattern:pattern options:ignoreCase?NSRegularExpressionCaseInsensitive:0 error:nil];
}
+ (NSRegularExpression*) rx:(NSString*)pattern options:(NSRegularExpressionOptions)options
{
return [[self alloc] initWithPattern:pattern options:options error:nil];
}
- (BOOL) isMatch:(NSString*)matchee
{
return [self numberOfMatchesInString:matchee options:0 range:NSMakeRange(0, matchee.length)] > 0;
}
- (int) indexOf:(NSString*)matchee
{
NSRange range = [self rangeOfFirstMatchInString:matchee options:0 range:NSMakeRange(0, matchee.length)];
return range.location == NSNotFound ? -1 : (int)range.location;
}
- (NSArray*) split:(NSString *)str
{
NSRange range = NSMakeRange(0, str.length);
//get locations of matches
NSMutableArray* matchingRanges = [NSMutableArray array];
NSArray* matches = [self matchesInString:str options:0 range:range];
for(NSTextCheckingResult* match in matches) {
[matchingRanges addObject:[NSValue valueWithRange:match.range]];
}
//invert ranges - get ranges of non-matched pieces
NSMutableArray* pieceRanges = [NSMutableArray array];
//add first range
[pieceRanges addObject:[NSValue valueWithRange:NSMakeRange(0,
(matchingRanges.count == 0 ? str.length : [matchingRanges[0] rangeValue].location))]];
//add between splits ranges and last range
for(int i=0; i=0; i--) {
NSTextCheckingResult* match = matches[i];
NSString* matchStr = [string substringWithRange:match.range];
NSString* replacement = replacer(matchStr);
[result replaceCharactersInRange:match.range withString:replacement];
}
return result;
}
- (NSString*) replace:(NSString *)string withDetailsBlock:(NSString*(^)(RxMatch* match))replacer
{
//no replacer? just return
if (!replacer) return string;
//copy the string so we can replace subsections
NSMutableString* replaced = [string mutableCopy];
//get matches
NSArray* matches = [self matchesInString:string options:0 range:NSMakeRange(0, string.length)];
//replace each match (right to left so indexing doesn't get messed up)
for (int i=(int)matches.count-1; i>=0; i--) {
NSTextCheckingResult* result = matches[i];
RxMatch* match = [self resultToMatch:result original:string];
NSString* replacement = replacer(match);
[replaced replaceCharactersInRange:result.range withString:replacement];
}
return replaced;
}
- (NSArray*) matches:(NSString*)str
{
NSMutableArray* matches = [NSMutableArray array];
NSArray* results = [self matchesInString:str options:0 range:NSMakeRange(0, str.length)];
for (NSTextCheckingResult* result in results) {
NSString* match = [str substringWithRange:result.range];
[matches addObject:match];
}
return matches;
}
- (NSString*) firstMatch:(NSString*)str
{
NSTextCheckingResult* match = [self firstMatchInString:str options:0 range:NSMakeRange(0, str.length)];
if (!match) return nil;
return [str substringWithRange:match.range];
}
- (RxMatch*) resultToMatch:(NSTextCheckingResult*)result original:(NSString*)original
{
RxMatch* match = [[RxMatch alloc] init];
match.original = original;
match.range = result.range;
match.value = result.range.length ? [original substringWithRange:result.range] : nil;
//groups
NSMutableArray* groups = [NSMutableArray array];
match.groups = groups;
for(int i=0; i.
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@class TTMPreferencesController;
@class TTMFiltersController;
@interface TTMAppController : NSObject
// Constants for command-line argument names
extern NSString *const TodoFileArgument;
@property (nonatomic, retain) TTMPreferencesController *preferencesController;
@property (nonatomic, retain) TTMFiltersController *filtersController;
- (IBAction)openPreferencesWindow:(id)sender;
- (IBAction)openFiltersWindow:(id)sender;
- (IBAction)openWebSite:(id)sender;
- (IBAction)openPlaintextProductivityWebSite:(id)sender;
- (IBAction)openTodoTxtTipsPlaintextProductivityWebSite:(id)sender;
#pragma mark - User Defaults-related Methods
/*!
* @method initializeUserDefaults:
* @abstract This method sets up preferences managed by NSUserDefaultsController.
*/
- (void)initializeUserDefaults:(id)sender;
/*!
* @method resetUserDefaults:
* @abstract This method resets preferences managed by NSUserDefaultsController to default values.
* It does not reset fitler-related preferences.
*/
- (void)resetUserDefaults:(id)sender;
#pragma mark - Command-line Argument-related Methods
/*!
* @method openTodoFileFromCommandLineArgument:
* @abstract This method opens a todo.txt file based on the command line argument.
* The name of the argument is defined in the TodoFileArgument constant.
* If there is no command line argument, this method does nothing.
*/
- (void)openTodoFileFromCommandLineArgument;
/*!
* @method commandLineArgumentTodoFile:
* @abstract This method returns the value of the todo-file command line argument.
* If there is no command-line argument, it returns null.
*/
- (NSString*)commandLineArgumentTodoFile;
/*!
* @method openDocumentFromFilePath:
* @abstract This method opens a todo.txt file (TTMDocument) based on a file path.
*/
- (void)openDocumentFromFilePath:(NSString*)filePath;
/*!
* @method openDocumentFromFilePath:
* @abstract This method opens a todo.txt file (TTMDocument) based on a file URL.
*/
- (void)openDocumentFromFileURL:(NSURL*)fileURL;
#pragma mark - Open Default Todo.txt File Methods
/*!
* @method openDefaultTodoFile:
* @abstract This method opens the default todo.txt file (TTMDocument) based on user preferences.
* If the user preference for opening a default todo.txt file on startup is disabled,
* this method does nothing.
*/
-(void)openDefaultTodoFile;
#pragma mark - Close All Windows Methods
/*!
* @method closeAllWindows:
* @abstract This method closes all open windows.
*/
- (IBAction)closeAllWindows:(id)sender;
/*!
* @method documentController:didCloseAll:contextInfo
* @abstract This method is a completion handler for closeAllWindows. It does nothing.
*/
- (void)documentController:(NSDocumentController *)docController
didCloseAll:(BOOL)didCloseAll
contextInfo:(void *)contextInfo;
#pragma mark - Reload All Methods
/*!
* @method reloadAll:
* @abstract This method refreshes the task list from disk for all open windows.
*/
- (IBAction)reloadAll:(id)sender;
#pragma mark - Visual Refresh Methods
/*!
* @method visualRefreshAll:
* @abstract This method visually refreshes the task list for all open windows.
*/
- (IBAction)visualRefreshAll:(id)sender;
@end
================================================
FILE: TodoTxtMac/TTMAppController.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMAppController.h"
#import "TTMPreferencesController.h"
#import "TTMFiltersController.h"
#import "TTMFilterPredicates.h"
#import "TTMDocument.h"
#import "TTMDocumentStatusBarText.h"
// Default user preference values, including those for saved filters
static NSDictionary *defaultValues() {
static NSData *defaultPredicateData = nil;
if (defaultPredicateData == nil) {
defaultPredicateData = [TTMFilterPredicates defaultFilterPredicateData];
}
static NSDictionary *dict = nil;
if (!dict) {
dict = [[NSDictionary alloc] initWithObjectsAndKeys:
@NO, @"prependDateOnNewTasks",
@1, @"taskListSortType",
defaultPredicateData, @"activefilterPredicate",
@0, @"activefilterPreset",
defaultPredicateData, @"filterPredicate1",
defaultPredicateData, @"filterPredicate2",
defaultPredicateData, @"filterPredicate3",
defaultPredicateData, @"filterPredicate4",
defaultPredicateData, @"filterPredicate5",
defaultPredicateData, @"filterPredicate6",
defaultPredicateData, @"filterPredicate7",
defaultPredicateData, @"filterPredicate8",
defaultPredicateData, @"filterPredicate9",
@"", @"archiveFilePath",
@NO, @"archiveTasksUponCompletion",
@NO, @"useUserFont",
@NO, @"moveToTaskListAfterTaskCreation",
@YES, @"useHighlightColorsInTaskList",
@NO, @"useCustomColorForOverdueTasks",
@NO, @"useCustomColorForDueTodayTasks",
@NO, @"useCustomColorForProjects",
@NO, @"useCustomColorForContexts",
@NO, @"useCustomColorForTags",
@NO, @"useCustomColorForDueDates",
@NO, @"useCustomColorForThresholdDates",
@NO, @"useCustomColorForCreationDates",
[NSArchiver archivedDataWithRootObject:[NSColor redColor]], @"dueTodayColor",
[NSArchiver archivedDataWithRootObject:[NSColor purpleColor]], @"overdueColor",
[NSArchiver archivedDataWithRootObject:[NSColor darkGrayColor]], @"projectColor",
[NSArchiver archivedDataWithRootObject:[NSColor darkGrayColor]], @"contextColor",
[NSArchiver archivedDataWithRootObject:[NSColor darkGrayColor]], @"tagColor",
[NSArchiver archivedDataWithRootObject:[NSColor darkGrayColor]], @"dueDateColor",
[NSArchiver archivedDataWithRootObject:[NSColor darkGrayColor]], @"thresholdDateColor",
[NSArchiver archivedDataWithRootObject:[NSColor darkGrayColor]], @"creationDateColor",
@NO, @"escapeKeyCancelsAllTextChanges",
@NO, @"openDefaultTodoFileOnStartup",
@"", @"defaultTodoFilePath",
@YES, @"showStatusBar",
[TTMDocumentStatusBarText defaultFormat], @"statusBarFormat",
@0, @"levelsOfUndo",
@YES, @"allowUndoOfArchiveCommand",
@NO, @"hideFutureTasks",
@NO, @"closingLastWindowClosesApplication",
@NO, @"hideHiddenTasks",
nil];
}
return dict;
}
// Default user preference values, excluding those for saved filters.
// Defined to help allow users to reset preferences without losing saved filters.
static NSDictionary *defaultValuesExcludingFilters() {
static NSMutableDictionary *defaults = nil;
if (defaults == nil) {
defaults = [NSMutableDictionary dictionaryWithDictionary:defaultValues()];
for (int i = 1; i <= 9; i++) {
[defaults removeObjectForKey:[TTMFilterPredicates keyFromPresetNumber:i]];
}
[defaults removeObjectForKey:@"activefilterPredicate"];
}
return defaults;
}
@implementation TTMAppController
// Constants for command-line argument names
NSString *const TodoFileArgument = @"todo-file";
- (id)init {
self = [super init];
if (self) {
}
return self;
}
- (IBAction)openPreferencesWindow:(id)sender {
if (!self.preferencesController) {
self.preferencesController = [[TTMPreferencesController alloc]
initWithWindowNibName:@"TTMPreferences"];
}
[self.preferencesController showWindow:self];
}
- (IBAction)openFiltersWindow:(id)sender {
if (!self.filtersController) {
self.filtersController = [[TTMFiltersController alloc]
initWithWindowNibName:@"TTMFilters"];
}
[self.filtersController showWindow:self];
}
- (void)launchURLFromString:(NSString*)urlString {
NSURL *url = [NSURL URLWithString:urlString];
[[NSWorkspace sharedWorkspace] openURL:url];
}
- (IBAction)openWebSite:(id)sender {
[self launchURLFromString:@"http://mjdescy.github.io/TodoTxtMac/"];
}
- (IBAction)openPlaintextProductivityWebSite:(id)sender {
[self launchURLFromString:@"http://plaintext-productivity.net"];
}
- (IBAction)openTodoTxtTipsPlaintextProductivityWebSite:(id)sender {
[self launchURLFromString:@"http://plaintext-productivity.net/1-00-tasks-introduction.html"];
}
#pragma mark - User Defaults-related Methods
- (void)initializeUserDefaults:(id)sender {
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultValues()];
[[NSUserDefaultsController sharedUserDefaultsController] setInitialValues:defaultValues()];
}
- (void)resetUserDefaults:(id)sender {
[[NSUserDefaultsController sharedUserDefaultsController] setInitialValues:
defaultValuesExcludingFilters()];
[[NSUserDefaultsController sharedUserDefaultsController] revertToInitialValues:self];
[[NSUserDefaultsController sharedUserDefaultsController] setInitialValues:defaultValues()];
}
#pragma mark - Command-line Argument-related Methods
- (void)openTodoFileFromCommandLineArgument {
NSString *fileToOpenOnLaunch = [self commandLineArgumentTodoFile];
if (!fileToOpenOnLaunch) {
return;
}
[self openDocumentFromFilePath:fileToOpenOnLaunch];
}
- (NSString*)commandLineArgumentTodoFile {
NSUserDefaults *args = [NSUserDefaults standardUserDefaults];
return [args stringForKey:TodoFileArgument];
}
- (void)openDocumentFromFilePath:(NSString*)filePath {
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
[self openDocumentFromFileURL:fileURL];
}
- (void)openDocumentFromFileURL:(NSURL*)fileURL {
[[NSDocumentController sharedDocumentController]
openDocumentWithContentsOfURL:fileURL
display:YES
completionHandler:^(NSDocument *document, BOOL alreadyOpen, NSError *error){
// NSLog(@"%@",document);
}];
}
#pragma mark - Open Default Todo.txt File Methods
-(void)openDefaultTodoFile {
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"openDefaultTodoFileOnStartup"]) {
return;
}
[self openDocumentFromFilePath:[[NSUserDefaults standardUserDefaults]
stringForKey:@"defaultTodoFilePath"]];
}
#pragma mark - Close All Windows Methods
- (IBAction)closeAllWindows:(id)sender {
[[NSDocumentController sharedDocumentController]
closeAllDocumentsWithDelegate:self
didCloseAllSelector:@selector(documentController:didCloseAll:contextInfo:)
contextInfo:NULL];
}
- (void)documentController:(NSDocumentController *)docController
didCloseAll:(BOOL)didCloseAll
contextInfo:(void *)contextInfo {
return;
}
#pragma mark - Reload All Methods
- (IBAction)reloadAll:(id)sender {
NSArray *documents = [[NSDocumentController sharedDocumentController] documents];
[documents enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[(TTMDocument*)obj reloadFile:self];
}];
}
#pragma mark - Visual Refresh Methods
- (IBAction)visualRefreshAll:(id)sender {
NSArray *documents = [[NSDocumentController sharedDocumentController] documents];
[documents enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[(TTMDocument*)obj visualRefreshOnly:self];
}];
}
@end
================================================
FILE: TodoTxtMac/TTMAppDelegate.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@class TTMAppController;
@interface TTMAppDelegate : NSObject
@property (nonatomic, retain) IBOutlet TTMAppController *appController;
@end
================================================
FILE: TodoTxtMac/TTMAppDelegate.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMAppDelegate.h"
#import "TTMFilterPredicates.h"
#import "TTMAppController.h"
@implementation TTMAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
[self.appController initializeUserDefaults:self];
// Open file from command line argument. Does nothing if there is no command line argument.
[self.appController openTodoFileFromCommandLineArgument];
// Open default todo file, if one is selected and the option is enabled.
[self.appController openDefaultTodoFile];
}
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender {
// Suppress creating an Untitled document on launch if either:
// 1. there is a command line argument to open a todo file, or
// 2. the open default todo.txt file on startup user preference is selected.
// Without this method override, opening a todo file using the command line argument
// or the default todo file user preference also opens an Untitled document every time.
return ([self.appController commandLineArgumentTodoFile] == NULL &&
![[NSUserDefaults standardUserDefaults] boolForKey:@"openDefaultTodoFileOnStartup"]);
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
return [[NSUserDefaults standardUserDefaults] boolForKey:@"closingLastWindowClosesApplication"];
}
@end
================================================
FILE: TodoTxtMac/TTMDateUtility.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@interface TTMDateUtility : NSObject
/*!
* @method convertStringToDate:
* @abstract This method converts a string in "yyyy-MM-dd" format to an NSDate object.
* @param dateString An NSString in "yyyy-MM-dd" format. It must not contain time elements.
* @return Returns a date object based on the date string.
*/
+ (NSDate*)convertStringToDate:(NSString*)dateString;
/*!
* @method convertDateToString:
* @abstract This method returns today's date as a string in "yyyy-MM-dd" format.
* @param date The date to convert to a string.
* @return The date parameter as a string in "yyyy-MM-dd" format.
*/
+ (NSString*)convertDateToString:(NSDate*)date;
/*!
* @method todayAsString:
* @abstract This method returns today's date.
* @return Today's date.
*/
+ (NSDate*)today;
/*!
* @method todayAsString:
* @abstract This method returns today's date as a string in "yyyy-MM-dd" format.
* @return Today's date as a string in "yyyy-MM-dd" format.
*/
+ (NSString*)todayAsString;
/*!
* @method addDays:toDate:
* @abstract This method adds a number of days to the date.
* @param days The number of days to add. Can be negative.
* @param date The date to add days to.
* @return A date offset by the given number of days.
*/
+ (NSDate*)addDays:(NSInteger)days toDate:(NSDate*)date;
/*!
* @method dateWithoutTime:
* @abstract This method strips the time element from a date.
* @param date The date to return as of 00:00:00.
* @return A date with the time element set to 00:00:00.
* @discussion This method is necessary to allow for date "is equal" comparisons
* in NSPredicateEditor.
*/
+ (NSDate*)dateWithoutTime:(NSDate*)date;
/*!
* @method dateFromNaturalLanguageString:
* @abstract This method returns a date based on a string such as "today" or "Monday".
* @param string A string that could represent a relative due date.
* @return A date, or nil if no date matches the string passed to the method.
*/
+ (NSDate*)dateFromNaturalLanguageString:(NSString*)string;
/*!
* @method relativeDateFromWeekdayName:withAllowedWeekdayNames:withDateFormat
* @abstract This method returns a date based on a string that represents a weekday name.
* @return A date, or nil if no date matches the string passed to the method.
* @param weekdayName A string that could be a weekday name.
* @param allowedWeekdayNames An array of weekday names (or shortnames) that the weekdayName
* will be tested to match.
* @param dateFormat Date format to apply to the weekdayName for matching purposes.
* @discussion This is a convenience method called from
* relativeDateFromWeekdayName:withAllowedWeekdayNames:withDateFormat.
*/
+ (NSDate*)relativeDateFromWeekdayName:(NSString*)weekdayName
withAllowedWeekdayNames:(NSArray*)allowedWeekdayNames
withDateFormat:(NSString*)dateFormat;
/*!
* @method dateStringFromNaturalLanguageString:
* @abstract This method returns a string-formatted date in "YYYY-MM-DD" format,
* based on a string such as "today" or "Monday".
* @param string A string that could represent a relative due date.
* @return A string-formatted date in "YYYY-MM-DD" format, or nil if no date matches
* the string passed to the method.
*/
+ (NSString*)dateStringFromNaturalLanguageString:(NSString*)string;
+ (NSInteger)daysBetweenDate:(NSDate*)startDate andEndDate:(NSDate*)endDate;
@end
================================================
FILE: TodoTxtMac/TTMDateUtility.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMDateUtility.h"
#import "NSDate+RelativeDates.h"
@implementation TTMDateUtility
+ (NSDate*)convertStringToDate:(NSString*)dateString {
if (!dateString) {
return nil;
}
// dateString must not contain a time element.
// We add a time element to it to set the time to midnight.
NSString *dateTimeString = [dateString stringByAppendingString:@" 00:00:00"];
// Convert dateString to NSDate.
NSDateFormatter *dateFormatter = [self dateFormatter];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
return [dateFormatter dateFromString:dateTimeString];
}
+ (NSDateFormatter*)dateFormatter {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
[dateFormatter setCalendar:gregorian];
[dateFormatter setLocale:[NSLocale systemLocale]];
[dateFormatter setDateFormat:@"yyyy-MM-dd"];
return dateFormatter;
}
+ (NSString*)convertDateToString:(NSDate*)date {
if (!date) {
return nil;
}
NSDateFormatter *dateFormatter = [self dateFormatter];
return [dateFormatter stringFromDate:date];
}
+ (NSDate*)today {
return [self dateWithoutTime:[NSDate date]];
}
+ (NSString*)todayAsString {
return [self convertDateToString:[self today]];
}
+ (NSDate*)addDays:(NSInteger)days toDate:(NSDate*)date {
NSDateComponents *dayComponent = [[NSDateComponents alloc] init];
dayComponent.day = days;
NSCalendar *theCalendar = [NSCalendar currentCalendar];
return [theCalendar dateByAddingComponents:dayComponent toDate:date options:0];
}
+ (NSDate*)dateWithoutTime:(NSDate*)date {
if (date == nil) {
return nil;
}
NSDateComponents *comps = [[NSCalendar currentCalendar]
components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay
fromDate:date];
return [[NSCalendar currentCalendar] dateFromComponents:comps];
}
+ (NSDate*)dateFromNaturalLanguageString:(NSString*)string {
// This method's structure of comparing localized strings, rather than just using
// an NSDataDetector, came about because NSDataDetector does not properly find dates
// in short strings such as "today", "tomorrow", or "Friday". NSDataDetector does find
// dates when a time is specified, such as "today at 00:00", but it also finds the time
// when nonsense plus a time is specified, as in "never at 00:00" (which returns today's date
// at midnight).
if (!string) {
return nil;
}
NSString *todayString = NSLocalizedStringFromTable(@"today", @"RelativeDates", @"today");
if ([string caseInsensitiveCompare:todayString] ==
NSOrderedSame) {
return [self today];
}
NSString *tomorrowString = NSLocalizedStringFromTable(@"tomorrow", @"RelativeDates",
@"tomorrow");
if ([string caseInsensitiveCompare:tomorrowString]
== NSOrderedSame) {
return [self addDays:1 toDate:[self today]];
}
NSString *yesterdayString = NSLocalizedStringFromTable(@"yesterday", @"RelativeDates",
@"yesterday");
if ([string caseInsensitiveCompare:yesterdayString]
== NSOrderedSame) {
return [self addDays:-1 toDate:[self today]];
}
NSString *testString = [string lowercaseString];
NSDate *returnDate;
NSArray *weekdayNames =
@[[NSLocalizedStringFromTable(@"Monday", @"RelativeDates", @"Monday") lowercaseString],
[NSLocalizedStringFromTable(@"Tuesday", @"RelativeDates", @"Tuesday") lowercaseString],
[NSLocalizedStringFromTable(@"Wednesday", @"RelativeDates", @"Wednesday") lowercaseString],
[NSLocalizedStringFromTable(@"Thursday", @"RelativeDates", @"Thursday") lowercaseString],
[NSLocalizedStringFromTable(@"Friday", @"RelativeDates", @"Friday") lowercaseString],
[NSLocalizedStringFromTable(@"Saturday", @"RelativeDates", @"Saturday") lowercaseString],
[NSLocalizedStringFromTable(@"Sunday", @"RelativeDates", @"Sunday") lowercaseString]];
returnDate = [self relativeDateFromWeekdayName:testString
withAllowedWeekdayNames:weekdayNames
withDateFormat:@"eeee"];
if (returnDate) {
return returnDate;
}
NSArray *shortWeekdayNames =
@[[NSLocalizedStringFromTable(@"Mon", @"RelativeDates", @"Mon") lowercaseString],
[NSLocalizedStringFromTable(@"Tue", @"RelativeDates", @"Tue") lowercaseString],
[NSLocalizedStringFromTable(@"Wed", @"RelativeDates", @"Wed") lowercaseString],
[NSLocalizedStringFromTable(@"Thu", @"RelativeDates", @"Thu") lowercaseString],
[NSLocalizedStringFromTable(@"Fri", @"RelativeDates", @"Fri") lowercaseString],
[NSLocalizedStringFromTable(@"Sat", @"RelativeDates", @"Sat") lowercaseString],
[NSLocalizedStringFromTable(@"Sun", @"RelativeDates", @"Sun") lowercaseString]];
returnDate = [self relativeDateFromWeekdayName:testString
withAllowedWeekdayNames:shortWeekdayNames
withDateFormat:@"eee"];
if (returnDate) {
return returnDate;
}
return nil;
}
+ (NSDate*)relativeDateFromWeekdayName:(NSString*)weekdayName
withAllowedWeekdayNames:(NSArray*)allowedWeekdayNames
withDateFormat:(NSString*)dateFormat {
NSSet *weekdayNamesSet = [NSSet setWithArray:allowedWeekdayNames];
if (![weekdayNamesSet containsObject:weekdayName]) {
return nil;
}
NSDateFormatter *dateFormatter = [self dateFormatter];
[dateFormatter setDateFormat:dateFormat];
NSDate *todaysDate = [self today];
for (NSUInteger i = 1; i < 8; i++) {
NSDate *testDate = [self addDays:i toDate:todaysDate];
NSString *generatedWeekdayName = [[dateFormatter stringFromDate:testDate] lowercaseString];
if ([weekdayName caseInsensitiveCompare:generatedWeekdayName] == NSOrderedSame) {
return testDate;
}
}
return nil;
}
+ (NSString*)dateStringFromNaturalLanguageString:(NSString*)naturalLanguageString {
NSDate *date = [self dateFromNaturalLanguageString:naturalLanguageString];
if (date == nil) {
return nil;
} else {
return [self convertDateToString:date];
}
}
+ (NSInteger)daysBetweenDate:(NSDate*)startDate andEndDate:(NSDate*)endDate {
NSCalendar *currentCalendar = [NSCalendar currentCalendar];
NSDateComponents *components = [currentCalendar components:NSCalendarUnitDay fromDate:startDate toDate:endDate options:NSCalendarMatchFirst];
return components.day;
}
@end
================================================
FILE: TodoTxtMac/TTMDocument.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@class TTMAppController;
@class TTMFieldEditor;
@class TTMTask;
@class TTMTasklistMetadata;
@class TTMTableView;
@class TTMTableViewDelegate;
#define TASKMENUTAG 3000
#define SORTMENUTAG 4000
#define FILTERMENUTAG 5000
#define STATUSBARMENUITEMTAG 6000
#define COPYTASKTONEWTASKMENUTAG 7000
typedef enum : NSUInteger {
TTMSortOrderInFile,
TTMSortPriority,
TTMSortProject,
TTMSortContext,
TTMSortDueDate,
TTMSortCreationDate,
TTMSortCompletionDate,
TTMSortThresholdDate,
TTMSortAlphabetical
} TTMTaskListSortType;
@interface TTMDocument : NSDocument
#pragma mark - Properties
// Data elements related to the task list
@property (nonatomic, copy) NSMutableArray *taskList;
@property (nonatomic) BOOL usesWindowsLineEndings;
@property (nonatomic, copy) NSString *preferredLineEnding;
// Window controls
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@property (nonatomic, retain) IBOutlet NSSearchField *searchField;
@property (nonatomic, retain) IBOutlet NSPredicate *searchFieldPredicate;
@property (nonatomic, retain) IBOutlet TTMTableView *tableView;
@property (nonatomic, retain) IBOutlet TTMTableViewDelegate *tableViewDelegate;
@property (nonatomic, retain) IBOutlet NSArrayController *arrayController;
@property (nonatomic, retain) IBOutlet NSCell *rawTextCell;
@property (nonatomic, retain) TTMFieldEditor *customFieldEditor;
@property (nonatomic, retain) IBOutlet NSTextField *statusBarTextField;
@property (nonatomic, retain) NSString *statusBarText;
@property (nonatomic, retain) IBOutlet NSLayoutConstraint *bottomConstraint;
@property (nonatomic, retain) IBOutlet NSView *findReplaceView;
@property (nonatomic, retain) IBOutlet NSTextField *findText;
@property (nonatomic, retain) IBOutlet NSTextField *replaceText;
// User font preference
@property (nonatomic) BOOL usingUserFont;
@property (nonatomic, retain) NSFont *userFont;
// Active filter predicate
@property (nonatomic, retain) NSPredicate *activeFilterPredicate;
@property (nonatomic) NSUInteger activeFilterPredicateNumber;
// Active sort type
@property (nonatomic) NSUInteger activeSortType;
// Tasklist metadata
@property (nonatomic, retain) TTMTasklistMetadata *tasklistMetadata;
@property (nonatomic, retain) TTMTasklistMetadata *filteredTasklistMetadata;
@property (nonatomic, retain) IBOutlet NSWindow *tasklistMetadataSheet;
// Task objects for undo/redo of task edits
@property (nonatomic, copy) NSArray *originalTasks;
@property (nonatomic, retain) NSDate *lastInternalModificationDate;
#pragma mark - File Loading and Saving Methods
/*!
* @method reloadFile:
* @abstract Reloads the task list file.
*/
- (IBAction)reloadFile:(id)sender;
/*!
* @method getTaskListSelections
* @abstract This method gets/saves selected items in the task list before the reload:
* method reloads the task list file, to allow for selections to be retained (as much as possible)
* after the user reloads the file.
*/
- (NSMutableArray*)getTaskListSelections;
/*!
* @method setTaskListSelections:
* @param taskListSelections Array of task items to select
* @abstract This method re-sets selected items in the task list after the reload:
* method reloads the task list file, to allow for selections to be retained (as much as possible)
* after the user reloads the file. This method makes a best effort to select the same tasks as
* were selected before (which are to be returned by the getTaskListSelections: method prior to
* reloading the file. Tasks that change (i.e., are completed or otherwise modified) or removed
* from the list will not be selected after reload. For duplicate tasks (those with identical
* raw text), the first of the duplicate tasks will be selected.
*/
- (void)setTaskListSelections:(NSArray*)taskListSelectedItems;
#pragma mark - Undo/Redo Methods
/*!
* @method replaceTasks:withTasks:
* @abstract This method replaces one array of tasks with another in the task list.
* It is used for undo/redo operations, namely to undo the reload file command.
*/
- (void)replaceAllTasks:(NSArray*)newTasks;
/*!
* @method replaceTasks:withTasks:
* @abstract This method replaces one array of tasks with another in the task list.
* It is used for undo/redo operations.
*/
- (void)replaceTasks:(NSArray*)oldTasks withTasks:(NSArray*)newTasks;
/*!
* @method addTasks:
* @abstract This method adds an array of tasks to the task list.
* It is used for undo/redo operations.
*/
- (void)addTasks:(NSArray*)newTasks;
/*!
* @method addTasks:
* @abstract This method removes an array of tasks from the task list.
* It is used for undo/redo operations.
*/
- (void)removeTasks:(NSArray*)oldTasks;
/*!
* @method addTasks:
* @abstract This method performs and undo for the archive command.
* It is used for undo/redo operations.
*/
- (void)undoArchiveTasks:(NSArray*)archivedTasks fromArchiveFile:(NSString*)archiveFilePath;
#pragma mark - Add/Remove Task(s) methods
/*!
* @method createWorkingTaskWithRawText:createWorkingTaskWithRawText
* @abstract Creates a task object to be inserted into the task list.
* @param rawText The text to base the task on
* @param newTaskId The (zero-based) numerical position of the task within the todo.txt file.
*/
- (TTMTask*)createWorkingTaskWithRawText:(NSString*)rawText withTaskId:(NSUInteger)newTaskId;
/*!
* @method moveFocusToNewTaskTextField:
* @abstract Moves focus to the new task text field so the user can type in a new task.
*/
- (IBAction)moveFocusToNewTaskTextField:(id)sender;
/*!
* @method removeAllTasks:
* @abstract Removes all tasks from the task list.
* @discussion This method is called before a todo.txt file is loaded.
*/
- (void)removeAllTasks;
/*!
* @method addTasksFromArray:removeAllTasksFirst:undoActionName
* @abstract Add tasks from an array to the task list.
* @param rawTextStrings The array of tasks' raw text strings.
* @param removeAllRecordsFirst Set to YES if all records should be removed prior to adding tasks.
* @param undoActionName Set to undo action name; blank if operation is not undoable
*/
- (void)addTasksFromArray:(NSArray*)rawTextStrings
removeAllTasksFirst:(BOOL)removeAllRecordsFirst
undoActionName:(NSString*)undoActionName;
/*!
* @method addNewTask:
* @abstract Adds a new task to the task list based on the content of the text field.
*/
- (IBAction)addNewTask:(id)sender;
/*!
* @method tabFromTextFieldToTaskList:
* @abstract Simulate a tab keypress to move from the text field to the task list.
* @discussion This method is optionally called in the addNewTask: method.
*/
- (void)tabFromTextFieldToTaskList;
/*!
* @method addNewTasksFromClipboard:
* @abstract Adds tasks on the clipboard (one or more tasks separated by line breaks)
* to the task list.
*/
- (void)addNewTasksFromClipboard:(id)sender;
/*!
* @method addNewTasksFromDragAndDrop:
* @abstract Add tasks from drag and drop (of text) onto the task list.
*/
- (IBAction)addNewTasksFromDragAndDrop:(id)sender;
/*!
* @method addNewTasksFromPasteBoard:
* @abstract Adds tasks from a pasteboard to the task list.
* @param pasteboard The pasteboard, either the general pasteboard or the dragging pasteboard.
* @discussion This is a convenience method called from both addNewTasksFromClipboard: and
* addNewTasksFromDragAndDrop:.
*/
- (void)addNewTasksFromPasteBoard:(NSPasteboard*)pasteboard;
/*!
* @method copyTaskToNewTask:
* @abstract Copies selected task to new tast text edit box.
*/
- (IBAction)copyTaskToNewTask:(id)sender;
#pragma mark - Update Task Methods
/*!
* @method refreshTaskListWithSave:
* @abstract Refresh the task list array controller and table view, and refresh
* the lists of projects and contexts used for autocompletion. Optionally save the
* file prior to calling the refresh.
* @param saveToFile Set to YES to save the file before the refresh.
*/
- (void)refreshTaskListWithSave:(BOOL)saveToFile;
/*!
* @method visualRefreshOnly:
* @abstract Refreshes the tableView control to apply color changes, etc., only.
*/
- (IBAction)visualRefreshOnly:(id)sender;
/*!
* @method setTaskListFont:
* @abstract Sets/changes font for task list.
*/
- (void)setTaskListFont;
/*!
* @method updateSelectedTask:
* @abstract Set the selected task in the task list to edit mode.
*/
- (IBAction)updateSelectedTask:(id)sender;
/*!
* @method initializeUpdateSelectedTask:
* @abstract Captures undo data for the update task list command, prior to the update being made.
*/
- (void)initializeUpdateSelectedTask;
/*!
* @method finalizeUpdateSelectedTask:rawText
* @abstract Finalizes preparation of undo data for the update task list command,
* after the update is made.
*/
- (void)finalizeUpdateSelectedTask:(NSString*)rawText;
/*!
* @method toggleTaskCompletion:
* @abstract Marks incomplete tasks completed. Marks complete tasks incomplete.
*/
- (IBAction)toggleTaskCompletion:(id)sender;
/*!
* @method deleteSelectedTasks:
* @abstract Delete selected tasks in the task list.
*/
- (IBAction)deleteSelectedTasks:(id)sender;
/*!
* @method appendText:
* @abstract Append text, entered in a modal sheet, to selected tasks.
*/
- (IBAction)appendText:(id)sender;
/*!
* @method prependText:
* @abstract Prepend text, entered in a modal sheet, to selected tasks.
*/
- (IBAction)prependText:(id)sender;
/*!
* @method replaceText:
* @abstract Find and replace text, entered in a modal sheet, to selected tasks.
*/
- (IBAction)replaceText:(id)sender;
#pragma mark - Priority Methods
/*!
* @method setPriority:
* @abstract Sets the priority for selected tasks via a modal sheet.
*/
- (IBAction)setPriority:(id)sender;
/*!
* @method increasePriority:
* @abstract Increases the priority of selected tasks by 1, e.g. from B to A.
*/
- (IBAction)increasePriority:(id)sender;
/*!
* @method decreasePriority:
* @abstract Decreases the priority of selected tasks by 1, e.g. from A to B.
*/
- (IBAction)decreasePriority:(id)sender;
/*!
* @method removePriority:
* @abstract Removes the priority from selected tasks.
*/
- (IBAction)removePriority:(id)sender;
#pragma mark - Postpone and Due Date Methods
/*!
* @method setDueDate:
* @abstract Sets the due date for selected tasks via a modal sheet.
*/
- (IBAction)setDueDate:(id)sender;
/*!
* @method increaseDueDateByOneDay:
* @abstract Increases the due date of selected tasks by one day, e.g. from 2014-12-01 to 2014-12-02.
*/
- (IBAction)increaseDueDateByOneDay:(id)sender;
/*!
* @method decreaseDueDateByOneDay:
* @abstract Decreases the due date of selected tasks by one day, e.g. from 2014-12-02 to 2014-12-01.
*/
- (IBAction)decreaseDueDateByOneDay:(id)sender;
/*!
* @method removeDueDate:
* @abstract Removes due date from selected tasks.
*/
- (IBAction)removeDueDate:(id)sender;
/*!
* @method postpone:
* @abstract Postpones (increases) the due date of selected tasks by a user-entered number of days,
* which is entered via a modal sheet.
* @discussion This method can be used to decrease the due date of selected tasks, too, if the user
* enters a negative number.
*/
- (IBAction)postpone:(id)sender;
#pragma mark - Threshold Date Methods
/*!
* @method setThresholdDate:
* @abstract Sets the threshold date for selected tasks via a modal sheet.
*/
- (IBAction)setThresholdDate:(id)sender;
/*!
* @method increaseThresholdDateByOneDay:
* @abstract Increases the threshold date of selected tasks by one day, e.g. from 2014-12-01 to 2014-12-02.
*/
- (IBAction)increaseThresholdDateByOneDay:(id)sender;
/*!
* @method decreaseDueDateByOneDay:
* @abstract Decreases the threshold date of selected tasks by one day, e.g. from 2014-12-02 to 2014-12-01.
*/
- (IBAction)decreaseThresholdDateByOneDay:(id)sender;
/*!
* @method removeThresholdDate:
* @abstract Removes threshold date for selected tasks.
*/
- (IBAction)removeThresholdDate:(id)sender;
#pragma mark - Sort Methods
/*!
* @method sortTaskList:
* @abstract Sorts the task list.
* @param sortType An enum value that specifies the sort type.
* @discussion This method also sets the default sort type to whatever sort type is passed to it.
*/
- (void)sortTaskList:(TTMTaskListSortType)sortType;
/*!
* @method sortTaskListUsingTagforPreset:
* @abstract Sorts the task list, using the preset number found in the sender's tag.
*/
- (IBAction)sortTaskListUsingTagforPreset:(id)sender;
#pragma mark - Filter Methods
/*!
* @method combineFilterPresetPredicate:withSearchFilterPredicate
* @abstract Combines the filter preset predicate applied to the task list with the search field
* predicate in an "AND" fashion.
*/
- (NSPredicate*)combineFilterPresetPredicate:(NSPredicate*)filterPresetPredicate
withSearchFilterPredicate:(NSPredicate*)searchFilterPredicate;
/*!
* @method filterTaskListUsingTagforPreset:
* @abstract Sets the filter on the task list to a numbered preset, based on the sender's tag.
* Filter preset 0 is defined to mean "no filter".
*/
- (IBAction)filterTaskListUsingTagforPreset:(id)sender;
/*!
* @method removeTaskListFilter:
* @abstract Removes the currently active filter.
*/
- (void)removeTaskListFilter;
/*!
* @method reapplyActiveFilterPredicate:
* @abstract Applies the active filter to the task list.
*/
- (void)reapplyActiveFilterPredicate;
/*!
* @method changeActiveFilterPredicateToPreset:
* @abstract Changes the active filter preset to the one the user selected.
* @param presetNumber The preset number the user selected.
*/
- (void)changeActiveFilterPredicateToPreset:(NSUInteger)presetNumber;
#pragma mark - Archive Methods
/*!
* @method archiveCompletedTasks:
* @abstract Archives all completed tasks to the user-specified archive file.
* @discussion The user must specify an archive file in the application's preferences.
* There is only one archive file; any open task file will archive to the same file.
*/
- (IBAction)archiveCompletedTasks:(id)sender;
/*!
* @method appendString:toArchiveFile:
* @abstract Appends a string, which can contain one or more tasks, to another file.
* @param content One or more tasks. Multiple tasks must be separated by line breaks.
* @param archiveFilePath Archive file path. This path must be specified by the file path
* saved in the application's preferences and obtained using the standard file open dialog.
* @discussion This is a convenience method called by the archiveCompletedTasks: method.
*/
- (void)appendString:(NSString*)content toArchiveFile:(NSString*)archiveFilePath;
- (void)removeTasks:(NSArray*)tasksToRemove fromArchiveFile:(NSString*)archiveFilePath;
#pragma mark - Find Methods
/*!
* @method moveFocusToSearchBox:
* @abstract Moves focus to the search box to find text.
*/
- (IBAction)moveFocusToSearchBox:(id)sender;
/*!
* @method makeSearchBoxRefuseFocus:
* @abstract Resets search box to refuse first responder (so user cannot tab to it).
*/
- (IBAction)makeSearchBoxRefuseFocus:(id)sender;
#pragma mark - Tasklist Metadata Methods
/*!
* @method showTasklistMetadata:
* @abstract Display tasklist metadata in a modal sheet.
*/
- (IBAction)showTasklistMetadata:(id)sender;
/*!
* @method hideTasklistMetadata:
* @abstract Hide tasklist metadata modal sheet.
*/
- (IBAction)hideTasklistMetadata:(id)sender;
#pragma mark - Status Bar Methods
/*!
* @method updateStatusBarText:
* @abstract Updates the status bar text, based on the properties of the TTMDocument.
*/
- (void)updateStatusBarText;
/*!
* @method statusBarVisable:
* @abstract Returns whether the status bar is visible.
*/
- (BOOL)statusBarVisable;
/*!
* @method setStatusBarVisable:
* @abstract Show or hide the status bar.
* Each time this method is called the choice to show or hide the status bar is saved to user
* defaults. The next window opened (including after relaunch) will either show or hide the
* status bar according to the flag passed to this method.
* @param flag Set to true to show the status bar; set to false to hide the status bar.
*/
- (void)setStatusBarVisable:(BOOL)flag;
/*!
* @method toggleStatusBarVisability:
* @abstract Change whether the status bar is shown or hidden.
*/
- (IBAction)toggleStatusBarVisability:(id)sender;
- (void)setTableWidthToWidthOfContents;
@end
================================================
FILE: TodoTxtMac/TTMDocument.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMDocument.h"
#import "TTMTask.h"
#import "TTMDateUtility.h"
#import "TTMTableView.h"
#import "TTMTableViewDelegate.h"
#import "TTMFilterPredicates.h"
#import "TTMFieldEditor.h"
#import "RegExCategories.h"
#import "TTMTasklistMetadata.h"
#import "TTMDocumentStatusBarText.h"
@implementation TTMDocument
#pragma mark - Instance Variables
static NSString * const RelativeDueDatePattern = @"(?<=due:)\\S*";
#pragma mark - init Methods
- (id)init
{
self = [super init];
if (self) {
[[self undoManager] disableUndoRegistration];
_taskList = [[NSMutableArray alloc] init];
_arrayController = [[NSArrayController alloc] initWithContent:_taskList];
_preferredLineEnding = @"\n";
_usesWindowsLineEndings = NO;
_activeFilterPredicateNumber = [TTMFilterPredicates activeFilterPredicatePresetNumber];
[self.undoManager setLevelsOfUndo:[[NSUserDefaults standardUserDefaults]
integerForKey:@"levelsOfUndo"]];
[[self undoManager] enableUndoRegistration];
_lastInternalModificationDate = nil;
}
return self;
}
- (void)awakeFromNib {
// Set custom field editor.
// Set arrayController sort type.
self.activeSortType = [[NSUserDefaults standardUserDefaults] integerForKey:@"taskListSortType"];
[self sortTaskList:self.activeSortType];
// Load active filter predicate.
self.activeFilterPredicate = [TTMFilterPredicates activeFilterPredicate];
// Set up drag and drop for tableView.
[self.tableView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:NO];
[self.tableView registerForDraggedTypes:[NSArray arrayWithObject:NSStringPboardType]];
[self setTaskListFont];
[self setTableWidthToWidthOfContents];
// Observe array controller selection to update "selected tasks" count in status bar
[self.arrayController addObserver:self forKeyPath:@"selection" options:NSKeyValueObservingOptionNew context:nil];
// Observe self to update search field filter
[self addObserver:self forKeyPath:@"searchFieldPredicate" options:NSKeyValueObservingOptionNew context:nil];
// Observe NSUserDefaults to update undo-related preferences
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"levelsOfUndo"
options:NSKeyValueObservingOptionNew
context:nil];
// Observe NSUserDefaults to update filter-related preferences
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"filterPredicate1"
options:NSKeyValueObservingOptionNew
context:nil];
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"filterPredicate2"
options:NSKeyValueObservingOptionNew
context:nil];
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"filterPredicate3"
options:NSKeyValueObservingOptionNew
context:nil];
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"filterPredicate4"
options:NSKeyValueObservingOptionNew
context:nil];
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"filterPredicate5"
options:NSKeyValueObservingOptionNew
context:nil];
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"filterPredicate6"
options:NSKeyValueObservingOptionNew
context:nil];
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"filterPredicate7"
options:NSKeyValueObservingOptionNew
context:nil];
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"filterPredicate8"
options:NSKeyValueObservingOptionNew
context:nil];
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"filterPredicate9"
options:NSKeyValueObservingOptionNew
context:nil];
}
- (NSString *)windowNibName {
return @"TTMDocument";
}
- (void)windowControllerDidLoadNib:(NSWindowController *)aController {
[super windowControllerDidLoadNib:aController];
// Add any code here that needs to be executed once the windowController
// has loaded the document's window.
[self setStatusBarVisable:[[NSUserDefaults standardUserDefaults] boolForKey:@"showStatusBar"]];
}
- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client {
if (!self.customFieldEditor) {
self.customFieldEditor = [[TTMFieldEditor alloc] init];
}
[self.customFieldEditor setFieldEditor:YES];
self.customFieldEditor.projectsArray = self.tasklistMetadata.projectsArray;
self.customFieldEditor.contextsArray = self.tasklistMetadata.contextsArray;
self.customFieldEditor.drawsBackground = YES;
self.customFieldEditor.backgroundColor = [NSColor whiteColor];
return self.customFieldEditor;
}
#pragma mark - File Loading and Saving Methods
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError {
// Prepare file contents to save.
NSMutableString *fileData = [[NSMutableString alloc] init];
for (int i = 0; i < [self.taskList count]; i++) {
if ([[self.taskList objectAtIndex:i] isKindOfClass:[TTMTask class]]) {
NSString *line = [[self.taskList objectAtIndex:i] rawText];
// Append the string to fileData if it is not null.
// Appending a null causes an exception.
if (line) {
[fileData appendString:line];
[fileData appendString:self.preferredLineEnding];
}
}
}
return [fileData dataUsingEncoding:NSUTF8StringEncoding];
}
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError {
// Read file contents.
NSString *fileContents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (!fileContents) {
if (outError != nil) {
*outError = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFileReadUnknownError
userInfo:nil];
}
return NO;
}
// Check the line endings in the file, and remember if Windows line endings ("\r\n") are used.
self.usesWindowsLineEndings = ([fileContents rangeOfString:@"\r\n"].location != NSNotFound);
self.preferredLineEnding = (self.usesWindowsLineEndings) ? @"\r\n" : @"\n";
// Split contents of file into an array of strings.
// Note: A file with Windows line endings ("\r\n") may also have Unix line endings ("\n").
// This can happen if a text file is created on Windows, then is edited on the Mac
// (in TextEdit, for example).
// Because inconsistent line endings can exist, for files with Windows line endings,
// we remove the carriage return character prior to splitting the file contents into
// an array of strings.
NSArray *rawTextStrings = (self.usesWindowsLineEndings) ?
[[fileContents stringByReplacingOccurrencesOfString:@"\r" withString:@""] componentsSeparatedByString:@"\n"] :
[fileContents componentsSeparatedByString:@"\n"];
// Refresh the arrayController and tableView
[self addTasksFromArray:rawTextStrings removeAllTasksFirst:YES undoActionName:@""];
[self updateLastInternalModificationDate];
return YES;
}
- (void)updateLastInternalModificationDate {
NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:self];
NSError *outError;
[fileCoordinator coordinateReadingItemAtURL:self.fileURL options:0 error:&outError byAccessor:^(NSURL *fileURL) {
NSError *error;
NSDate *fileDate;
[fileURL getResourceValue:&fileDate forKey:NSURLContentModificationDateKey error:&error];
self.lastInternalModificationDate = fileDate;
}];
}
- (IBAction)reloadFile:(id)sender {
[[self.undoManager prepareWithInvocationTarget:self] replaceAllTasks:[self.taskList copy]];
[self.undoManager setActionName:NSLocalizedString(@"Reload File", @"Undo Reload File")];
// retain selected items, because selection is lost when the file/arrayController is reloaded
NSArray *taskListSelectedItemsList = [self getTaskListSelections];
// Reload the file.
NSError *error;
[self revertToContentsOfURL:self.fileURL ofType:@"NSString" error:&error];
// re-set selected items
[self setTaskListSelections:taskListSelectedItemsList];
[self updateTaskListMetadata];
}
- (NSArray*)getTaskListSelections {
return [[self.arrayController selectedObjects] copy];
}
- (void)setTaskListSelections:(NSArray*)taskListSelectedItems {
if (taskListSelectedItems == nil) {
return;
}
NSMutableArray *selectedItems = [NSMutableArray arrayWithArray:taskListSelectedItems];
NSMutableArray *itemsToSelect = [NSMutableArray array];
for (TTMTask *task in [self.arrayController arrangedObjects]) {
int i = 0;
BOOL selected = NO;
while (i < [selectedItems count] && !selected) {
TTMTask *selection = [selectedItems objectAtIndex:i];
if ([task.rawText isEqualToString:selection.rawText]) {
[itemsToSelect addObject:task];
[selectedItems removeObjectAtIndex:i];
selected = YES;
}
else {
i++;
}
}
}
[self.arrayController setSelectedObjects:itemsToSelect];
}
- (void)presentedItemDidChange {
dispatch_async(dispatch_get_main_queue(), ^{
[self performSynchronousFileAccessUsingBlock:^{
NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:self];
NSError *outError;
[fileCoordinator coordinateReadingItemAtURL:self.fileURL options:0 error:&outError byAccessor:^(NSURL *fileURL) {
NSError *error;
NSDate *fileDate;
[fileURL getResourceValue:&fileDate forKey:NSURLContentModificationDateKey error:&error];
if (![self.lastInternalModificationDate isEqualToDate:fileDate] && !self.tableView.isEditing) {
[self reloadFile:self];
}
}];
}];
});
}
+ (BOOL)autosavesInPlace {
return YES;
}
#pragma mark - Undo/Redo Methods
- (void)replaceAllTasks:(NSArray*)newTasks {
[[self.undoManager prepareWithInvocationTarget:self] replaceAllTasks:[[self.arrayController arrangedObjects] copy]];
NSRange range = NSMakeRange(0, [[self.arrayController arrangedObjects] count]);
// retain selected items, because selection is lost when the file/arrayController is reloaded
NSArray *taskListSelectedItemsList = [self getTaskListSelections];
// Save the current filter number.
NSUInteger filterNumber = self.activeFilterPredicateNumber;
// Remove the current filter.
[self removeTaskListFilter];
// remove all tasks
[self.arrayController removeObjectsAtArrangedObjectIndexes:[NSIndexSet indexSetWithIndexesInRange:range]];
// add new tasks
[self.arrayController addObjects:newTasks];
// Refresh the task list.
[self refreshTaskListWithSave:NO];
// Re-apply the filter active before the file was reloaded.
[self changeActiveFilterPredicateToPreset:filterNumber];
// re-set selected items
[self setTaskListSelections:taskListSelectedItemsList];
}
- (void)replaceTasks:(NSArray*)oldTasks withTasks:(NSArray*)newTasks {
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.arrayController removeObjects:oldTasks];
[self.arrayController addObjects:newTasks];
[self refreshTaskListWithSave:YES];
}
- (void)addTasks:(NSArray*)newTasks {
[[self.undoManager prepareWithInvocationTarget:self] removeTasks:newTasks];
[self.arrayController addObjects:newTasks];
[self refreshTaskListWithSave:YES];
}
- (void)removeTasks:(NSArray*)oldTasks {
[[self.undoManager prepareWithInvocationTarget:self] addTasks:oldTasks];
[self.arrayController removeObjects:oldTasks];
[self refreshTaskListWithSave:YES];
}
- (void)undoArchiveTasks:(NSArray*)archivedTasks fromArchiveFile:(NSString*)archiveFilePath {
[self addTasks:archivedTasks];
[self removeTasks:archivedTasks fromArchiveFile:archiveFilePath];
}
#pragma mark - Add/Remove Task Methods
- (TTMTask*)createWorkingTaskWithRawText:(NSString*)rawText withTaskId:(NSUInteger)newTaskId {
// Convert natural-language due dates, such as "due:today" and "due:tomorrow", to YYYY-MM-DD.
NSString *relativeDueDateText = [rawText firstMatch:RX(RelativeDueDatePattern)];
NSString *relativeDueDateReplacementText =
[TTMDateUtility dateStringFromNaturalLanguageString:relativeDueDateText];
if (relativeDueDateReplacementText != nil) {
rawText = [rawText replace:RX(RelativeDueDatePattern)
with:relativeDueDateReplacementText];
}
// Optionally prepend the creation date and create the task.
BOOL prependDate = [[NSUserDefaults standardUserDefaults] boolForKey:@"prependDateOnNewTasks"];
TTMTask *workingTask = (prependDate) ?
[[self.arrayController newObject] initWithRawText:rawText
withTaskId:newTaskId
withPrependedDate:[TTMDateUtility today]] :
[[self.arrayController newObject] initWithRawText:rawText withTaskId:newTaskId];
return workingTask;
}
- (IBAction)moveFocusToNewTaskTextField:(id)sender {
[self.textField becomeFirstResponder];
}
- (void)removeAllTasks {
for (TTMTask *task in self.taskList) {
[self.arrayController removeObject:task];
}
}
- (void)addTasksFromArray:(NSArray*)rawTextStrings
removeAllTasksFirst:(BOOL)removeAllTasksFirst
undoActionName:(NSString*)undoActionName {
if (removeAllTasksFirst) {
[self removeAllTasks];
}
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
NSUInteger newTaskId = (self.arrayController == nil) ?
[self.taskList count] :
[[self.arrayController arrangedObjects] count];
for (NSString *rawTextString in rawTextStrings) {
if (rawTextString.length > 0) {
TTMTask *newTask;
if (removeAllTasksFirst) {
newTask = [[TTMTask alloc]
initWithRawText:(NSString*)rawTextString
withTaskId:newTaskId++];
[self.arrayController addObject:newTask];
} else {
newTask = [self createWorkingTaskWithRawText:(NSString*)rawTextString
withTaskId:newTaskId++];
[self.arrayController addObject:newTask];
}
[newTasks addObject:[newTask copy]];
}
}
if ([undoActionName length] > 0) {
[self.undoManager setActionName:undoActionName];
[[self.undoManager prepareWithInvocationTarget:self] removeTasks:newTasks];
}
if (removeAllTasksFirst) {
[self visualRefreshOnly:self];
} else {
[self updateTaskListMetadata];
}
}
- (IBAction)addNewTask:(id)sender {
NSString *newTaskText = [self.textField stringValue];
// Reject zero-length input.
if ([newTaskText length] == 0) {
return;
}
NSUInteger newTaskId = [[self.arrayController arrangedObjects] count];
TTMTask *newTask = [self createWorkingTaskWithRawText:newTaskText
withTaskId:newTaskId];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
[newTasks addObject:[newTask copy]];
[[self.undoManager prepareWithInvocationTarget:self] removeTasks:newTasks];
[self.undoManager setActionName:NSLocalizedString(@"Add New Task", @"Undo Add New Task")];
[self.arrayController addObject:newTask];
[self reapplyActiveFilterPredicate];
[self refreshTaskListWithSave:YES];
[self.textField setStringValue:@""];
// Optionally move focus to the task list depending on the user setting.
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"moveToTaskListAfterTaskCreation"]) {
if ([self.arrayController.selectedObjects containsObject:newTask]) {
[self tabFromTextFieldToTaskList];
[self.tableView scrollRowToVisible:self.tableView.selectedRow];
}
}
}
- (void)tabFromTextFieldToTaskList {
// Simulate a tab press.
unichar keyChar = 9;
NSString *keyDownString = [NSString stringWithCharacters:&keyChar length:1];
NSPoint point = {0, 0};
NSEvent *newEvent =[NSEvent keyEventWithType:NSKeyDown
location:point
modifierFlags:0
timestamp:[NSDate timeIntervalSinceReferenceDate]
windowNumber:self.windowForSheet.windowNumber
context:nil
characters:keyDownString
charactersIgnoringModifiers:keyDownString
isARepeat:NO
keyCode:keyChar];
[NSApp postEvent:newEvent atStart:YES];
}
- (void)addNewTasksFromClipboard:(id)sender {
[self addNewTasksFromPasteBoard:[NSPasteboard generalPasteboard]];
}
- (void)addNewTasksFromDragAndDrop:(id)sender {
[self.undoManager setActionName:NSLocalizedString(@"Drag and Drop", @"Undo Drag and Drop")];
[self addNewTasksFromPasteBoard:[sender draggingPasteboard]];
}
- (void)addNewTasksFromPasteBoard:(NSPasteboard*)pasteboard {
NSString *pasteboardText = [pasteboard stringForType:NSPasteboardTypeString];
if ([pasteboardText length] == 0) {
return;
}
NSArray *rawTextStrings = [pasteboardText
componentsSeparatedByCharactersInSet:
[NSCharacterSet newlineCharacterSet]];
[self addTasksFromArray:rawTextStrings
removeAllTasksFirst:NO undoActionName:NSLocalizedString(@"Paste", @"Undo Paste")];
[self reapplyActiveFilterPredicate];
[self refreshTaskListWithSave:YES];
}
- (IBAction)copyTaskToNewTask:(id)sender {
// cancel if multiple rows are selected
if ([[self.arrayController selectedObjects] count] != 1) {
return;
}
TTMTask *task = [[self.arrayController selectedObjects] objectAtIndex:0];
[self.textField setStringValue:task.rawText];
[self moveFocusToNewTaskTextField:self];
}
#pragma mark - Update Task Methods
- (void)refreshTaskListWithSave:(BOOL)saveToFile {
// retain selected items, because selection is lost when the file/arrayController is reloaded
NSArray *taskListSelectedItemsList = [self getTaskListSelections];
// Optionally save the file.
if (saveToFile) {
[self saveToFile];
}
// Re-sort the table.
[self.arrayController rearrangeObjects];
// Reload table.
[self.tableView reloadData];
[self setTableWidthToWidthOfContents];
// re-set selected items
[self setTaskListSelections:taskListSelectedItemsList];
// Update the lists of projects and contexts.
[self updateTaskListMetadata];
}
- (void)saveToFile {
[self autosaveWithImplicitCancellability:YES completionHandler:^(NSError * _Nullable errorOrNil) {
[self updateLastInternalModificationDate];
}];
}
- (BOOL)canAsynchronouslyWriteToURL:(NSURL *)url ofType:(NSString *)typeName forSaveOperation:(NSSaveOperationType)saveOperation {
return YES;
}
- (IBAction)visualRefreshOnly:(id)sender {
[self setTaskListFont];
[self reapplyActiveFilterPredicate];
[self.tableView reloadData];
[self setTableWidthToWidthOfContents];
[self updateTaskListMetadata];
}
- (void)setTaskListFont {
self.usingUserFont = [[NSUserDefaults standardUserDefaults] boolForKey:@"useUserFont"];
if (self.usingUserFont) {
self.userFont = [NSFont userFontOfSize:0.0];
} else {
self.userFont = [NSFont controlContentFontOfSize:0];
}
[self.rawTextCell setFont:self.userFont];
}
- (IBAction)updateSelectedTask:(id)sender {
// cancel if multiple rows are selected
if ([[self.arrayController selectedObjects] count] != 1) {
return;
}
[self.tableView editColumn:0 row:[self.tableView selectedRow] withEvent:nil select:YES];
}
- (void)initializeUpdateSelectedTask {
self.originalTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
}
- (void)finalizeUpdateSelectedTask:(NSString*)rawText {
NSArray *newTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTaskStrings = [[NSMutableArray alloc] init];
BOOL taskWasCompleted = NO;
BOOL recurringTasksWereCreated = NO;
BOOL prependDate = [[NSUserDefaults standardUserDefaults] boolForKey:@"prependDateOnNewTasks"];
for (TTMTask *task in newTasks) {
// if task is being marked complete...
if (task.isCompleted) {
taskWasCompleted = YES;
}
if (task.isCompleted && task.isRecurring) {
TTMTask *newTaskBase = [task copy];
[newTaskBase markIncomplete];
TTMTask *newTask = [newTaskBase newRecurringTask];
if (newTask != nil) {
recurringTasksWereCreated = YES;
if (prependDate) {
[newTask removeCreationDate];
}
[newTaskStrings addObject:newTask.rawText];
}
}
}
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks
withTasks:self.originalTasks];
[self.undoManager setActionName:NSLocalizedString(@"Edit Task", @"Undo Edit Task")];
self.originalTasks = nil;
if (taskWasCompleted && [[NSUserDefaults standardUserDefaults] integerForKey:@"archiveTasksUponCompletion"]) {
[self archiveCompletedTasks:self];
} else {
[self refreshTaskListWithSave:YES];
}
if (recurringTasksWereCreated) {
[self addTasksFromArray:newTaskStrings removeAllTasksFirst:NO undoActionName:NSLocalizedString(@"Add Recurring Task", @"")];
}
}
- (IBAction)toggleTaskCompletion:(id)sender {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
NSMutableArray *newTaskStrings = [[NSMutableArray alloc] init];
BOOL recurringTasksWereCreated = NO;
BOOL prependDate = [[NSUserDefaults standardUserDefaults] boolForKey:@"prependDateOnNewTasks"];
for (TTMTask *task in [self.arrayController selectedObjects]) {
// if task is being marked complete...
if (!task.isCompleted) {
if (task.isRecurring) {
TTMTask *newTask = [task newRecurringTask];
if (newTask != nil) {
if (prependDate) {
[newTask removeCreationDate];
}
[newTaskStrings addObject:newTask.rawText];
recurringTasksWereCreated = YES;
}
}
}
[task toggleCompletionStatus];
[newTasks addObject:[task copy]];
}
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Toggle Completion", @"Undo Toggle Completion")];
if ([[NSUserDefaults standardUserDefaults] integerForKey:@"archiveTasksUponCompletion"]) {
[self archiveCompletedTasks:self];
} else {
[self refreshTaskListWithSave:YES];
}
if (recurringTasksWereCreated) {
[self addTasksFromArray:newTaskStrings removeAllTasksFirst:NO undoActionName:NSLocalizedString(@"Add Recurring Tasks", @"")];
[self reapplyActiveFilterPredicate];
}
}
- (IBAction)deleteSelectedTasks:(id)sender {
NSAlert *deletePrompt = [[NSAlert alloc] init];
deletePrompt.messageText = @"Delete";
deletePrompt.informativeText = @"Are you sure you want to delete all selected tasks?";
[deletePrompt addButtonWithTitle:@"OK"];
[deletePrompt addButtonWithTitle:@"Cancel"];
[deletePrompt beginSheetModalForWindow:self.windowForSheet completionHandler:^(NSModalResponse returnCode) {
if (returnCode == NSAlertFirstButtonReturn) {
NSArray *oldTasks = [[NSArray alloc]
initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
[[self.undoManager prepareWithInvocationTarget:self] addTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Delete Tasks", @"Undo Delete Tasks")];
[self.arrayController removeObjectsAtArrangedObjectIndexes:[self.tableView selectedRowIndexes]];
[self refreshTaskListWithSave:YES];
}
}];
}
- (IBAction)appendText:(id)sender {
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Append Text";
alert.informativeText = @"Text to append to each selected task:";
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:@"Cancel"];
NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 295, 24)];
[input setStringValue:@""];
[alert setAccessoryView:input];
// Define the completion handler for the modal sheet.
void (^completionHandler)(NSModalResponse returnCode) = ^(NSModalResponse returnCode) {
if (returnCode != NSAlertFirstButtonReturn || [[input stringValue] length] == 0) {
return;
}
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task appendText:[input stringValue]];
[newTasks addObject:[task copy]];
}
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Append Text", @"Undo Append Text")];
};
[alert beginSheetModalForWindow:self.windowForSheet completionHandler: completionHandler];
[[alert.accessoryView window] makeFirstResponder:alert.accessoryView];
}
- (IBAction)prependText:(id)sender {
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Prepend Text";
alert.informativeText = @"Text to prepend to each selected task:";
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:@"Cancel"];
NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 295, 24)];
[input setStringValue:@""];
[alert setAccessoryView:input];
// Define the completion handler for the modal sheet.
void (^completionHandler)(NSModalResponse returnCode) = ^(NSModalResponse returnCode) {
if (returnCode != NSAlertFirstButtonReturn || [[input stringValue] length] == 0) {
return;
}
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task prependText:[input stringValue]];
[newTasks addObject:[task copy]];
}
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Prepend Text", @"Undo Prepend Text")];
};
[alert beginSheetModalForWindow:self.windowForSheet completionHandler: completionHandler];
[[alert.accessoryView window] makeFirstResponder:alert.accessoryView];
}
- (IBAction)replaceText:(id)sender {
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Replace Text";
alert.informativeText = @"Text to find and replace in each selected task:";
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:@"Cancel"];
[NSBundle.mainBundle loadNibNamed:@"TTMFindReplace" owner:self topLevelObjects:nil];
[alert setAccessoryView:self.findReplaceView];
// Define the completion handler for the modal sheet.
void (^completionHandler)(NSModalResponse returnCode) = ^(NSModalResponse returnCode) {
if (returnCode != NSAlertFirstButtonReturn || [[self.findText stringValue] length] == 0) {
return;
}
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task replaceText:[self.findText stringValue] withText:[self.replaceText stringValue]];
[newTasks addObject:[task copy]];
}
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Replace Text", @"Undo Replace Text")];
};
[alert beginSheetModalForWindow:self.windowForSheet completionHandler: completionHandler];
[[alert.accessoryView window] makeFirstResponder:alert.accessoryView];
}
#pragma mark - Priority Methods
- (IBAction)setPriority:(id)sender {
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Set Priority";
alert.informativeText = @"Priority:";
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:@"Cancel"];
NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 295, 24)];
[input setStringValue:@""];
[alert setAccessoryView:input];
// Define the completion handler for the modal sheet.
void (^completionHandler)(NSModalResponse returnCode) = ^(NSModalResponse returnCode) {
if (returnCode != NSAlertFirstButtonReturn || [[input stringValue] length] == 0) {
return;
}
NSString *uppercaseInputString = [[input stringValue] uppercaseString];
unichar priority = [uppercaseInputString characterAtIndex:0];
NSCharacterSet *validPriorityCharacters = [NSCharacterSet uppercaseLetterCharacterSet];
if (![validPriorityCharacters characterIsMember:priority]) {
return;
}
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task setPriority:priority];
[newTasks addObject:[task copy]];
}
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Set Priority", @"Undo Set Priority")];
[self refreshTaskListWithSave:YES];
};
[alert beginSheetModalForWindow:self.windowForSheet completionHandler: completionHandler];
[[alert.accessoryView window] makeFirstResponder:alert.accessoryView];
}
- (IBAction)increasePriority:(id)sender {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task increasePriority];
[newTasks addObject:[task copy]];
}
[self refreshTaskListWithSave:YES];
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Increase Priority", @"Undo Increase Priority")];
}
- (IBAction)decreasePriority:(id)sender {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task decreasePriority];
[newTasks addObject:[task copy]];
}
[self refreshTaskListWithSave:YES];
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Decrease Priority", @"Undo Decrease Priority")];
}
- (IBAction)removePriority:(id)sender {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task removePriority];
[newTasks addObject:[task copy]];
}
[self refreshTaskListWithSave:YES];
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Remove Priority", @"Undo Remove Priority")];
}
# pragma mark - Postpone/Due Date Methods
- (IBAction)setDueDate:(id)sender {
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Due date";
alert.informativeText = @"Set the due date:";
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:@"Cancel"];
NSDatePicker *input = [[NSDatePicker alloc] initWithFrame:NSMakeRect(0, 0, 110, 24)];
[input setDatePickerElements:NSYearMonthDayDatePickerElementFlag];
[input setDateValue:[TTMDateUtility today]];
[alert setAccessoryView:input];
// Define the completion handler for the modal sheet.
void (^completionHandler)(NSModalResponse returnCode) = ^(NSModalResponse returnCode) {
if (returnCode == NSAlertFirstButtonReturn) {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task setDueDate:[input dateValue]];
[newTasks addObject:[task copy]];
}
[self refreshTaskListWithSave:YES];
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Set Due Date", @"Undo Set Due Date")];
}
};
[alert beginSheetModalForWindow:self.windowForSheet completionHandler: completionHandler];
[[alert.accessoryView window] makeFirstResponder:alert.accessoryView];
}
- (IBAction)increaseDueDateByOneDay:(id)sender {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task incrementDueDate:1];
[newTasks addObject:[task copy]];
}
[self refreshTaskListWithSave:YES];
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Increase Due Date", @"Undo Increase Due Date")];
}
- (IBAction)decreaseDueDateByOneDay:(id)sender {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task decrementDueDate:1];
[newTasks addObject:[task copy]];
}
[self refreshTaskListWithSave:YES];
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Decrease Due Date", @"Undo Decrease Due Date")];
}
- (IBAction)removeDueDate:(id)sender {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task removeDueDate];
[newTasks addObject:[task copy]];
}
[self refreshTaskListWithSave:YES];
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Remove Due Date", @"Undo Remove Due Date")];
}
- (IBAction)postpone:(id)sender {
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Postpone";
alert.informativeText = @"Days to postpone task:";
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:@"Cancel"];
NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 295, 24)];
[input setStringValue:@""];
[alert setAccessoryView:input];
// Define the completion handler for the modal sheet.
void (^completionHandler)(NSModalResponse returnCode) = ^(NSModalResponse returnCode) {
if (returnCode == NSAlertFirstButtonReturn &&
[[input stringValue] length] != 0 &&
[input integerValue] != 0) {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task postponeTask:[input integerValue]];
[newTasks addObject:[task copy]];
}
[self refreshTaskListWithSave:YES];
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Postpone", @"Undo Postpone")];
}
};
[alert beginSheetModalForWindow:self.windowForSheet completionHandler: completionHandler];
[[alert.accessoryView window] makeFirstResponder:alert.accessoryView];
}
#pragma mark - Threshold Date Methods
- (IBAction)setThresholdDate:(id)sender {
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Threshold Date";
alert.informativeText = @"Set the threshold date:";
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:@"Cancel"];
NSDatePicker *input = [[NSDatePicker alloc] initWithFrame:NSMakeRect(0, 0, 110, 24)];
[input setDatePickerElements:NSYearMonthDayDatePickerElementFlag];
[input setDateValue:[TTMDateUtility today]];
[alert setAccessoryView:input];
// Define the completion handler for the modal sheet.
void (^completionHandler)(NSModalResponse returnCode) = ^(NSModalResponse returnCode) {
if (returnCode == NSAlertFirstButtonReturn) {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task setThresholdDate:[input dateValue]];
[newTasks addObject:[task copy]];
}
[self refreshTaskListWithSave:YES];
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Set Threshold Date", @"Undo Set Threshold Date")];
}
};
[alert beginSheetModalForWindow:self.windowForSheet completionHandler: completionHandler];
[[alert.accessoryView window] makeFirstResponder:alert.accessoryView];
}
- (IBAction)increaseThresholdDateByOneDay:(id)sender {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task incrementThresholdDate:1];
[newTasks addObject:[task copy]];
}
[self refreshTaskListWithSave:YES];
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Increase Threshold Date", @"Undo Increase Threshold Date")];
}
- (IBAction)decreaseThresholdDateByOneDay:(id)sender {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task decrementThresholdDate:1];
[newTasks addObject:[task copy]];
}
[self refreshTaskListWithSave:YES];
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Decrease Threshold Date", @"Undo Decrease Threshold Date")];
}
- (IBAction)removeThresholdDate:(id)sender {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
NSMutableArray *newTasks = [[NSMutableArray alloc] init];
for (TTMTask *task in [self.arrayController selectedObjects]) {
[task removeThresholdDate];
[newTasks addObject:[task copy]];
}
[self refreshTaskListWithSave:YES];
[[self.undoManager prepareWithInvocationTarget:self] replaceTasks:newTasks withTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Remove Threshold Date", @"Undo Remove Threshold Date")];
}
#pragma mark - Sorting Methods
- (void)sortTaskList:(TTMTaskListSortType)sortType {
// set up sort descriptors for the arrayController
NSSortDescriptor *isPrioritizedDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"isPrioritized"
ascending:NO
selector:@selector(compare:)];
NSSortDescriptor *priorityDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"priority"
ascending:YES
selector:@selector(compare:)];
NSSortDescriptor *hasProjectsDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"hasProjects"
ascending:NO
selector:@selector(compare:)];
NSSortDescriptor *projectDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"projects"
ascending:YES
selector:@selector(localizedCaseInsensitiveCompare:)];
NSSortDescriptor *hasContextsDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"hasContexts"
ascending:NO
selector:@selector(compare:)];
NSSortDescriptor *contextDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"contexts"
ascending:YES
selector:@selector(localizedCaseInsensitiveCompare:)];
NSSortDescriptor *dueStateDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"dueState"
ascending:YES
selector:@selector(compare:)];
NSSortDescriptor *dueDateDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"dueDate"
ascending:YES
selector:@selector(compare:)];
NSSortDescriptor *creationDateDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"creationDate"
ascending:YES
selector:@selector(compare:)];
NSSortDescriptor *completionDateDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"completionDate"
ascending:YES
selector:@selector(compare:)];
NSSortDescriptor *taskIdDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"taskId"
ascending:YES
selector:@selector(compare:)];
NSSortDescriptor *completedDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"isCompleted"
ascending:YES
selector:@selector(compare:)];
NSSortDescriptor *thresholdDateDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"thresholdDate"
ascending:YES
selector:@selector(compare:)];
NSSortDescriptor *alphabeticalDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"rawText"
ascending:YES
selector:@selector(localizedCaseInsensitiveCompare:)];
// apply sort descriptors, depending on sort type, to the arrayController
NSArray *sortDescriptors;
switch (sortType) {
case TTMSortOrderInFile:
sortDescriptors = @[taskIdDescriptor];
break;
case TTMSortPriority:
sortDescriptors = @[isPrioritizedDescriptor, priorityDescriptor, completedDescriptor,
dueStateDescriptor, dueDateDescriptor, thresholdDateDescriptor, taskIdDescriptor];
break;
case TTMSortProject:
sortDescriptors = @[hasProjectsDescriptor, projectDescriptor, priorityDescriptor,
completedDescriptor, dueDateDescriptor, thresholdDateDescriptor, taskIdDescriptor];
break;
case TTMSortContext:
sortDescriptors = @[hasContextsDescriptor, contextDescriptor, isPrioritizedDescriptor,
priorityDescriptor, completedDescriptor, dueDateDescriptor, thresholdDateDescriptor, taskIdDescriptor];
break;
case TTMSortDueDate:
sortDescriptors = @[dueDateDescriptor, isPrioritizedDescriptor, priorityDescriptor,
thresholdDateDescriptor, taskIdDescriptor];
break;
case TTMSortCreationDate:
sortDescriptors = @[creationDateDescriptor, taskIdDescriptor];
break;
case TTMSortCompletionDate:
sortDescriptors = @[completionDateDescriptor, taskIdDescriptor];
break;
case TTMSortThresholdDate:
sortDescriptors = @[thresholdDateDescriptor, isPrioritizedDescriptor, priorityDescriptor, completedDescriptor, dueStateDescriptor, dueDateDescriptor, taskIdDescriptor];
break;
case TTMSortAlphabetical:
sortDescriptors = @[alphabeticalDescriptor];
break;
default:
sortDescriptors = @[taskIdDescriptor];
break;
}
[self.arrayController setSortDescriptors:sortDescriptors];
// Update the active sort type.
self.activeSortType = sortType;
// Change the default sort type.
[[NSUserDefaults standardUserDefaults] setInteger:sortType forKey:@"taskListSortType"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self updateTaskListMetadata];
}
- (IBAction)sortTaskListUsingTagforPreset:(id)sender {
[self sortTaskList:[sender tag]];
}
#pragma mark - Filter Methods
- (NSPredicate*)combineFilterPresetPredicate:(NSPredicate*)filterPresetPredicate
withSearchFilterPredicate:(NSPredicate*)searchFilterPredicate {
if (searchFilterPredicate == nil && filterPresetPredicate == nil) {
return nil;
}
if (searchFilterPredicate == nil && filterPresetPredicate != nil) {
return filterPresetPredicate;
}
if (searchFilterPredicate != nil && filterPresetPredicate == nil) {
return searchFilterPredicate;
}
// if (searchFilterPredicate != nil && filterPresetPredicate != nil)
NSCompoundPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:
@[filterPresetPredicate, searchFilterPredicate]];
return predicate;
}
- (IBAction)filterTaskListUsingTagforPreset:(id)sender {
[self changeActiveFilterPredicateToPreset:[sender tag]];
}
- (void)removeTaskListFilter {
[self changeActiveFilterPredicateToPreset:0];
}
- (void)reapplyActiveFilterPredicate {
[self changeActiveFilterPredicateToPreset:self.activeFilterPredicateNumber];
}
- (void)changeActiveFilterPredicateToPreset:(NSUInteger)presetNumber {
NSPredicate *filterPresetPredicate = [TTMFilterPredicates
getFilterPredicateFromPresetNumber:presetNumber];
self.activeFilterPredicate = [self combineFilterPresetPredicate:filterPresetPredicate
withSearchFilterPredicate:self.searchFieldPredicate];
[TTMFilterPredicates setActiveFilterPredicate:self.activeFilterPredicate];
[TTMFilterPredicates setActiveFilterPredicatePresetNumber:presetNumber];
self.activeFilterPredicateNumber = presetNumber;
[self updateTaskListMetadata];
}
#pragma mark - Archiving Methods
- (IBAction)archiveCompletedTasks:(id)sender {
NSString *archiveFilePath = [[NSUserDefaults standardUserDefaults]
objectForKey:@"archiveFilePath"];
if ([archiveFilePath length] == 0) {
NSAlert *noArchiveFilePrompt = [[NSAlert alloc] init];
noArchiveFilePrompt.messageText = @"No archive file set";
noArchiveFilePrompt.informativeText = @"No archive file is set. Assign an archive file in Preferences and try again.";
[noArchiveFilePrompt addButtonWithTitle:@"Dismiss"];
[noArchiveFilePrompt beginSheetModalForWindow:self.windowForSheet completionHandler:^(NSModalResponse returnCode) {
// do nothing
}];
return;
}
// Collect indexes of all completed tasks, and build string containing all completed tasks.
NSMutableIndexSet *completedTasksIndexSet = [[NSMutableIndexSet alloc] init];
NSMutableString *completedTasksString = [[NSMutableString alloc] init];
NSMutableArray *archivedTasks = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < [[self.arrayController arrangedObjects] count]; i++) {
TTMTask *task = [[self.arrayController arrangedObjects] objectAtIndex:i];
if (task.isCompleted) {
[completedTasksIndexSet addIndex:i];
[completedTasksString appendString:self.preferredLineEnding]; // assumption may be wrong
[completedTasksString appendString:task.rawText];
[archivedTasks addObject:[task copy]];
}
}
// Abort if no completed tasks were found.
if ([completedTasksIndexSet count] == 0) {
return;
}
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"allowUndoOfArchiveCommand"]) {
[self.undoManager setActionName:NSLocalizedString(@"Archive Tasks", @"Undo Archive Tasks")];
[[self.undoManager prepareWithInvocationTarget:self] undoArchiveTasks:archivedTasks
fromArchiveFile:archiveFilePath];
}
@try {
// Append string containing all completed tasks to archive file.
[self appendString:completedTasksString toArchiveFile:archiveFilePath];
// Delete all completed tasks.
[self.arrayController removeObjectsAtArrangedObjectIndexes:completedTasksIndexSet];
// Refresh the tableView and save the file.
[self refreshTaskListWithSave:YES];
}
@catch (NSException *exception) {
NSLog(@"Exception: %@", [exception reason]);
[self refreshTaskListWithSave:NO];
}
}
- (void)appendString:(NSString*)content toArchiveFile:(NSString*)archiveFilePath {
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:archiveFilePath];
if (fileHandle) {
[fileHandle seekToEndOfFile];
[fileHandle writeData:[content dataUsingEncoding:NSUTF8StringEncoding]];
[fileHandle closeFile];
}
else {
[content writeToFile:archiveFilePath
atomically:YES
encoding:NSUTF8StringEncoding
error:nil];
}
}
- (void)removeTasks:(NSArray*)tasksToRemove fromArchiveFile:(NSString*)archiveFilePath {
NSURL *archiveFileURL = [[NSURL alloc] initFileURLWithPath:archiveFilePath];
NSError *err = [[NSError alloc] init];
NSString *fileContents = [[NSString alloc] initWithContentsOfURL:archiveFileURL
encoding:NSUTF8StringEncoding
error:&err];
BOOL usesWindowsLineEndings = ([fileContents rangeOfString:@"\r\n"].location != NSNotFound);
NSString *preferredLineEnding = (usesWindowsLineEndings) ? @"\r\n" : @"\n";
NSMutableArray *rawTextStrings = [[NSMutableArray alloc] initWithArray:[fileContents componentsSeparatedByString:preferredLineEnding]];
for (TTMTask *task in tasksToRemove) {
for (long j = [rawTextStrings count] - 1; j > 0; j--) {
if ([[rawTextStrings objectAtIndex:j] isEqualToString:task.rawText]) {
[rawTextStrings removeObjectAtIndex:j];
break;
}
}
}
[self.undoManager setActionName:NSLocalizedString(@"Remove Tasks From Archive",
@"Undo Remove Tasks From Archive")];
[[self.undoManager prepareWithInvocationTarget:self] archiveCompletedTasks:self];
NSString *content = [rawTextStrings componentsJoinedByString:preferredLineEnding];
[content writeToFile:archiveFilePath
atomically:YES
encoding:NSUTF8StringEncoding
error:nil];
}
#pragma mark - NSDocument Method Overrides
// Override normal copy handler to copy selected tasks from the task list.
// This does not get called when the field editor is active.
- (IBAction)copy:(id)sender {
NSMutableArray *selectedTasksRawText = [[NSMutableArray alloc] init];
NSIndexSet *selectedRowIndexes = [self.arrayController selectionIndexes];
for (NSUInteger i = [selectedRowIndexes firstIndex];
i != NSNotFound;
i = [selectedRowIndexes indexGreaterThanIndex:i]) {
NSString *rawText = [(TTMTask*)[[self.arrayController arrangedObjects]
objectAtIndex:i] rawText];
[selectedTasksRawText addObject:rawText];
}
NSString *clipboardTextString = [selectedTasksRawText componentsJoinedByString:@"\n"];
[[NSPasteboard generalPasteboard] clearContents];
[[NSPasteboard generalPasteboard] setString:clipboardTextString forType:NSStringPboardType];
}
// Override normal cut handler to cut selected tasks from the task list.
// This does not get called when the field editor is active.
- (IBAction)cut:(id)sender {
NSArray *oldTasks = [[NSArray alloc] initWithArray:[self.arrayController selectedObjects]
copyItems:YES];
[[self.undoManager prepareWithInvocationTarget:self] addTasks:oldTasks];
[self.undoManager setActionName:NSLocalizedString(@"Cut", @"Undo Cut")];
[self copy:sender];
[self.arrayController removeObjectsAtArrangedObjectIndexes:[self.tableView selectedRowIndexes]];
[self refreshTaskListWithSave:YES];
}
- (IBAction)paste:(id)sender {
[self.undoManager setActionName:NSLocalizedString(@"Paste", @"Undo Paste")];
[self addNewTasksFromClipboard:self];
}
#pragma mark - Menu Item Validation Methods
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
// Note: Parent menu item tags rather than titles are queried so we don't need to worry about
// internationalization of menu item title strings.
// Check active sort menu item.
if ([menuItem.parentItem tag] == SORTMENUTAG) {
if (menuItem.tag == self.activeSortType) {
[menuItem setState:NSOnState];
} else {
[menuItem setState:NSOffState];
}
}
// Check active filter menu item.
if ([menuItem.parentItem tag] == FILTERMENUTAG) {
if (menuItem.tag == self.activeFilterPredicateNumber) {
[menuItem setState:NSOnState];
} else {
[menuItem setState:NSOffState];
}
}
// Toggle show/hide status bar menu title
if (menuItem.tag == STATUSBARMENUITEMTAG) {
if (self.statusBarVisable) {
[menuItem setTitle:@"Hide Status Bar"];
} else {
[menuItem setTitle:@"Show Status Bar"];
}
}
// Toggle copy task to new task menu item.
if (menuItem.tag == COPYTASKTONEWTASKMENUTAG) {
NSInteger selectedCount = [[self.arrayController selectedObjects] count];
BOOL enabled = (selectedCount == 1);
return enabled;
}
// Toggle task menu items.
if ([menuItem.parentItem tag] == TASKMENUTAG) {
BOOL enabled = (self.tableView.editedRow == -1);
return enabled;
}
return [super validateMenuItem:menuItem];
}
#pragma mark - Find Methods
- (IBAction)moveFocusToSearchBox:(id)sender {
[self.searchField setRefusesFirstResponder:NO];
[self.windowForSheet makeFirstResponder:self.searchField];
// Starting in OS X 10.10 Yosemite, setting refusesFirstResponder to YES without a delay causes
// the search box to not be editable.
[self performSelector:@selector(makeSearchBoxRefuseFocus:) withObject:self afterDelay:0.5];
}
- (IBAction)makeSearchBoxRefuseFocus:(id)sender {
[self.searchField setRefusesFirstResponder:YES];
}
#pragma mark - Tasklist Metadata Methods
- (void)updateTaskListMetadata {
// Update tasklist metadata.
if (!self.tasklistMetadata) {
self.tasklistMetadata = [[TTMTasklistMetadata alloc] init];
}
[self.tasklistMetadata updateMetadataFromTaskArray:self.taskList];
// Update filtered tasklist metadata.
if (!self.filteredTasklistMetadata) {
self.filteredTasklistMetadata = [[TTMTasklistMetadata alloc] init];
}
[self.filteredTasklistMetadata
updateMetadataFromTaskArray:[self.arrayController arrangedObjects]];
// Update status bar text
[self updateStatusBarText];
}
- (IBAction)showTasklistMetadata:(id)sender {
[self updateTaskListMetadata];
// Display tasklist metadata in a modal sheet.
if (!self.tasklistMetadataSheet) {
[[NSBundle mainBundle] loadNibNamed:@"TTMTasklistMetadata" owner:self topLevelObjects:nil];
}
[self.windowForSheet beginSheet:self.tasklistMetadataSheet completionHandler:nil];
}
- (IBAction)hideTasklistMetadata:(id)sender {
[self.windowForSheet endSheet:self.tasklistMetadataSheet];
[self.tasklistMetadataSheet close];
self.tasklistMetadataSheet = nil;
}
#pragma mark - Status Bar Methods
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"selection"]) {
[self updateStatusBarText];
return;
}
if ([keyPath isEqualToString:@"searchFieldPredicate"]) {
[self reapplyActiveFilterPredicate];
return;
}
if ([keyPath isEqualToString:@"levelsOfUndo"]) {
[self.undoManager setLevelsOfUndo:[[NSUserDefaults standardUserDefaults] integerForKey:@"levelsOfUndo"]];
return;
}
if ([keyPath isEqualToString:@"filterPredicate1"]) {
[self visualRefreshIfFilterChangedAtPreset:1];
return;
}
if ([keyPath isEqualToString:@"filterPredicate2"]) {
[self visualRefreshIfFilterChangedAtPreset:2];
return;
}
if ([keyPath isEqualToString:@"filterPredicate3"]) {
[self visualRefreshIfFilterChangedAtPreset:3];
return;
}
if ([keyPath isEqualToString:@"filterPredicate4"]) {
[self visualRefreshIfFilterChangedAtPreset:4];
return;
}
if ([keyPath isEqualToString:@"filterPredicate5"]) {
[self visualRefreshIfFilterChangedAtPreset:5];
return;
}
if ([keyPath isEqualToString:@"filterPredicate6"]) {
[self visualRefreshIfFilterChangedAtPreset:6];
return;
}
if ([keyPath isEqualToString:@"filterPredicate7"]) {
[self visualRefreshIfFilterChangedAtPreset:7];
return;
}
if ([keyPath isEqualToString:@"filterPredicate8"]) {
[self visualRefreshIfFilterChangedAtPreset:8];
return;
}
if ([keyPath isEqualToString:@"filterPredicate9"]) {
[self visualRefreshIfFilterChangedAtPreset:9];
}
}
- (void)visualRefreshIfFilterChangedAtPreset:(int)presentNumber {
if (self.activeFilterPredicateNumber == presentNumber) {
[self visualRefreshOnly:self];
}
}
- (void)updateStatusBarText {
NSString *format = [[NSUserDefaults standardUserDefaults] stringForKey:@"statusBarFormat"];
TTMDocumentStatusBarText *txt = [[TTMDocumentStatusBarText alloc]
initWithTTMDocument:self
format:format];
self.statusBarText = [txt statusBarText];
}
- (BOOL)statusBarVisable {
return ([self.bottomConstraint constant] != 0.0);
}
- (void)setStatusBarVisable:(BOOL)flag {
CGFloat bottomBorderHeight = (flag) ? 22.0 : 0.0;
[self.bottomConstraint setConstant:bottomBorderHeight];
[self.windowForSheet setContentBorderThickness:bottomBorderHeight forEdge:NSMinYEdge];
[self.statusBarTextField setHidden:!flag];
[[NSUserDefaults standardUserDefaults] setBool:flag forKey:@"showStatusBar"];
}
- (IBAction)toggleStatusBarVisability:(id)sender {
[self setStatusBarVisable:!self.statusBarVisable];
}
// MARK - Column resizing methods
- (void)setTableWidthToWidthOfContents {
CGFloat currentWidth = self.tableView.tableColumns.lastObject.width;
CGFloat tableContentWidth = [self tableViewContentWidth];
[self.tableView.tableColumns.lastObject setMinWidth:tableContentWidth];
if (currentWidth > tableContentWidth) {
[self.tableView.tableColumns.lastObject setWidth:tableContentWidth];
}
}
- (CGFloat)tableViewContentWidth {
NSTableView * tableView = self.tableView;
NSRect rect = NSMakeRect(0,0, INFINITY, tableView.rowHeight);
NSInteger columnIndex = 0;
CGFloat maxSize = 0;
for (NSInteger i = 0; i < tableView.numberOfRows; i++) {
NSCell *cell = [tableView preparedCellAtColumn:columnIndex row:i];
NSSize size = [cell cellSizeForBounds:rect];
maxSize = MAX(maxSize, size.width);
}
return maxSize;
}
@end
================================================
FILE: TodoTxtMac/TTMDocumentStatusBarText.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@class TTMDocument;
@interface TTMDocumentStatusBarText : NSObject
extern NSString* const TTMAllStatusBarAllTaskCountTag;
extern NSString* const TTMAllCompletedTaskCount;
extern NSString* const TTMAllIncompleteTaskCount;
extern NSString* const TTMAllDueTodayTaskCount;
extern NSString* const TTMAllOverdueTaskCount;
extern NSString* const TTMAllNotDueTaskCount;
extern NSString* const TTMAllNoDueDateTaskCount;
extern NSString* const TTMAllProjectsCount;
extern NSString* const TTMAllContextsCount;
extern NSString* const TTMAllPrioritiesCount;
extern NSString* const TTMAllActiveFilterNumber;
extern NSString* const TTMAllActiveSortNumber;
extern NSString* const TTMShownStatusBarAllTaskCountTag;
extern NSString* const TTMShownCompletedTaskCount;
extern NSString* const TTMShownIncompleteTaskCount;
extern NSString* const TTMShownDueTodayTaskCount;
extern NSString* const TTMShownOverdueTaskCount;
extern NSString* const TTMShownNotDueTaskCount;
extern NSString* const TTMShownNoDueDateTaskCount;
extern NSString* const TTMShownProjectsCount;
extern NSString* const TTMShownContextsCount;
extern NSString* const TTMShownPrioritiesCount;
extern NSString* const TTMActiveFilterNumber;
extern NSString* const TTMActiveSortNumber;
extern NSString* const TTMActiveSortName;
extern NSString* const TTMSelectedTaskCount;
extern NSString* const TTMHideFutureTasks;
extern NSString* const TTMHideHiddenTasks;
@property (nonatomic, retain) TTMDocument *document;
@property (nonatomic) NSString *format;
#pragma mark - Init Method
/*!
* @method initWithTTMDocument:format:
* @abstract This is the proper init method to call. A source document and format string must
* be passed to this class for proper functionality.
* @param sourceDocument A TTMDocument, which contains metadata from which to build a string.
* @param format A format string, containing plaintext and tags.
*/
- (id)initWithTTMDocument:(TTMDocument*)sourceDocument format:(NSString*)format;
#pragma mark - Metadata Method
/*!
* @method documentMetadata:
* @abstract This is a convenience method that creates a dictionary with tags as keys and
* document metadata values as objects. This dictionary is used in the statusBarText: method.
*/
- (NSDictionary*)documentMetadata;
#pragma mark - Output/Property Methods
/*!
* @method statusBarText:
* @abstract This method produces text for the task list status bar. It builds the output string
* by replacing tags within the format property string with document metadata.
*/
- (NSString*)statusBarText;
/*!
* @method availableTags:
* @abstract This method returns a list of tags available for the user to insert into the status
* bar format string.
*/
+ (NSArray*)availableTags;
/*!
* @method defaultFormat:
* @abstract This method returns the default status bar format string.
*/
+ (NSString*)defaultFormat;
@end
================================================
FILE: TodoTxtMac/TTMDocumentStatusBarText.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMDocumentStatusBarText.h"
#import "TTMDocument.h"
#import "TTMTasklistMetadata.h"
#import "TTMFilterPredicates.h"
@implementation TTMDocumentStatusBarText
NSString* const TTMAllStatusBarAllTaskCountTag = @"{All Tasks}";
NSString* const TTMAllCompletedTaskCount = @"{All Completed}";
NSString* const TTMAllIncompleteTaskCount = @"{All Incomplete}";
NSString* const TTMAllDueTodayTaskCount = @"{All Due Today}";
NSString* const TTMAllOverdueTaskCount = @"{All Overdue}";
NSString* const TTMAllNotDueTaskCount = @"{All Not Due}";
NSString* const TTMAllNoDueDateTaskCount = @"{All No Due Date}";
NSString* const TTMAllProjectsCount = @"{All Projects}";
NSString* const TTMAllContextsCount = @"{All Contexts}";
NSString* const TTMAllPrioritiesCount = @"{All Priorities}";
NSString* const TTMShownStatusBarAllTaskCountTag = @"{Shown Tasks}";
NSString* const TTMShownCompletedTaskCount = @"{Shown Completed}";
NSString* const TTMShownIncompleteTaskCount = @"{Shown Incomplete}";
NSString* const TTMShownDueTodayTaskCount = @"{Shown Due Today}";
NSString* const TTMShownOverdueTaskCount = @"{Shown Overdue}";
NSString* const TTMShownNotDueTaskCount = @"{Shown Not Due}";
NSString* const TTMShownNoDueDateTaskCount = @"{Shown No Due Date}";
NSString* const TTMShownProjectsCount = @"{Shown Projects}";
NSString* const TTMShownContextsCount = @"{Shown Contexts}";
NSString* const TTMShownPrioritiesCount = @"{Shown Priorities}";
NSString* const TTMActiveFilterNumber = @"{Filter Preset}";
NSString* const TTMActiveSortNumber = @"{Sort Preset}";
NSString* const TTMActiveSortName = @"{Sort Name}";
NSString* const TTMSelectedTaskCount = @"{Selected}";
NSString* const TTMHideFutureTasks = @"{Hide Future Tasks}";
NSString* const TTMHideHiddenTasks = @"{Hide Hidden Tasks}";
#pragma mark - Init Method
- (id)initWithTTMDocument:(TTMDocument*)sourceDocument format:(NSString*)format {
self = [super init];
if (self) {
_document = sourceDocument;
_format = format;
}
return self;
}
#pragma mark - Metadata Method
- (NSDictionary*)documentMetadata {
NSDictionary *sortNames = @{@(TTMSortOrderInFile) : @"File",
@(TTMSortPriority) : @"Priority",
@(TTMSortProject) : @"Project",
@(TTMSortContext) : @"Context",
@(TTMSortDueDate) : @"Due Date",
@(TTMSortCreationDate) : @"Creation Date",
@(TTMSortCompletionDate) : @"Completion Date",
@(TTMSortThresholdDate) : @"Threshold Date",
@(TTMSortAlphabetical) : @"Alphabetical"
};
return @{TTMAllStatusBarAllTaskCountTag : @(self.document.tasklistMetadata.allTaskCount),
TTMAllCompletedTaskCount : @(self.document.tasklistMetadata.completedTaskCount),
TTMAllIncompleteTaskCount : @(self.document.tasklistMetadata.incompleteTaskCount),
TTMAllDueTodayTaskCount : @(self.document.tasklistMetadata.dueTodayTaskCount),
TTMAllOverdueTaskCount : @(self.document.tasklistMetadata.overdueTaskCount),
TTMAllNotDueTaskCount : @(self.document.tasklistMetadata.notDueTaskCount),
TTMAllNoDueDateTaskCount : @(self.document.tasklistMetadata.noDueDateTaskCount),
TTMAllPrioritiesCount : @(self.document.tasklistMetadata.projectsCount),
TTMAllProjectsCount : @(self.document.tasklistMetadata.projectsCount),
TTMAllContextsCount : @(self.document.tasklistMetadata.contextsCount),
TTMShownStatusBarAllTaskCountTag : @(self.document.filteredTasklistMetadata.allTaskCount),
TTMShownCompletedTaskCount : @(self.document.filteredTasklistMetadata.completedTaskCount),
TTMShownIncompleteTaskCount : @(self.document.filteredTasklistMetadata.incompleteTaskCount),
TTMShownDueTodayTaskCount : @(self.document.filteredTasklistMetadata.dueTodayTaskCount),
TTMShownOverdueTaskCount : @(self.document.filteredTasklistMetadata.overdueTaskCount),
TTMShownNotDueTaskCount : @(self.document.filteredTasklistMetadata.notDueTaskCount),
TTMShownNoDueDateTaskCount : @(self.document.filteredTasklistMetadata.noDueDateTaskCount),
TTMShownPrioritiesCount : @(self.document.filteredTasklistMetadata.projectsCount),
TTMShownProjectsCount : @(self.document.filteredTasklistMetadata.projectsCount),
TTMShownContextsCount : @(self.document.filteredTasklistMetadata.contextsCount),
TTMActiveFilterNumber : @(self.document.activeFilterPredicateNumber),
TTMActiveSortNumber : @(self.document.activeSortType),
TTMActiveSortName : [sortNames objectForKey:@(self.document.activeSortType)],
TTMSelectedTaskCount : @(self.document.arrayController.selectionIndexes.count),
TTMHideFutureTasks : [self hideFutureTasks],
TTMHideHiddenTasks : [self hideHiddenTasks]
};
}
- (NSString*)hideFutureTasks {
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"hideFutureTasks"]) {
return NSLocalizedString(@"Yes", "");
} else {
return NSLocalizedString(@"No", "");
}
}
- (NSString*)hideHiddenTasks {
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"hideHiddenTasks"]) {
return NSLocalizedString(@"Yes", "");
} else {
return NSLocalizedString(@"No", "");
}
}
#pragma mark - Output/Property Methods
- (NSString*)statusBarText {
NSMutableString *text = [self.format mutableCopy];
NSDictionary *dict = [self documentMetadata];
for (NSString *key in dict) {
[text replaceOccurrencesOfString:key
withString:[NSString stringWithFormat:@"%@",
[dict objectForKey:key]]
options:NSCaseInsensitiveSearch
range:NSMakeRange(0, text.length)];
}
return text;
}
+ (NSArray*)availableTags {
return @[TTMAllStatusBarAllTaskCountTag,
TTMAllCompletedTaskCount,
TTMAllIncompleteTaskCount,
TTMAllDueTodayTaskCount,
TTMAllOverdueTaskCount,
TTMAllNotDueTaskCount,
TTMAllNoDueDateTaskCount,
TTMAllPrioritiesCount,
TTMAllProjectsCount,
TTMAllContextsCount,
TTMShownStatusBarAllTaskCountTag,
TTMShownCompletedTaskCount,
TTMShownIncompleteTaskCount,
TTMShownDueTodayTaskCount,
TTMShownOverdueTaskCount,
TTMShownNotDueTaskCount,
TTMShownNoDueDateTaskCount,
TTMShownPrioritiesCount,
TTMShownProjectsCount,
TTMShownContextsCount,
TTMActiveFilterNumber,
TTMActiveSortNumber,
TTMActiveSortName,
TTMSelectedTaskCount,
TTMHideFutureTasks,
TTMHideHiddenTasks
];
}
+ (NSString*)defaultFormat {
return @"Filter #: {Filter Preset} | Sort: {Sort Name} | Tasks: {Shown Tasks} of {All Tasks} | Incomplete: {Shown Incomplete} | Due Today: {Shown Due Today} | Overdue: {Shown Overdue} | Hide Future Tasks: {Hide Future Tasks}";
}
@end
================================================
FILE: TodoTxtMac/TTMFieldEditor.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@interface TTMFieldEditor : NSTextView
#pragma mark - Properties
@property (nonatomic, retain) NSArray *projectsArray;
@property (nonatomic, retain) NSArray *contextsArray;
@property (nonatomic, retain) NSTimer *completionTimer;
@property (nonatomic) NSUInteger nextInsertionIndex;
@property (nonatomic) NSString *originalValue;
#pragma mark - Autocompletion Timer Methods
/*!
* @method startCompletionTimer:
* @abstract This method starts the timer for autocompletion of projects and contexts.
*/
- (void)startCompletionTimer;
/*!
* @method stopCompletionTimer:
* @abstract This method stops the timer for autocompletion of projects and contexts.
*/
- (void)stopCompletionTimer;
/*!
* @method doCompletion:
* @param The time to process the completion event for.
* @abstract This method is fired when the timer for autocompletion fires its selector, and
* kicks off autocompletion.
*/
- (void)doCompletion:(NSTimer*)timer;
@end
================================================
FILE: TodoTxtMac/TTMFieldEditor.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMFieldEditor.h"
#define COMPLETION_DELAY (0.25)
@implementation TTMFieldEditor
#pragma mark - Init Methods
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (BOOL)becomeFirstResponder {
self.originalValue = [self.string copy]; // retain value for cancelOperation method
return ([super becomeFirstResponder]);
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
// Drawing code here.
}
#pragma mark - Autocompletion Timer Methods
- (void)startCompletionTimer {
[self stopCompletionTimer]; // cancel any timers running already
self.completionTimer = [NSTimer scheduledTimerWithTimeInterval:COMPLETION_DELAY
target:self
selector:@selector(doCompletion:)
userInfo:nil
repeats:NO];
}
- (void)stopCompletionTimer {
[self.completionTimer invalidate];
self.completionTimer = nil;
}
- (void)doCompletion:(NSTimer*)timer {
[self complete:nil];
[self stopCompletionTimer];
}
#pragma mark - Autocompletion Event Handler Methods
/*!
* @method keyUp:
* @abstract This method fires after the user types a character.
* @discussion It is necessary to override this method to handle autocompletion of contexts and
* projects, which start with "@" and "+" respectively. Autocompletion is handled by a timer,
* which means that the user has to pause a split second to see the autocompletion list. If the
* user does not pause, the autocompeltion menu does not display. This implementation was
* selected so the program does not interrupt the user when typing math (with "+") or email
* addresses (with "@").
*/
- (void)keyUp:(NSEvent*)event {
// Start the completion timer if the range for user completion starts with "@" or "+".
NSString *partialRange = [[self string] substringWithRange:self.rangeForUserCompletion];
if ([partialRange hasPrefix:@"@"] || [partialRange hasPrefix:@"+"]) {
// Don't trigger autocompletion time if user is pressing a deletion key or pressing Enter
unichar keyChar = [self keyCharFromEvent:event];
if (![self keyCharIsADeletionKey:keyChar] && ![self keyCharIsEnterKey:keyChar]) {
[self startCompletionTimer];
}
}
// Call the super so we don't override any other behaviors.
[super keyUp:event];
}
- (BOOL)keyCharIsADeletionKey:(unichar)keyChar {
return (keyChar == NSBackspaceCharacter || keyChar == NSDeleteCharacter);
}
- (BOOL)keyCharIsEnterKey:(unichar)keyChar {
return (keyChar == NSEnterCharacter || keyChar == '\r');
}
- (unichar)keyCharFromEvent:(NSEvent*)event {
NSString *passedChar = [event charactersIgnoringModifiers];
unichar keyChar = [passedChar characterAtIndex:0];
return keyChar;
}
/*!
* @method completionsForPartialWordRange:indexOfSelectedItem:
* @abstract This method returns autocompletion suggestions based on the range it receives.
* @discussion It is necessary to override this method to handle autocompletion of contexts and
* projects, which start with "@" and "+" respectively.
*/
- (NSArray*)completionsForPartialWordRange:(NSRange)charRange
indexOfSelectedItem:(NSInteger*)index {
// Check the character range for "@" and "+".
NSString *partialString = [[self string] substringWithRange:charRange];
if ([partialString hasPrefix:@"+"]) {
return [self partialCompletionsFromSourceArray:self.projectsArray partialString:partialString];
} else if ([partialString hasPrefix:@"@"]) {
return [self partialCompletionsFromSourceArray:self.contextsArray partialString:partialString];
} else {
// Call the super method to get the default behavior.
// This allows for the user to type Esc and still trigger autocompletion.
return [super completionsForPartialWordRange:charRange indexOfSelectedItem:index];
}
}
- (NSArray*)partialCompletionsFromSourceArray:(NSArray*)sourceArray
partialString:(NSString*)partialString{
if (sourceArray == nil) {
return nil;
}
NSMutableArray *returnArray = [[NSMutableArray alloc] init];
for (NSString *str in sourceArray) {
if ([[str uppercaseString] hasPrefix:[partialString uppercaseString]]) {
[returnArray addObject:str];
}
}
return returnArray;
}
/*!
* @method rangeForUserCompletion:
* @abstract This method returns the range to be replaced by autocompletion.
* @discussion It is necessary to override this method to handle autocompletion of contexts,
* which begin with the @ (at) sign. The super's rangeForUserCompletion: method does not
* consider that an @ sign could start a word, so it returns the word and space before the @
* sign. When the complete: method fires, the prior word and space are deleted, which is not
* what is desired.
*/
- (NSRange)rangeForUserCompletion {
// Call the super method to get the default behavior.
NSRange superRange = [super rangeForUserCompletion];
// For some reason, when triggering autocompletion of contexts, which begin with "@",
// the superRange has a length of 0, which prevents autocompletion from working.
// This conditional code block, which adjusts the range, fixes that.
if (superRange.length == 0 && superRange.location > 0) {
superRange.location -= 1;
superRange.length = 1;
}
// Look 1 character back from the superRange.
// If it is a "@" or "+", extend the superRange back to include that character.
// This is necessary for autocompletion to work properly for contexts and projects.
NSString *leadingCharacter = [self leadingCharacterToLeftOfRange:superRange];
if ([leadingCharacter isEqualToString:@"@"] || [leadingCharacter isEqualToString:@"+"]) {
if (superRange.location > 0) {
superRange.location -= 1;
superRange.length += 1;
}
}
return superRange;
}
- (NSString*)leadingCharacterToLeftOfRange:(NSRange)range {
if (range.location == 0) {
return [[self string] substringWithRange:range];
}
NSRange newRange = NSMakeRange(range.location - 1, 1);
return [[self string] substringWithRange:newRange];
}
- (NSString*)stringForRangeWithAdditionalLeadingCharacter:(NSRange)range {
if (range.location == 0) {
return [[self string] substringWithRange:range];
}
NSRange newRange = NSMakeRange(range.location - 1, range.length + 1);
return [[self string] substringWithRange:newRange];
}
/*!
* @method: cancelOperation:
* @abstract This method undoes all changes of the text field being edited when the user hits Esc,
* if the user has opted for that setting.
* @discussion This method also triggers autocompletion, again dependent on the user setting.
*/
- (void)cancelOperation:(id)sender {
// How the Esc key behaves is dependent on a user setting.
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"escapeKeyCancelsAllTextChanges"]) {
[self.undoManager removeAllActions];
self.string = self.originalValue;
} else {
// Trigger autocompletion (default behavior).
[self complete:nil];
}
}
@end
================================================
FILE: TodoTxtMac/TTMFilterPredicates.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@interface TTMFilterPredicates : NSObject
#pragma mark - Default Filter Predicate Methods
/*!
* @method defaultFilterPredicate:
* @abstract This method returns a default (blank) filter predicate for use with TTMDocument.
*/
+ (NSPredicate*)defaultFilterPredicate;
/*!
* @method defaultFilterPredicateData:
* @abstract This method returns a default (blank) filter predicate in the form of an NSData
* object, from defaultFitlerPredicate:, for use in user defaults.
*/
+ (NSData*)defaultFilterPredicateData;
/*!
* @method hideFutureTasksFilterSubPredicate:
* @abstract This method returns a filter predicate for use with the "hide future tasks" option.
*/
+ (NSPredicate*)hideFutureTasksFilterSubPredicate;
/*!
* @method hideHiddenTasksFilterSubPredicate:
* @abstract This method returns a filter predicate for use with the "hide hidden tasks" option.
*/
+ (NSPredicate*)hideHiddenTasksFilterSubPredicate;
/*!
* @method noFilterPredicate:
* @abstract This method returns a filter predicate for use when the filter is disabled.
*/
+ (NSPredicate*)noFilterPredicate;
#pragma mark - Set Filter Predicate Methods
/*!
* @method setFilterPredicate:toUserDefaultsKey:
* @abstract This method sets a filter predicate value to the user defaults.
* @param predicate The predicate to set to user defaults.
* @param key The user defaults key to set the predicate to.
*/
+ (void)setFilterPredicate:(NSPredicate*)predicate toUserDefaultsKey:(NSString*)key;
/*!
* @method setFilterPredicate:toPresetNumber:
* @abstract This method sets a filter predicate value to the user defaults.
* @param predicate The predicate to set to user defaults.
* @param presetNumber The (user-facing) preset number to set the predicate to.
*/
+ (void)setFilterPredicate:(NSPredicate*)predicate toPresetNumber:(NSUInteger)presetNumber;
/*!
* @method setActiveFilterPredicate:
* @abstract This method sets the active filter predicate in user defaults.
* @param predicate The predicate to set as the active filter predicate in user defaults.
*/
+ (void)setActiveFilterPredicate:(NSPredicate*)predicate;
#pragma mark - Get Filter Predicate Methods
/*!
* @method getFilterPredicateFromUserDefaultsKey:
* @abstract This method gets a filter predicate value from the user defaults.
* @param key The user defaults key to get the predicate from.
*/
+ (NSPredicate*)getFilterPredicateFromUserDefaultsKey:(NSString*)key;
/*!
* @method getFilterPredicateFromPresetNumber:
* @abstract This method gets a filter predicate value from the user defaults.
* @param presetNumber The (user-facing) preset number to get the predicate for.
*/
+ (NSPredicate*)getFilterPredicateFromPresetNumber:(NSUInteger)presetNumber;
/*!
* @method keyFromPresetNumber:
* @abstract This method returns the user defaults key name for a given preset number.
* @param presetNumber The (user-facing) preset number to get the key name for.
*/
+ (NSString*)keyFromPresetNumber:(NSUInteger)presetNumber;
/*!
* @method activeFilterPredicate:
* @abstract This method returns the active filter predicate from user defaults.
* @param presetNumber The (user-facing) preset number to get the key name for.
*/
+ (NSPredicate*)activeFilterPredicate;
/*!
* @method setActiveFilterPredicatePresetNumber:
* @abstract This method sets the active filter predicate to user defaults.
* @param presetNumber The (user-facing) preset number to set the default to.
*/
+ (void)setActiveFilterPredicatePresetNumber:(NSUInteger)presetNumber;
/*!
* @method activeFilterPredicatePresetNumber:
* @abstract This method gets the active filter preset number from user defaults.
*/
+ (NSUInteger)activeFilterPredicatePresetNumber;
#pragma mark - Reset Filter Predicate Methods
/*!
* @method resetAllFilterPredicates:
* @abstract This method clears/resets a single filter preset to the default filter predicate
* returned by defaultFilterPredicate:.
*/
+ (void)resetFilterPredicate:(NSUInteger)presetNumber;
/*!
* @method resetAllFilterPredicates:
* @abstract This method clears/resets all filters to the default filter predicate
* returned by defaultFilterPredicate:.
*/
+ (void)resetAllFilterPredicates;
@end
================================================
FILE: TodoTxtMac/TTMFilterPredicates.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMFilterPredicates.h"
#import "TTMTask.h"
@implementation TTMFilterPredicates
- (id)init
{
self = [super init];
if (self) {
// do nothing
}
return self;
}
#pragma mark - Default Filter Predicate Methods
+ (NSPredicate*)defaultFilterPredicate {
static NSPredicate *defaultPredicate = nil;
if (defaultPredicate == nil) {
NSPredicate *defaultSubPredicate = [NSPredicate predicateWithFormat:@"rawText contains ''"];
NSArray *subPredicates = @[defaultSubPredicate];
defaultPredicate = [NSCompoundPredicate
andPredicateWithSubpredicates:subPredicates];
}
return defaultPredicate;
}
+ (NSData*)defaultFilterPredicateData {
static NSData *defaultPredicateData = nil;
if (defaultPredicateData == nil) {
defaultPredicateData = [NSKeyedArchiver
archivedDataWithRootObject:[self defaultFilterPredicate]];
}
return defaultPredicateData;
}
+ (NSPredicate*)noFilterPredicate {
return [self filterPredicateWithHideOptions];
}
+ (BOOL)hideFutureTasks {
return [[NSUserDefaults standardUserDefaults] boolForKey:@"hideFutureTasks"];
}
+ (BOOL)hideHiddenTasks {
return [[NSUserDefaults standardUserDefaults] boolForKey:@"hideHiddenTasks"];
}
+ (NSPredicate*)filterPredicateWithHideOptions {
NSMutableArray *subPredicates = [[NSMutableArray alloc] init];
if ([self hideFutureTasks]) {
[subPredicates addObject:[self hideFutureTasksFilterSubPredicate]];
}
if ([self hideHiddenTasks]) {
[subPredicates addObject:[self hideHiddenTasksFilterSubPredicate]];
}
return [NSCompoundPredicate andPredicateWithSubpredicates:subPredicates];
}
+ (NSPredicate*)hideFutureTasksFilterSubPredicate {
return [NSPredicate predicateWithFormat:@"thresholdState != %d", (int)ThresholdAfterToday];
}
+ (NSPredicate*)hideHiddenTasksFilterSubPredicate {
return [NSPredicate predicateWithFormat:@"isHidden == 0"];
}
#pragma mark - Set Filter Predicate Methods
+ (void)setFilterPredicate:(NSPredicate*)predicate toUserDefaultsKey:(NSString*)key {
NSData *filterPredicateData = [NSKeyedArchiver archivedDataWithRootObject:predicate];
[[NSUserDefaults standardUserDefaults] setObject:filterPredicateData forKey:key];
}
+ (void)setFilterPredicate:(NSPredicate*)predicate toPresetNumber:(NSUInteger)presetNumber {
[self setFilterPredicate:predicate toUserDefaultsKey:[self keyFromPresetNumber:presetNumber]];
}
+ (void)setActiveFilterPredicate:(NSPredicate*)predicate {
[self setFilterPredicate:predicate toUserDefaultsKey:@"activeFilterPredicate"];
}
#pragma mark - Get Filter Predicate Methods
+ (NSPredicate*)getFilterPredicateFromUserDefaultsKey:(NSString*)key {
NSData *filterPredicateData = [[NSUserDefaults standardUserDefaults] objectForKey:key];
return [NSKeyedUnarchiver unarchiveObjectWithData:filterPredicateData];
}
+ (NSPredicate*)getFilterPredicateFromPresetNumber:(NSUInteger)presetNumber {
if (presetNumber < 1 || presetNumber > 9) {
return [self noFilterPredicate];
}
NSPredicate *defaultPredicate = [self filterPredicateWithHideOptions];
NSPredicate *filterPresetSubPredicate = [self getFilterPredicateFromUserDefaultsKey:[self keyFromPresetNumber:presetNumber]];
if ([self hideFutureTasks] || [self hideHiddenTasks]) {
NSArray *subPredicates = @[defaultPredicate, filterPresetSubPredicate];
return [NSCompoundPredicate andPredicateWithSubpredicates:subPredicates];
} else {
return filterPresetSubPredicate;
}
}
+ (NSString*)keyFromPresetNumber:(NSUInteger)presetNumber {
if (presetNumber > 9) {
return nil;
}
return [NSString stringWithFormat:@"filterPredicate%lu", (unsigned long)presetNumber];
}
+ (NSPredicate*)activeFilterPredicate {
return [self getFilterPredicateFromPresetNumber:[self activeFilterPredicatePresetNumber]];
}
+ (void)setActiveFilterPredicatePresetNumber:(NSUInteger)presetNumber {
[[NSUserDefaults standardUserDefaults] setObject:@(presetNumber) forKey:@"activeFilterPreset"];
}
+ (NSUInteger)activeFilterPredicatePresetNumber {
return [[NSUserDefaults standardUserDefaults] integerForKey:@"activeFilterPreset"];
}
#pragma mark - Reset Filter Predicate Methods
+ (void)resetFilterPredicate:(NSUInteger)presetNumber {
[self setFilterPredicate:[self defaultFilterPredicate] toPresetNumber:presetNumber];
}
+ (void)resetAllFilterPredicates {
for (int i = 1; i <= 9; i++) {
[self resetFilterPredicate:i];
}
}
@end
================================================
FILE: TodoTxtMac/TTMFilters.xib
================================================
rawText
projects
contexts
priorityText
dueDate
completionDate
creationDate
thresholdDate
completed
dueState
thresholdState
isHidden
NSKeyedUnarchiveFromData
rawText
projects
contexts
priorityText
dueDate
completionDate
creationDate
thresholdDate
completed
dueState
thresholdState
isHidden
NSKeyedUnarchiveFromData
rawText
projects
contexts
priorityText
dueDate
completionDate
creationDate
thresholdDate
completed
dueState
thresholdState
isHidden
NSKeyedUnarchiveFromData
rawText
projects
contexts
priorityText
dueDate
completionDate
creationDate
thresholdDate
completed
dueState
thresholdState
isHidden
NSKeyedUnarchiveFromData
rawText
projects
contexts
priorityText
dueDate
completionDate
creationDate
thresholdDate
completed
dueState
thresholdState
isHidden
NSKeyedUnarchiveFromData
rawText
projects
contexts
priorityText
dueDate
completionDate
creationDate
thresholdDate
completed
dueState
thresholdState
isHidden
NSKeyedUnarchiveFromData
rawText
projects
contexts
priorityText
dueDate
completionDate
creationDate
thresholdDate
completed
dueState
thresholdState
isHidden
NSKeyedUnarchiveFromData
rawText
projects
contexts
priorityText
dueDate
completionDate
creationDate
thresholdDate
completed
dueState
thresholdState
isHidden
NSKeyedUnarchiveFromData
rawText
projects
contexts
priorityText
dueDate
completionDate
creationDate
thresholdDate
completed
dueState
thresholdState
isHidden
NSKeyedUnarchiveFromData
================================================
FILE: TodoTxtMac/TTMFiltersController.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@class TTMAppController;
@interface TTMFiltersController : NSWindowController
@property (nonatomic, retain) IBOutlet NSTabView *tabView;
@property (nonatomic, retain) IBOutlet NSPredicateEditor *filter1PredicateEditor;
@property (nonatomic, retain) IBOutlet NSPredicateEditor *filter2PredicateEditor;
@property (nonatomic, retain) IBOutlet NSPredicateEditor *filter3PredicateEditor;
@property (nonatomic, retain) IBOutlet NSPredicateEditor *filter4PredicateEditor;
@property (nonatomic, retain) IBOutlet NSPredicateEditor *filter5PredicateEditor;
@property (nonatomic, retain) IBOutlet NSPredicateEditor *filter6PredicateEditor;
@property (nonatomic, retain) IBOutlet NSPredicateEditor *filter7PredicateEditor;
@property (nonatomic, retain) IBOutlet NSPredicateEditor *filter8PredicateEditor;
@property (nonatomic, retain) IBOutlet NSPredicateEditor *filter9PredicateEditor;
/*!
* @method resetAllFilters:
* @abstract This method allows the user to clear/reset all filters.
*/
- (IBAction)resetAllFilters:(id)sender;
@end
================================================
FILE: TodoTxtMac/TTMFiltersController.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMFiltersController.h"
#import "TTMFilterPredicates.h"
@implementation TTMFiltersController
- (id)initWithWindow:(NSWindow *)window {
self = [super initWithWindow:window];
if (self) {
// Initialization code here.
}
return self;
}
- (IBAction)resetAllFilters:(id)sender {
NSAlert *resetPrompt = [[NSAlert alloc] init];
resetPrompt.messageText = @"Clear all filters";
resetPrompt.informativeText = @"Are you sure you want to do this? You will lose all filter customizations.";
[resetPrompt addButtonWithTitle:@"OK"];
[resetPrompt addButtonWithTitle:@"Cancel"];
[resetPrompt beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) {
if (returnCode == NSAlertFirstButtonReturn) {
[TTMFilterPredicates resetAllFilterPredicates];
// Reload all the filter predicate editors because
// the one with focus at the time this method is executed
// will not be cleared. This is only really necessary to
// call on the predicate editor with focus.
[self reloadAllPredicateEditors];
}
}];
}
- (void)reloadAllPredicateEditors {
[self.filter1PredicateEditor reloadCriteria];
[self.filter2PredicateEditor reloadCriteria];
[self.filter3PredicateEditor reloadCriteria];
[self.filter4PredicateEditor reloadCriteria];
[self.filter5PredicateEditor reloadCriteria];
[self.filter6PredicateEditor reloadCriteria];
[self.filter7PredicateEditor reloadCriteria];
[self.filter8PredicateEditor reloadCriteria];
[self.filter9PredicateEditor reloadCriteria];
}
#pragma mark - Window Delegate Methods
- (void)keyDown:(NSEvent *)theEvent {
NSUInteger flags = [theEvent modifierFlags];
NSString *passedChar = [theEvent charactersIgnoringModifiers];
if ((flags & NSCommandKeyMask) &&
(flags & NSShiftKeyMask) &&
([passedChar isEqualToString:@"{"])) {
[self.tabView selectPreviousTabViewItem:self];
return;
}
if ((flags & NSCommandKeyMask) &&
(flags & NSShiftKeyMask) &&
([passedChar isEqualToString:@"}"])) {
[self.tabView selectNextTabViewItem:self];
return;
}
[super keyDown:theEvent];
}
- (void)windowDidResignKey:(NSNotification *)notification {
[self forceFilterPredicateEditsToBeApplied];
}
- (void)forceFilterPredicateEditsToBeApplied {
if ([self.window.firstResponder isKindOfClass:[NSTextView class]]) {
[self.window.firstResponder insertNewline:self];
}
}
@end
================================================
FILE: TodoTxtMac/TTMFindReplace.xib
================================================
================================================
FILE: TodoTxtMac/TTMPredicateEditorCompletedRowTemplate.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@interface TTMPredicateEditorCompletedRowTemplate : NSPredicateEditorRowTemplate
@property (nonatomic, retain) NSPopUpButton *keypathPopUp;
@property (nonatomic, retain) NSPopUpButton *boolPopUp;
@end
================================================
FILE: TodoTxtMac/TTMPredicateEditorCompletedRowTemplate.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMPredicateEditorCompletedRowTemplate.h"
@implementation TTMPredicateEditorCompletedRowTemplate
#pragma mark - Class Property Getters
- (NSPopUpButton*)keypathPopUp {
if(!_keypathPopUp) {
NSMenu *keypathMenu = [[NSMenu alloc]
initWithTitle:@"completed menu"];
NSMenuItem *menuItem = [[NSMenuItem alloc]
initWithTitle:@"completed"
action:nil
keyEquivalent:@""];
[menuItem setRepresentedObject:[NSExpression expressionForKeyPath:@"completed"]];
[menuItem setEnabled:YES];
NSMenuItem *menuItem2 = [[NSMenuItem alloc]
initWithTitle:@"hidden"
action:nil
keyEquivalent:@""];
[menuItem2 setRepresentedObject:[NSExpression expressionForKeyPath:@"isHidden"]];
[menuItem2 setEnabled:YES];
[keypathMenu addItem:menuItem];
[keypathMenu addItem:menuItem2];
_keypathPopUp = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
[_keypathPopUp setMenu:keypathMenu];
}
return _keypathPopUp;
}
- (NSPopUpButton*)boolPopUp {
if (!_boolPopUp) {
NSMenuItem *yesItem = [[NSMenuItem alloc] initWithTitle:@"Yes" action:nil keyEquivalent:@""];
[yesItem setRepresentedObject:[NSExpression expressionForConstantValue:@YES]];
[yesItem setEnabled:YES];
[yesItem setTag:1];
NSMenuItem *noItem = [[NSMenuItem alloc] initWithTitle:@"No" action:nil keyEquivalent:@""];
[noItem setRepresentedObject:[NSExpression expressionForConstantValue:@NO]];
[noItem setEnabled:YES];
[noItem setTag:0];
NSMenu *boolMenu = [[NSMenu alloc] initWithTitle:@"Yes/No"];
[boolMenu addItem:yesItem];
[boolMenu addItem:noItem];
_boolPopUp = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
[_boolPopUp setMenu:boolMenu];
}
return _boolPopUp;
}
#pragma mark - NSPredicateEditorRowTemplate Method Overrides
- (NSArray*)templateViews {
NSMutableArray *newTemplateViews = [[super templateViews] mutableCopy];
[newTemplateViews replaceObjectAtIndex:0 withObject:self.keypathPopUp];
[newTemplateViews replaceObjectAtIndex:2 withObject:self.boolPopUp];
return newTemplateViews;
}
- (void)setPredicate:(NSPredicate*)predicate {
id rightValue = [[(NSComparisonPredicate*)predicate rightExpression] constantValue];
if ([rightValue isKindOfClass:[NSNumber class]]) {
[self.boolPopUp selectItemWithTag:[rightValue integerValue]];
}
}
- (NSPredicate*)predicateWithSubpredicates:(NSArray*)subpredicates {
NSPredicate *newPredicate =
[NSComparisonPredicate
predicateWithLeftExpression:[[self.keypathPopUp selectedItem] representedObject]
rightExpression:[[self.boolPopUp selectedItem] representedObject]
modifier:NSDirectPredicateModifier
type:NSEqualToPredicateOperatorType
options:0];
return newPredicate;
}
@end
================================================
FILE: TodoTxtMac/TTMPredicateEditorDateRowTemplate.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@interface TTMPredicateEditorDateRowTemplate : NSPredicateEditorRowTemplate
@end
================================================
FILE: TodoTxtMac/TTMPredicateEditorDateRowTemplate.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMPredicateEditorDateRowTemplate.h"
#import "TTMDateUtility.h"
@implementation TTMPredicateEditorDateRowTemplate
- (NSPredicate*)predicateWithSubpredicates:(NSArray *)subpredicates {
NSPredicate *p = [super predicateWithSubpredicates:subpredicates];
if ([p isKindOfClass:[NSComparisonPredicate class]]) {
// Get the date value from the "right" comparison property.
NSComparisonPredicate *comparison = (NSComparisonPredicate*)p;
NSExpression *right = [comparison rightExpression];
NSDate *dateValue = [right constantValue];
// Set the "right" comparison property to its date value stripped of its time part
// (that is, as of 00:00:00).
NSDate *dateWithoutTime = [TTMDateUtility dateWithoutTime:dateValue];
right = [NSExpression expressionForConstantValue:dateWithoutTime];
p = [NSComparisonPredicate
predicateWithLeftExpression:[comparison leftExpression]
rightExpression:right
modifier:[comparison comparisonPredicateModifier]
type:[comparison predicateOperatorType]
options:[comparison options]];
}
return p;
}
@end
================================================
FILE: TodoTxtMac/TTMPredicateEditorDueRowTemplate.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@interface TTMPredicateEditorDueRowTemplate : NSPredicateEditorRowTemplate
@property (nonatomic, retain) NSPopUpButton *keypathPopUp;
@property (nonatomic, retain) NSPopUpButton *dueStatePopUp;
@end
================================================
FILE: TodoTxtMac/TTMPredicateEditorDueRowTemplate.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMPredicateEditorDueRowTemplate.h"
#import "TTMTask.h"
@implementation TTMPredicateEditorDueRowTemplate
#pragma mark - Class Property Getters
- (NSPopUpButton*)keypathPopUp {
if(!_keypathPopUp) {
NSMenu *keypathMenu = [[NSMenu alloc]
initWithTitle:@"due state menu"];
NSMenuItem *menuItem = [[NSMenuItem alloc]
initWithTitle:@"due state"
action:nil
keyEquivalent:@""];
[menuItem setRepresentedObject:[NSExpression expressionForKeyPath:@"dueState"]];
[menuItem setEnabled:YES];
[keypathMenu addItem:menuItem];
_keypathPopUp = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
[_keypathPopUp setMenu:keypathMenu];
}
return _keypathPopUp;
}
- (NSPopUpButton*)dueStatePopUp {
if (!_dueStatePopUp) {
NSMenuItem *dueTodayItem = [[NSMenuItem alloc] initWithTitle:@"due today"
action:nil
keyEquivalent:@""];
[dueTodayItem setRepresentedObject:[NSExpression expressionForConstantValue:@(DueToday)]];
[dueTodayItem setEnabled:YES];
[dueTodayItem setTag:(long)DueToday];
NSMenuItem *overdueItem = [[NSMenuItem alloc] initWithTitle:@"overdue"
action:nil
keyEquivalent:@""];
[overdueItem setRepresentedObject:[NSExpression expressionForConstantValue:@(Overdue)]];
[overdueItem setEnabled:YES];
[overdueItem setTag:(long)Overdue];
NSMenuItem *notDueItem = [[NSMenuItem alloc] initWithTitle:@"not due"
action:nil
keyEquivalent:@""];
[notDueItem setRepresentedObject:[NSExpression expressionForConstantValue:@(NotDue)]];
[notDueItem setEnabled:YES];
[notDueItem setTag:(long)NotDue];
NSMenuItem *noDueDateItem = [[NSMenuItem alloc] initWithTitle:@"no due date"
action:nil
keyEquivalent:@""];
[noDueDateItem setRepresentedObject:[NSExpression expressionForConstantValue:@(NoDueDate)]];
[noDueDateItem setEnabled:YES];
[noDueDateItem setTag:(long)NoDueDate];
NSMenu *dueStateMenu = [[NSMenu alloc] initWithTitle:@"Due State"];
[dueStateMenu addItem:dueTodayItem];
[dueStateMenu addItem:overdueItem];
[dueStateMenu addItem:notDueItem];
[dueStateMenu addItem:noDueDateItem];
_dueStatePopUp = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
[_dueStatePopUp setMenu:dueStateMenu];
}
return _dueStatePopUp;
}
#pragma mark - NSPredicateEditorRowTemplate Method Overrides
- (NSArray*)templateViews {
NSMutableArray *newTemplateViews = [[super templateViews] mutableCopy];
[newTemplateViews replaceObjectAtIndex:0 withObject:self.keypathPopUp];
[newTemplateViews replaceObjectAtIndex:2 withObject:self.dueStatePopUp];
return newTemplateViews;
}
- (void)setPredicate:(NSPredicate *)predicate {
id rightValue = [[(NSComparisonPredicate*)predicate rightExpression] constantValue];
if ([rightValue isKindOfClass:[NSNumber class]]) {
[self.dueStatePopUp selectItemWithTag:[rightValue integerValue]];
}
}
- (NSPredicate*)predicateWithSubpredicates:(NSArray*)subpredicates {
NSPredicate *p = [super predicateWithSubpredicates:subpredicates];
NSComparisonPredicate *comparison = (NSComparisonPredicate*)p;
NSPredicate *newPredicate =
[NSComparisonPredicate
predicateWithLeftExpression:[[self.keypathPopUp selectedItem] representedObject]
rightExpression:[[self.dueStatePopUp selectedItem] representedObject]
modifier:[comparison comparisonPredicateModifier]
type:[comparison predicateOperatorType]
options:[comparison options]];
return newPredicate;
}
@end
================================================
FILE: TodoTxtMac/TTMPredicateEditorHiddenRowTemplate.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@interface TTMPredicateEditorHiddenRowTemplate : NSPredicateEditorRowTemplate
@property (nonatomic, retain) NSPopUpButton *keypathPopUp;
@property (nonatomic, retain) NSPopUpButton *boolPopUp;
@end
================================================
FILE: TodoTxtMac/TTMPredicateEditorHiddenRowTemplate.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMPredicateEditorHiddenRowTemplate.h"
@implementation TTMPredicateEditorHiddenRowTemplate
#pragma mark - Class Property Getters
- (NSPopUpButton*)keypathPopUp {
if(!_keypathPopUp) {
NSMenu *keypathMenu = [[NSMenu alloc]
initWithTitle:@"hidden menu"];
NSMenuItem *menuItem = [[NSMenuItem alloc]
initWithTitle:@"hidden"
action:nil
keyEquivalent:@""];
[menuItem setRepresentedObject:[NSExpression expressionForKeyPath:@"isHidden"]];
[menuItem setEnabled:YES];
[keypathMenu addItem:menuItem];
_keypathPopUp = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
[_keypathPopUp setMenu:keypathMenu];
}
return _keypathPopUp;
}
- (NSPopUpButton*)boolPopUp {
if (!_boolPopUp) {
NSMenuItem *yesItem = [[NSMenuItem alloc] initWithTitle:@"Yes" action:nil keyEquivalent:@""];
[yesItem setRepresentedObject:[NSExpression expressionForConstantValue:@YES]];
[yesItem setEnabled:YES];
[yesItem setTag:1];
NSMenuItem *noItem = [[NSMenuItem alloc] initWithTitle:@"No" action:nil keyEquivalent:@""];
[noItem setRepresentedObject:[NSExpression expressionForConstantValue:@NO]];
[noItem setEnabled:YES];
[noItem setTag:0];
NSMenu *boolMenu = [[NSMenu alloc] initWithTitle:@"Yes/No"];
[boolMenu addItem:yesItem];
[boolMenu addItem:noItem];
_boolPopUp = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
[_boolPopUp setMenu:boolMenu];
}
return _boolPopUp;
}
#pragma mark - NSPredicateEditorRowTemplate Method Overrides
- (NSArray*)templateViews {
NSMutableArray *newTemplateViews = [[super templateViews] mutableCopy];
[newTemplateViews replaceObjectAtIndex:0 withObject:self.keypathPopUp];
[newTemplateViews replaceObjectAtIndex:2 withObject:self.boolPopUp];
return newTemplateViews;
}
- (void)setPredicate:(NSPredicate*)predicate {
id rightValue = [[(NSComparisonPredicate*)predicate rightExpression] constantValue];
if ([rightValue isKindOfClass:[NSNumber class]]) {
[self.boolPopUp selectItemWithTag:[rightValue integerValue]];
}
}
- (NSPredicate*)predicateWithSubpredicates:(NSArray*)subpredicates {
NSPredicate *newPredicate =
[NSComparisonPredicate
predicateWithLeftExpression:[[self.keypathPopUp selectedItem] representedObject]
rightExpression:[[self.boolPopUp selectedItem] representedObject]
modifier:NSDirectPredicateModifier
type:NSEqualToPredicateOperatorType
options:0];
return newPredicate;
}
@end
================================================
FILE: TodoTxtMac/TTMPredicateEditorTextRowTemplate.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2016 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@interface TTMPredicateEditorTextRowTemplate : NSPredicateEditorRowTemplate
@end
================================================
FILE: TodoTxtMac/TTMPredicateEditorTextRowTemplate.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2016 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMPredicateEditorTextRowTemplate.h"
@implementation TTMPredicateEditorTextRowTemplate
NSString *const inFormatPrefix = @"rawText IN[cd]";
NSString *const notContainsFormatPrefix = @"NOT rawText CONTAINS[cd]";
#pragma mark - NSPredicateEditorRowTemplate Method Overrides
- (double)matchForPredicate:(NSPredicate *)predicate {
if ([predicate.predicateFormat hasPrefix:notContainsFormatPrefix]) {
return 0.4;
}
return [super matchForPredicate:predicate];
}
- (void)setPredicate:(NSPredicate*)predicate {
if ([predicate.predicateFormat hasPrefix:notContainsFormatPrefix]) {
NSPredicate *newPredicate = [self swapPredicateFormatPrefix:notContainsFormatPrefix withPrefix:inFormatPrefix forPredicate:predicate];
[super setPredicate:newPredicate];
return;
}
[super setPredicate:predicate];
}
- (NSPredicate*)predicateWithSubpredicates:(NSArray*)subpredicates {
NSPredicate *predicate = [super predicateWithSubpredicates:subpredicates];
return [self swapPredicateFormatPrefix:inFormatPrefix withPrefix:notContainsFormatPrefix forPredicate:predicate];
}
- (NSPredicate*)swapPredicateFormatPrefix:(NSString*)oldPrefix withPrefix:(NSString*)newPrefix forPredicate:(NSPredicate*)predicate {
NSString *predicateFormat = predicate.predicateFormat;
if ([predicateFormat hasPrefix:oldPrefix]) {
NSRange oldPrefixRange = [predicateFormat rangeOfString:oldPrefix];
NSString *newFormat = [predicateFormat stringByReplacingOccurrencesOfString:oldPrefix withString:newPrefix options:0 range:oldPrefixRange];
NSPredicate *newPredicate = [NSPredicate predicateWithFormat:newFormat];
return newPredicate;
}
return predicate;
}
@end
================================================
FILE: TodoTxtMac/TTMPredicateEditorThresholdRowTemplate.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@interface TTMPredicateEditorThresholdRowTemplate : NSPredicateEditorRowTemplate
@property (nonatomic, retain) NSPopUpButton *keypathPopUp;
@property (nonatomic, retain) NSPopUpButton *thresholdStatePopUp;
@end
================================================
FILE: TodoTxtMac/TTMPredicateEditorThresholdRowTemplate.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMPredicateEditorThresholdRowTemplate.h"
#import "TTMTask.h"
@implementation TTMPredicateEditorThresholdRowTemplate
#pragma mark - Class Property Getters
- (NSPopUpButton*)keypathPopUp {
if(!_keypathPopUp) {
NSMenu *keypathMenu = [[NSMenu alloc]
initWithTitle:@"threshold state menu"];
NSMenuItem *menuItem = [[NSMenuItem alloc]
initWithTitle:@"threshold state"
action:nil
keyEquivalent:@""];
[menuItem setRepresentedObject:[NSExpression expressionForKeyPath:@"thresholdState"]];
[menuItem setEnabled:YES];
[keypathMenu addItem:menuItem];
_keypathPopUp = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
[_keypathPopUp setMenu:keypathMenu];
}
return _keypathPopUp;
}
- (NSPopUpButton*)thresholdStatePopUp {
if (!_thresholdStatePopUp) {
NSMenuItem *noThresholdDateItem = [[NSMenuItem alloc]
initWithTitle:@"no threshold date"
action:nil
keyEquivalent:@""];
[noThresholdDateItem setRepresentedObject:[NSExpression
expressionForConstantValue:@(NoThresholdDate)]];
[noThresholdDateItem setEnabled:YES];
[noThresholdDateItem setTag:(long)NoThresholdDate];
NSMenuItem *thresholdBeforeToday = [[NSMenuItem alloc]
initWithTitle:@"threshold before today"
action:nil
keyEquivalent:@""];
[thresholdBeforeToday setRepresentedObject:[NSExpression
expressionForConstantValue:@(ThresholdBeforeToday)]];
[thresholdBeforeToday setEnabled:YES];
[thresholdBeforeToday setTag:(long)ThresholdBeforeToday];
NSMenuItem *thresholdIsTodayItem = [[NSMenuItem alloc]
initWithTitle:@"threshold is today"
action:nil
keyEquivalent:@""];
[thresholdIsTodayItem setRepresentedObject:[NSExpression
expressionForConstantValue:@(ThresholdIsToday)]];
[thresholdIsTodayItem setEnabled:YES];
[thresholdIsTodayItem setTag:(long)ThresholdIsToday];
NSMenuItem *thresholdAfterTodayItem = [[NSMenuItem alloc]
initWithTitle:@"threshold after today"
action:nil
keyEquivalent:@""];
[thresholdAfterTodayItem setRepresentedObject:[NSExpression
expressionForConstantValue:@(
ThresholdAfterToday)]];
[thresholdAfterTodayItem setEnabled:YES];
[thresholdAfterTodayItem setTag:(long)ThresholdAfterToday];
NSMenu *thresholdStateMenu = [[NSMenu alloc]
initWithTitle:@"Threshold State"];
[thresholdStateMenu addItem:noThresholdDateItem];
[thresholdStateMenu addItem:thresholdBeforeToday];
[thresholdStateMenu addItem:thresholdIsTodayItem];
[thresholdStateMenu addItem:thresholdAfterTodayItem];
_thresholdStatePopUp = [[NSPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO];
[_thresholdStatePopUp setMenu:thresholdStateMenu];
}
return _thresholdStatePopUp;
}
#pragma mark - NSPredicateEditorRowTemplate Method Overrides
- (NSArray*)templateViews {
NSMutableArray *newTemplateViews = [[super templateViews] mutableCopy];
[newTemplateViews replaceObjectAtIndex:0 withObject:self.keypathPopUp];
[newTemplateViews replaceObjectAtIndex:2 withObject:self.thresholdStatePopUp];
return newTemplateViews;
}
- (void)setPredicate:(NSPredicate *)predicate {
id rightValue = [[(NSComparisonPredicate*)predicate rightExpression] constantValue];
if ([rightValue isKindOfClass:[NSNumber class]]) {
[self.thresholdStatePopUp selectItemWithTag:[rightValue integerValue]];
}
}
- (NSPredicate*)predicateWithSubpredicates:(NSArray*)subpredicates {
NSPredicate *p = [super predicateWithSubpredicates:subpredicates];
NSComparisonPredicate *comparison = (NSComparisonPredicate*)p;
NSPredicate *newPredicate =
[NSComparisonPredicate
predicateWithLeftExpression:[[self.keypathPopUp selectedItem] representedObject]
rightExpression:[[self.thresholdStatePopUp selectedItem] representedObject]
modifier:[comparison comparisonPredicateModifier]
type:[comparison predicateOperatorType]
options:[comparison options]];
return newPredicate;
}
@end
================================================
FILE: TodoTxtMac/TTMPreferences.xib
================================================
FontNameTransformer
NSUnarchiveFromData
NSUnarchiveFromData
NSUnarchiveFromData
NSUnarchiveFromData
NSUnarchiveFromData
NSUnarchiveFromData
NSUnarchiveFromData
NSUnarchiveFromData
================================================
FILE: TodoTxtMac/TTMPreferencesController.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@class TTMAppController;
@interface TTMPreferencesController : NSWindowController
@property (nonatomic, retain) IBOutlet TTMAppController *appController;
@property (nonatomic, retain) NSFont *selectedFont;
@property (nonatomic, retain) IBOutlet NSTextField *statusBarFormat;
@property (nonatomic, retain) NSArray *availableStatusBarTags;
@property (nonatomic, retain) IBOutlet NSArrayController *statusBarTags;
#pragma mark - Choose File Methods
/*!
* @method chooseArchiveFile:
* @abstract This method allows the user to choose the archive file (done.txt).
*/
- (IBAction)chooseArchiveFile:(id)sender;
/*!
* @method chooseDefaultTodoFile:
* @abstract This method allows the user to choose a default todo.txt file to open at startup.
*/
- (IBAction)chooseDefaultTodoFile:(id)sender;
/*!
* @method chooseFileForUserDefaultsKey:withPrompt:
* @abstract This method calls the file open method, allows the user to select a file,
* and stores the file URL to a specified user default key.
* @discussion This is a helper method called by chooseArchiveFile: and chooseDefaultTodoFile:.
*/
- (void)chooseFileForUserDefaultsKey:(NSString*)userDefaultsKey withPrompt:(NSString*)prompt;
#pragma mark - Behavior Change Methods
/*!
* @method hideFutureTasksPreferenceChanged:
* @abstract This method is called when the "hide future tasks" settings is changed.
*/
- (IBAction)hideFutureTasksPreferenceChanged:(id)sender;
/*!
* @method hideHiddenTasksPreferenceChanged:
* @abstract This method is called when the "hide hidden tasks" settings is changed.
*/
- (IBAction)hideHiddenTasksPreferenceChanged:(id)sender;
#pragma mark - Font Change Methods
/*!
* @method openFontPanel:
* @abstract This method allows the user to choose a user font from the font panel.
* @discussion The changeFont: method is called whenever the user changes the font in the font panel.
*/
- (IBAction)openFontPanel:(id)sender;
#pragma mark - Color Change Methods
/*!
* @method colorChanged:
* @abstract This method triggers a visual refresh of all open todo files.
* @discussion This method is called whenever a user changes the color in an associated colorwell.
*/
- (IBAction)colorChanged:(id)sender;
#pragma mark - Status Bar Methods
/*!
* @method insertTagIntoStatusBarFormat:
* @abstract This method inserts the tag selected from the tags popup into the status bar format.
*/
- (IBAction)insertTagIntoStatusBarFormat:(id)sender;
/*!
* @method resetStatusBarFormatToDefault:
* @abstract This method resets the status bar format to the default value.
*/
- (IBAction)resetStatusBarFormatToDefault:(id)sender;
/*!
* @method controlTextDidChange:
* @abstract This is a delegate method for the status bar text field. On any change to the text,
* it forces a visual refresh of all open windows, to update the status bars.
*/
- (void)controlTextDidChange:(NSNotification *)aNotification;
@end
================================================
FILE: TodoTxtMac/TTMPreferencesController.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMPreferencesController.h"
#import "TTMAppController.h"
#import "TTMDocumentStatusBarText.h"
@implementation TTMPreferencesController
- (id)initWithWindow:(NSWindow *)window {
self = [super initWithWindow:window];
if (self) {
// Initialization code here.
_availableStatusBarTags = [NSArray arrayWithArray:[TTMDocumentStatusBarText availableTags]];
}
return self;
}
- (void)windowDidLoad {
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
- (void)awakeFromNib {
NSFontPanel *fontPanel = [NSFontPanel sharedFontPanel];
[fontPanel display];
}
#pragma mark - *** Window delegation ***
- (BOOL)windowShouldClose:(NSWindow *)window {
return [window makeFirstResponder:nil]; // validate editing
}
#pragma mark - Choose File Methods
- (IBAction)chooseArchiveFile:(id)sender {
[self chooseFileForUserDefaultsKey:@"archiveFilePath" withPrompt:@"Choose Archive File"];
}
- (IBAction)chooseDefaultTodoFile:(id)sender {
[self chooseFileForUserDefaultsKey:@"defaultTodoFilePath" withPrompt:@"Choose todo.txt File"];
}
- (void)chooseFileForUserDefaultsKey:(NSString*)userDefaultsKey withPrompt:(NSString*)prompt {
NSOpenPanel *panel = [NSOpenPanel openPanel];
[panel setCanChooseFiles:YES];
[panel setCanChooseDirectories:NO];
[panel setAllowsMultipleSelection:NO];
[panel setPrompt:prompt];
[panel setAllowedFileTypes:@[@"txt", @"TXT", @"todo", @"TODO", @""]];
if ([panel runModal] == NSFileHandlingPanelOKButton) {
for (NSURL *fileURL in [panel URLs]) {
[[NSUserDefaults standardUserDefaults] setValue:[fileURL path] forKey:userDefaultsKey];
}
}
}
#pragma mark - Behavior Change Methods
- (IBAction)hideFutureTasksPreferenceChanged:(id)sender {
[self.appController visualRefreshAll:self];
}
- (IBAction)hideHiddenTasksPreferenceChanged:(id)sender {
[self.appController visualRefreshAll:self];
}
#pragma mark - Font Change Methods
- (IBAction)openFontPanel:(id)sender {
NSFontManager *fontManager = [NSFontManager sharedFontManager];
[fontManager setTarget:self];
[fontManager setSelectedFont:[NSFont userFontOfSize:0.0] isMultiple:NO];
[fontManager orderFrontFontPanel:self];
[self.appController visualRefreshAll:self];
}
- (void)changeFont:(id)fontManager {
self.selectedFont = [fontManager convertFont:self.selectedFont];
[self.appController visualRefreshAll:self];
}
- (NSFont*)selectedFont {
return [NSFont userFontOfSize:0.0];
}
- (void)setSelectedFont:(NSFont*)newFont {
[NSFont setUserFont:newFont];
}
#pragma mark - Color Change Methods
- (IBAction)colorChanged:(id)sender {
[self.appController visualRefreshAll:self];
}
#pragma mark - Status Bar Methods
- (IBAction)insertTagIntoStatusBarFormat:(id)sender {
[[self.statusBarFormat currentEditor] insertText:self.statusBarTags.selectedObjects[0]];
}
- (IBAction)resetStatusBarFormatToDefault:(id)sender {
NSAlert *resetPrompt = [[NSAlert alloc] init];
resetPrompt.messageText = @"Reset status bar format to default?";
resetPrompt.informativeText = @"Are you sure you want to do this? You will lose all status bar customizations.";
[resetPrompt addButtonWithTitle:@"OK"];
[resetPrompt addButtonWithTitle:@"Cancel"];
[resetPrompt beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) {
if (returnCode == NSAlertFirstButtonReturn) {
[[NSUserDefaults standardUserDefaults] setValue:[TTMDocumentStatusBarText defaultFormat]
forKey:@"statusBarFormat"];
[self.appController visualRefreshAll:self];
}
}];
}
- (void)controlTextDidChange:(NSNotification *)aNotification {
[self.appController visualRefreshAll:self];
}
@end
================================================
FILE: TodoTxtMac/TTMTableView.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@class TTMDocument;
@interface TTMTableView : NSTableView
#pragma mark - Properties
@property (nonatomic, retain) IBOutlet TTMDocument *parentDocument;
@property (nonatomic, copy) NSString *selectedRawText;
#pragma mark - Handle Keyboard Events Methods
/*!
* @abstract This method allows us to send a new KeyDown event to this class's super
* or to another class, namely this object's window. It allows us to translate
* a keypress of 'j', for example, into a down arrow.
*/
- (void)translateKeyDownEvent:(NSEvent*)theEvent
toKeyDown:(unichar)keyDown
sendToControl:(id)targetControl;
#pragma mark - Row Height Methods
/*!
* @method defaultLineHeightForFont:
* @abstract This method returns the default line height for the given font.
* @param font The font for which the line height is needed.
* @return Returns the line height to set so the given font is not truncated.
*/
- (CGFloat)defaultLineHeightForFont:(NSFont*)font;
#pragma mark - isEditing property
/*!
* @method isEditing
* @return Returns true if the table is being edited.
*/
- (bool)isEditing;
@end
================================================
FILE: TodoTxtMac/TTMTableView.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMTableView.h"
#import "TTMDocument.h"
#import "TTMTask.h"
@implementation TTMTableView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_selectedRawText = nil;
}
return self;
}
#pragma mark - Handle Keyboard Events Methods
/*!
* @method keyDown:
* @abstract Override the default keyDown event handler to call custom commands,
* such as those handled by the parent window.
*/
- (void)keyDown:(NSEvent *)theEvent {
NSUInteger flags = [theEvent modifierFlags];
NSString *passedChar = [theEvent charactersIgnoringModifiers];
unichar keyChar = [passedChar characterAtIndex:0];
// tab key (we do not want the tab key to trigger edit mode)
if (keyChar == 9) {
[self translateKeyDownEvent:theEvent toKeyDown:keyChar sendToControl:[self window]];
return;
}
// command+c to copy selected tasks
if ((flags & NSCommandKeyMask) &&
(keyChar == 'c')) {
[self translateKeyDownEvent:theEvent toKeyDown:keyChar sendToControl:[self window]];
return;
}
// handle command+option+arrow key combinations
if ((flags & NSCommandKeyMask) &&
(flags & NSNumericPadKeyMask) &&
(flags & NSAlternateKeyMask)) {
[self translateKeyDownEvent:theEvent toKeyDown:keyChar sendToControl:[self window]];
return;
}
// handle command+arrow key combinations
if ((flags & NSCommandKeyMask) &&
(flags & NSNumericPadKeyMask)) {
[self translateKeyDownEvent:theEvent toKeyDown:keyChar sendToControl:[self window]];
return;
}
// handle option + key shortcuts
// This fixes a bug in which Option+s jumps to the first task starting with the letter 's'.
if (flags & NSAlternateKeyMask) {
[self translateKeyDownEvent:theEvent toKeyDown:keyChar sendToControl:[self window]];
return;
}
// do not override the super for other special key combinations
if ((flags & NSCommandKeyMask) ||
(flags & NSControlKeyMask)) {
[super keyDown:theEvent];
return;
}
// delete/backspace
if (keyChar == NSBackspaceCharacter) {
[self translateKeyDownEvent:theEvent
toKeyDown:NSBackspaceCharacter
sendToControl:[self window]];
return;
}
// move down
if (keyChar == 'j') {
[self translateKeyDownEvent:theEvent toKeyDown:NSDownArrowFunctionKey sendToControl:self];
return;
}
// move up
if (keyChar == 'k') {
[self translateKeyDownEvent:theEvent toKeyDown:NSUpArrowFunctionKey sendToControl:self];
return;
}
// update task (send Enter/Return to super)
if (keyChar == NSEnterCharacter || keyChar == '\r' || keyChar == 'u') {
[self translateKeyDownEvent:theEvent toKeyDown:'u' sendToControl:[self window]];
return;
}
// Handle all other single-character commands (those that do not require translating
// to different key presses) by passing them to the parent window.
// The key equivalents are defined for the menu items in MainMenu.xib
NSMutableCharacterSet *singleKeyCommands = [[NSMutableCharacterSet alloc] init];
[singleKeyCommands addCharactersInString:@"nxdfprcsait.0123456789"];
if ([singleKeyCommands characterIsMember:keyChar]) {
[self translateKeyDownEvent:theEvent toKeyDown:keyChar sendToControl:[self window]];
return;
}
// default behavior: pass the event to the super if we didn't make a match above
[super keyDown:theEvent];
}
- (void)translateKeyDownEvent:(NSEvent*)theEvent
toKeyDown:(unichar)keyDown
sendToControl:(id)targetControl {
NSString *keyDownString = [NSString stringWithCharacters:&keyDown length:1];
NSEvent *newEvent =[NSEvent keyEventWithType:NSKeyDown
location:theEvent.locationInWindow
modifierFlags:theEvent.modifierFlags
timestamp:theEvent.timestamp
windowNumber:theEvent.windowNumber
context:nil
characters:keyDownString
charactersIgnoringModifiers:keyDownString
isARepeat:theEvent.isARepeat
keyCode:keyDown];
if (targetControl == self || nil == targetControl)
{
[super keyDown:newEvent];
} else {
[targetControl keyDown:newEvent];
}
}
#pragma mark - Respond to Changes Methods
- (void)editColumn:(NSInteger)column row:(NSInteger)row withEvent:(NSEvent *)theEvent select:(BOOL)select {
[self.tableColumns.lastObject setMinWidth:0];
[self.tableColumns.lastObject setMaxWidth:self.parentDocument.windowForSheet.frame.size.width];
[self.tableColumns.lastObject setWidth:self.parentDocument.windowForSheet.frame.size.width];
[super editColumn:column row:row withEvent:theEvent select:select];
}
- (void)textDidBeginEditing:(NSNotification*)notification {
[self.parentDocument initializeUpdateSelectedTask];
[super textDidBeginEditing:notification];
self.selectedRawText = [[notification object] string];
}
- (void)textDidEndEditing:(NSNotification*)notification {
[super textDidEndEditing:notification];
NSString *newValue = [[notification object] string];
// Handle no change.
if (self.selectedRawText == nil ||
[self.selectedRawText isEqualToString:newValue]) {
[self.parentDocument setTableWidthToWidthOfContents];
return;
}
[self.parentDocument finalizeUpdateSelectedTask:newValue];
self.selectedRawText = nil;
}
#pragma mark - Drag and Drop Methods
- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender {
return NSDragOperationCopy;
}
- (NSDragOperation)draggingUpdated:(id)sender {
return NSDragOperationCopy;
}
- (BOOL)performDragOperation:(id)sender {
return YES;
}
- (void)concludeDragOperation:(id)sender {
[self.parentDocument addNewTasksFromDragAndDrop:sender];
}
#pragma mark - Row Height Methods
- (CGFloat)rowHeight {
return ([self.parentDocument usingUserFont]) ?
[self defaultLineHeightForFont:[self.parentDocument userFont]] :
[super rowHeight];
}
- (CGFloat)defaultLineHeightForFont:(NSFont*)font {
// Use default user font if font is nil.
if (font == nil) {
font = [NSFont userFontOfSize:0];
}
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[layoutManager setTypesetterBehavior:NSTypesetterBehavior_10_2_WithCompatibility];
return [layoutManager defaultLineHeightForFont:font];
}
#pragma mark - isEditing property
- (bool)isEditing {
return (self.editedRow != -1);
}
@end
================================================
FILE: TodoTxtMac/TTMTableViewDelegate.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@class TTMTask;
@interface TTMTableViewDelegate : NSObject
#pragma mark - Properties
@property (nonatomic, retain) IBOutlet NSArrayController *arrayController;
@end
================================================
FILE: TodoTxtMac/TTMTableViewDelegate.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMTableViewDelegate.h"
#import "RegExCategories.h"
#import "TTMTask.h"
#import "NSUserDefaults+myColorSupport.h"
@implementation TTMTableViewDelegate
#pragma mark - TableView Delegate Methods
- (void)tableView:(NSTableView *)tableView
willDisplayCell:(id)cell
forTableColumn:(NSTableColumn *)tableColumn
row:(NSInteger)row {
// Apply the task's display format to the rawText cell.
if ([[tableColumn identifier] isEqualToString:@"rawText"]) {
TTMTask *task = [[self.arrayController arrangedObjects] objectAtIndex:row];
if (nil == task || task.isBlank) {
return;
}
// Get the user's preferred highlight colors or the defaults.
BOOL selected = ([tableView.selectedRowIndexes containsIndex:row]);
BOOL useHighlightColorsInTaskList = [[NSUserDefaults standardUserDefaults]
boolForKey:@"useHighlightColorsInTaskList"];
NSColor *completedColor = [NSColor lightGrayColor];
NSColor *dueTodayColor = ([[NSUserDefaults standardUserDefaults]
boolForKey:@"useCustomColorForDueTodayTasks"]) ?
[[NSUserDefaults standardUserDefaults] colorForKey:@"dueTodayColor"] :
[NSColor redColor];
NSColor *overdueColor = ([[NSUserDefaults standardUserDefaults]
boolForKey:@"useCustomColorForOverdueTasks"]) ?
[[NSUserDefaults standardUserDefaults] colorForKey:@"overdueColor"] :
[NSColor purpleColor];
NSColor *projectColor = ([[NSUserDefaults standardUserDefaults]
boolForKey:@"useCustomColorForProjects"]) ?
[[NSUserDefaults standardUserDefaults] colorForKey:@"projectColor"] :
[NSColor darkGrayColor];
NSColor *contextColor = ([[NSUserDefaults standardUserDefaults]
boolForKey:@"useCustomColorForContexts"]) ?
[[NSUserDefaults standardUserDefaults] colorForKey:@"contextColor"] :
[NSColor darkGrayColor];
NSColor *tagColor = ([[NSUserDefaults standardUserDefaults]
boolForKey:@"useCustomColorForTags"]) ?
[[NSUserDefaults standardUserDefaults] colorForKey:@"tagColor"] :
[NSColor darkGrayColor];
NSColor *dueDateColor = ([[NSUserDefaults standardUserDefaults]
boolForKey:@"useCustomColorForDueDates"]) ?
[[NSUserDefaults standardUserDefaults] colorForKey:@"dueDateColor"] :
[NSColor darkGrayColor];
NSColor *thresholdDateColor = ([[NSUserDefaults standardUserDefaults]
boolForKey:@"useCustomColorForThresholdDates"]) ?
[[NSUserDefaults standardUserDefaults] colorForKey:@"thresholdDateColor"] :
[NSColor darkGrayColor];
NSColor *creationDateColor = ([[NSUserDefaults standardUserDefaults]
boolForKey:@"useCustomColorForCreationDates"]) ?
[[NSUserDefaults standardUserDefaults] colorForKey:@"creationDateColor"] :
[NSColor darkGrayColor];
NSAttributedString *as = [task displayText:selected
font:[cell font]
useHighlightColorsInTaskList:useHighlightColorsInTaskList
completedColor:completedColor
dueTodayColor:dueTodayColor
overdueColor:overdueColor
projectColor:projectColor
contextColor:contextColor
tagColor:tagColor
dueDateColor:dueDateColor
thresholdDateColor:thresholdDateColor
creationDateColor:creationDateColor];
[cell setAttributedStringValue:as];
}
}
@end
================================================
FILE: TodoTxtMac/TTMTask.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
/*!
* @class TTMTask
* @abstract TTMTask represents a single todo.txt task.
* @discussion A single task is a single line in the todo.txt file, which is in a specific format.
* @seealso Todo.txt format specification:
* https://github.com/ginatrapani/todo.txt-cli/wiki/The-Todo.txt-Format
*/
@interface TTMTask : NSObject
/*! Defines the three due states of a task: Overdue, Due Today, and Not Due */
typedef enum : NSUInteger {
Overdue,
DueToday,
NotDue,
NoDueDate
} TTMDueState;
/*! Defines the threshold date-related state of a task */
typedef enum : NSUInteger {
NoThresholdDate,
ThresholdBeforeToday,
ThresholdIsToday,
ThresholdAfterToday
} TTMThresholdState;
#pragma mark - Properties
/*! Raw text of the task (a single line in the todo.txt file) */
@property (nonatomic, readwrite, setter = setRawText:, getter = rawText) NSString *rawText;
/*! The line number in todo.txt file, starting at zero */
@property (nonatomic, readonly) NSUInteger taskId;
@property (nonatomic, readonly) NSString *fullPriorityText;
@property (nonatomic, readonly) NSString *priorityText;
@property (nonatomic, readonly) unichar priority;
@property (nonatomic, readonly) NSString *dueDateText;
@property (nonatomic, readonly) NSDate *dueDate;
@property (nonatomic, readonly) NSString *creationDateText;
@property (nonatomic, readonly) NSDate *creationDate;
@property (nonatomic, readonly) NSString *completionDateText;
@property (nonatomic, readonly) NSDate *completionDate;
@property (nonatomic, readonly) NSString *thresholdDateText;
@property (nonatomic, readonly) NSDate *thresholdDate;
@property (nonatomic, readonly, copy) NSArray *contextsArray;
@property (nonatomic, readonly, copy) NSString *contexts;
@property (nonatomic, readonly) BOOL hasContexts;
@property (nonatomic, readonly, copy) NSArray *projectsArray;
@property (nonatomic, readonly, copy) NSString *projects;
@property (nonatomic, readonly) BOOL hasProjects;
@property (nonatomic, readonly) TTMDueState dueState;
@property (nonatomic, readonly) TTMThresholdState thresholdState;
@property (nonatomic, readonly) BOOL isCompleted;
@property (nonatomic, readonly) BOOL isPrioritized;
@property (nonatomic, readonly) BOOL isBlank;
@property (nonatomic, readonly) BOOL isRecurring;
@property (nonatomic, readonly) NSString *recurrencePattern;
@property (nonatomic, readonly) BOOL isHidden;
#pragma mark - Init Methods
/*!
* @method initWithRawText:withTaskId:withPrependedDate:
* @abstract Initializes task object with a task ID number, raw text, and a prepended date
* (or no date if nil is submitted).
* @discussion This function initializes the task and sets up all its properties.
* @param taskId An integer that represents the task's line number (ID) in the todo.txt file.
* @param rawText The raw text that represents a task in the Todo.txt format.
* @param prependedDate The creation date of the task to prepend to the task.
* @result Returns the newly initiatized object or an error.
* @seealso Todo.txt format specification:
* https://github.com/ginatrapani/todo.txt-cli/wiki/The-Todo.txt-Format
*/
- (id)initWithRawText:(NSString*)rawText withTaskId:(NSInteger)taskId
withPrependedDate:(NSDate*)prependedDate;
/*!
* @method initWithRawText:withTaskId:
* @abstract Initializes task object with a task ID number and raw text.
* @discussion This function initializes the task and sets up all its properties.
* @param taskId An integer that represents the task's line number (ID) in the todo.txt file.
* @param rawText The raw text that represents a task in the Todo.txt format.
* @result Returns the newly initiatized object or an error.
* @seealso Todo.txt format specification:
* https://github.com/ginatrapani/todo.txt-cli/wiki/The-Todo.txt-Format
*/
- (id)initWithRawText:(NSString*)rawText withTaskId:(NSInteger)taskId;
#pragma mark - rawText Methods
/*!
* @method setRawText:
* @abstract Changes raw text of the task.
* @discussion This function initializes the task and sets up all its properties other than
* the taskId number.
* @param rawText The raw text that represents a task in the Todo.txt format.
* @seealso Todo.txt format specification.
* https://github.com/ginatrapani/todo.txt-cli/wiki/The-Todo.txt-Format
*/
- (void)setRawText:(NSString*)rawText;
/*!
* @method setRawText:withPrependedDate:
* @abstract Changes raw text of the task and prepends a date if a creation date if one
* does not already exist in the first parameter.
* @discussion This function initializes the task and sets up all its properties other than
* the taskId number.
* @param rawText The raw text that represents a task in the Todo.txt format.
* @param taskId An integer that represents the task's line number (ID) in the todo.txt file.
* @param prependedDate A date, which represents the task creation date, to prepend to
* the task's raw text.
* @seealso Todo.txt format specification.
* https://github.com/ginatrapani/todo.txt-cli/wiki/The-Todo.txt-Format
*/
- (void)setRawText:(NSString*)rawText withPrependedDate:(NSDate*)prependedDate;
/*!
* @method displayText:
* @abstact Returns the task's raw text as a formatted string for display.
* @return Returns an attributed string to be used for display in the user interface.
* @discussion For good MVC compartmentalization, this method does not access the application's
* user defaults. Therefore, all color options are passed to this method.
*/
- (NSAttributedString*)displayText:(BOOL)selected
font:(NSFont*)font
useHighlightColorsInTaskList:(BOOL)useHighlightColorsInTaskList
completedColor:(NSColor*)completedColor
dueTodayColor:(NSColor*)dueTodayColor
overdueColor:(NSColor*)overdueColor
projectColor:(NSColor*)projectColor
contextColor:(NSColor*)contextColor
tagColor:(NSColor*)tagColor
dueDateColor:(NSColor*)dueDateColor
thresholdDateColor:(NSColor*)thresholdDateColor
creationDateColor:(NSColor*)creationDateColor;
#pragma mark - Append and Prepend Methods
/*!
* @method appendText:
* @abstract Appends text to the end of the task.
*/
- (void)appendText:(NSString*)textToAppend;
/*!
* @method prependText:
* @abstract Prepends text to the beginning of the task.
@ @discussion Prepending text to a task with a priority or a creation date will
* insert text after the priority or creation date. Otherwise, it will insert text
* at the start of the task.
*/
- (void)prependText:(NSString*)textToPrepend;
#pragma Find/replace Method
/*!
* @method prependText:
* @abstract Prepends text to the beginning of the task.
* @param textToReplace
* @param replacementText
*/
- (void)replaceText:(NSString*)textToReplace withText:(NSString*)replacementText;
#pragma mark - Due/Not Due Method
/*!
* @method getDueState:
* @abstract Compares the task's DueDate property to today's date and determines
* the due status of the task (overdue, due today, or not due).
* @return Returns a TTMDueState enum type value that indicates a task is "Overdue", "Not Due",
* or "Due Today".
* @discussion This method sets the property dueState.
*/
- (TTMDueState)getDueState;
#pragma mark - Threshold Date Methods
/*!
* @method setThresholdDate:
* @abstract Sets the threshold date.
* @param dueDate The threshold date to set.
* @discussion The thresholdDate parameter is not a string, it is an NSDate value.
* Handling of "natural language" due dates would have be handled prior to invoking this method.
*/
- (void)setThresholdDate:(NSDate *)thresholdDate;
/*!
* @method removeThresholdDate;
* @abstract Removes the threshold date from the task's raw text.
*/
- (void)removeThresholdDate;
/*!
* @method incrementThresholdDate:
* @abstract Increases threshold day by a specified number of days.
* Sets threshold date to tomorrow if there is no threshold date.
* @param Number of days to add to the task threshold date.
*/
- (void)incrementThresholdDate:(NSInteger)days;
/*!
* @method decrementThresholdDate:
* @abstract Decreases threshold day by a specified number of days.
* Sets threshold date to yesterday if there is no threshold date.
* @param Number of days to subtract to the task threshold date.
*/
- (void)decrementThresholdDate:(NSInteger)days;
/*!
* @method getThresholdState:
* @abstract Compares the task's thresholdDate property to today's date and determines
* the status of the task (today's date is before, on, or after the threshold date).
* @return Returns a TTMThresholdState enum type value that indicates whether today is before,
on, or after a task's threshold date.
* or "Due Today".
* @discussion This method sets the property thresholdState.
*/
- (TTMThresholdState)getThresholdState;
#pragma mark - Priority Methods
/*!
* @method setPriority:
* @abstract Sets the priority of a task, whether or not it already has
* a priority assigned.
* @param priority This is the priority to set the task to. It must be a capital letter [A-Z],
* as in @"A".
* @discussion The priority parameter is not passed with parentheses, as in "(A)",
* as it is written in the todo.txt file.
*/
- (void)setPriority:(unichar)priority;
/*!
* @method increasePriority:
* @abstract Increases the priority of a task by one step.
* @discussion If the task has no priority, set priority to 'A'.
*/
- (void)increasePriority;
/*!
* @method decreasePriority:
* @abstract Decreases the priority of a task by one step.
* @discussion If the task has no priority, set priority to 'A'.
*/
- (void)decreasePriority;
/*!
* @method removePriority:
* @abstract Removes the priority of a task.
*/
- (void)removePriority;
#pragma mark - Completion Methods
/*!
* @method markComplete:
* @abstract Marks an incomplete task as complete by prepending "x YYYY-mm-dd " to the raw text.
* @discussion This method is usually called via the toggleCompletionStatus: method.
*/
- (void)markComplete;
/*!
* @method markIncomplete:
* @abstract Marks a completed task as incomplete by removing the prepended
* "x YYYY-mm-dd " from the raw text.
* @discussion This method is usually called via the toggleCompletionStatus method.
*/
- (void)markIncomplete;
/*!
* @method toggleCompletionStatus:
* @abstract Toggles completion status of a task.
* @discussion This method calls the method markIncomplete or the method markIncomplete.
*/
- (void)toggleCompletionStatus;
# pragma mark - Postpone and Set Due Date Methods
/*!
* @method postponeTask;
* @abstract Postpones a task by the number of days provided.
* @discussion This method will set a due date if none already exists. If a negative number
* is passed to it, the due date will move up rather than back.
*/
- (void)postponeTask:(NSInteger)days;
/*!
* @method incrementDueDate:
* @abstract Increases due date by a specified number of days.
* Sets due date to tomorrow if there is no threshold date.
* @param Number of days to add to the task due date.
*/
- (void)incrementDueDate:(NSInteger)days;
/*!
* @method decrementDueDate:
* @abstract Decreases due date by a specified number of days.
* Sets due date to yesterday if there is no threshold date.
* @param Number of days to subtract to the task due date.
*/
- (void)decrementDueDate:(NSInteger)days;
/*!
* @method setDueDate:
* @abstract Sets the due date.
* @param dueDate The due date to set.
* @discussion The dueDate parameter is not a string, it is an NSDate value.
* Handling of "natural language" due dates would have be handled prior to invoking this method.
*/
- (void)setDueDate:(NSDate *)dueDate;
/*!
* @method removeDueDate;
* @abstract Removes the due date from the task's raw text.
*/
- (void)removeDueDate;
- (TTMTask*)newRecurringTask;
- (void)removeCreationDate;
@end
================================================
FILE: TodoTxtMac/TTMTask.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMTask.h"
#import "RegExCategories.h"
#import "TTMDateUtility.h"
#import "NSMutableAttributableString+ColorRegExMatches.h"
#import "NSDate+RelativeDates.h"
@implementation TTMTask
@synthesize rawText=_rawText;
// define constants for regular expressions
static NSString * const LineBreakPattern = @"(\\r|\\n)";
static NSString * const CompletedPattern = @"^x[ ]((\\d{4})-(\\d{2})-(\\d{2}))[ ]";
static NSString * const CompletionDatePattern = @"(?<=^x[ ])((\\d{4})-(\\d{2})-(\\d{2}))(?=[ ]|$)";
static NSString * const PriorityTextPattern = @"^(\\([A-Z]\\)[ ])";
static NSString * const CreationDatePatternIncomplete = @"(?<=^|\\([A-Z]\\)[ ])((\\d{4})-(\\d{2})-(\\d{2}))(?=[ ]|$)";
static NSString * const CreationDatePatternIncompletePlusTrailingSpace = @"(?<=^|\\([A-Z]\\)[ ])((\\d{4})-(\\d{2})-(\\d{2}))([ ]|$)";
static NSString * const CreationDatePatternCompleted = @"(?<=^x[ ]((\\d{4})-(\\d{2})-(\\d{2}))[ ])((\\d{4})-(\\d{2})-(\\d{2}))(?=[ ]|$)";
static NSString * const CreationDatePatternCompletedPlusTrailingSpace = @"(?<=^x[ ]((\\d{4})-(\\d{2})-(\\d{2}))[ ])((\\d{4})-(\\d{2})-(\\d{2}))(?=[ ]|$)";
static NSString * const DueDatePattern = @"(?<=(^|[ ])due:)((\\d{4})-(\\d{2})-(\\d{2}))(?=[ ]|$)";
static NSString * const FullDueDatePatternMiddleOrEnd = @"(([ ])due:)((\\d{4})-(\\d{2})-(\\d{2}))(?=[ ]|$)";
static NSString * const FullDueDatePatternBeginning = @"^due:((\\d{4})-(\\d{2})-(\\d{2}))[ ]?|$";
static NSString * const ThresholdDatePattern = @"(?<=(^|[ ])t:)((\\d{4})-(\\d{2})-(\\d{2}))(?=[ ]|$)";
static NSString * const FullThresholdDatePatternMiddleOrEnd = @"(([ ])t:)((\\d{4})-(\\d{2})-(\\d{2}))(?=[ ]|$)";
static NSString * const FullThresholdDatePatternBeginning = @"^t:((\\d{4})-(\\d{2})-(\\d{2}))[ ]?|$";
static NSString * const ProjectPattern = @"(?<=^|[ ])(\\+[^[ ]]+)";
static NSString * const ContextPattern = @"(?<=^|[ ])(\\@[^[ ]]+)";
static NSString * const TagPattern = @"(?<=^|[ ])([:graph:]+:[:graph:]+)";
static NSString * const RecurrencePattern = @"(?<=(^|[ ])rec:)((\\+?)\\d+[dDwWmMyYbB])";
static NSString * const HiddenPattern = @"(?<=^|[ ])(h:1)(?=[ ]|$)";
#pragma mark - Init Methods
- (id)initWithRawText:(NSString*)rawText withTaskId:(NSInteger)taskId
withPrependedDate:(NSDate*)prependedDate {
self = [super init];
if (self) {
_taskId = taskId;
[self setRawText:rawText withPrependedDate:prependedDate];
}
return self;
}
- (id)initWithRawText:(NSString*)rawText withTaskId:(NSInteger)taskId {
return [self initWithRawText:rawText withTaskId:taskId withPrependedDate:nil];
}
#pragma mark - rawText Methods
- (void)setRawText:(NSString*)rawText withPrependedDate:(NSDate*)prependedDate {
NSString *newRawText;
if (!prependedDate ||
[rawText isMatch:RX(CreationDatePatternIncomplete)] ||
[rawText isMatch:RX(CreationDatePatternCompleted)] ||
[rawText isMatch:RX(CompletedPattern)]
) {
// if no prepended date is passed, or if there is already a creation date, or the task is already completed, prepend nothing
newRawText = rawText;
} else if ([rawText isMatch:RX(PriorityTextPattern)]) {
// if the rawText has a priority, prepend the date after the priority
newRawText = [NSString stringWithFormat:@"%@%@%c%@",
[rawText substringToIndex:4],
[TTMDateUtility convertDateToString:prependedDate],
' ',
[rawText substringFromIndex:4]];
} else {
// if the rawText has no priority, prepend the date at the beginning of the string
newRawText = [NSString stringWithFormat:@"%@%c%@",
[TTMDateUtility convertDateToString:prependedDate],
' ',
rawText];
}
[self setRawText:newRawText];
}
- (void)setRawText:(NSString*)rawText {
// only update rawText and other properties if the new raw text differs from the old raw text
if ([rawText isEqualToString:_rawText]) {
return;
}
// make sure the task doesn't contain line breaks
_rawText = [rawText replace:RX(LineBreakPattern) with:@""];
// handle blank strings gracefully
if (rawText == nil || [rawText isEqualToString:@""]) {
_isBlank = YES;
_isCompleted = NO;
_isPrioritized = NO;
_priorityText = @"";
_priority = '~';
_contexts = @"";
_contextsArray = nil;
_projects = @"";
_projectsArray = nil;
_completionDateText = @"";
_completionDate = nil;
_dueDateText = @"";
_dueDate = nil;
_creationDateText = @"";
_creationDate = nil;
_thresholdDateText = @"";
_thresholdDate = nil;
_dueState = NotDue;
_hasContexts = NO;
_hasProjects = NO;
_isRecurring = NO;
_recurrencePattern = nil;
_isHidden = NO;
return;
}
// set properties for non-blank strings
_isBlank = NO;
// completion date
_completionDateText = [_rawText firstMatch:RX(CompletionDatePattern)];
// Set completion date to the high date (9999-12-31) to ensure that tasks with no
// completion date are sorted after tasks with a due date.
NSDate *newCompletionDate = (_completionDateText == nil) ?
[TTMDateUtility convertStringToDate:@"9999-12-31"] :
[TTMDateUtility convertStringToDate:_completionDateText];
_completionDate = (newCompletionDate == nil) ?
[TTMDateUtility convertStringToDate:@"9999-12-31"] :
newCompletionDate;
_isCompleted = [_rawText isMatch:RX(CompletedPattern)] && (newCompletionDate != nil);
// priority
_isPrioritized = [_rawText isMatch:RX(PriorityTextPattern)];
_fullPriorityText = [_rawText firstMatch:RX(PriorityTextPattern)];
NSRange range = {.location = 1, .length = 1};
_priorityText = [_fullPriorityText substringWithRange:range];
// Set priority to tilde (~) to ensure that tasks with no priority are sorted after
// tasks with any other priority (A-Z).
_priority = (_priorityText != nil) ? [_priorityText characterAtIndex:0] : '~';
// sorted array of projects
_projectsArray = [[_rawText matches:RX(ProjectPattern)]
sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
_projects = [_projectsArray componentsJoinedByString:@", "];
_hasProjects = (_projectsArray.count > 0);
// sorted array of contexts
_contextsArray = [[_rawText matches:RX(ContextPattern)]
sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
_contexts = [_contextsArray componentsJoinedByString:@", "];
_hasContexts = (_contextsArray.count > 0);
// due date
_dueDateText = [_rawText firstMatch:RX(DueDatePattern)];
// Set due date to the high date (9999-12-31) to ensure that tasks with no due date
// are sorted after tasks with a due date.
NSDate *newDueDate = (_dueDateText == nil) ?
[TTMDateUtility convertStringToDate:@"9999-12-31"] :
[TTMDateUtility convertStringToDate:_dueDateText];
if (newDueDate == nil) {
_dueDate = [TTMDateUtility convertStringToDate:@"9999-12-31"];
_dueDateText = @"";
} else {
_dueDate = newDueDate;
}
// creation date
_creationDateText = _isCompleted ?
[_rawText firstMatch:RX(CreationDatePatternCompleted)] :
[_rawText firstMatch:RX(CreationDatePatternIncomplete)];
// Set creation date to the high date (9999-12-31) to ensure that tasks with no
// creation date are sorted after tasks with a creation date.
NSDate *newCreationDate = (_creationDateText == nil) ?
[TTMDateUtility convertStringToDate:@"9999-12-31"] :
[TTMDateUtility convertStringToDate:_creationDateText];
if (newCreationDate == nil) {
_creationDate = [TTMDateUtility convertStringToDate:@"9999-12-31"];
_creationDateText = @"";
} else {
_creationDate = newCreationDate;
}
// threshold date
_thresholdDateText = [_rawText firstMatch:RX(ThresholdDatePattern)];
// Set threshold date to the low date (1900-01-01) to ensure that tasks with no
// threshold date are properly sorted/displated when filtered.
NSDate *newThresholdDate = (_thresholdDateText == nil) ?
[TTMDateUtility convertStringToDate:@"1900-01-01"] :
[TTMDateUtility convertStringToDate:_thresholdDateText];
if (newThresholdDate == nil) {
_thresholdDate = [TTMDateUtility convertStringToDate:@"1900-01-01"];
_thresholdDateText = @"";
} else {
_thresholdDate = newThresholdDate;
}
// due state (past due, due today, not due)
_dueState = [self getDueState];
// threshold state (no threshold date, before, on, after threshold date)
_thresholdState = [self getThresholdState];
// recurrence
_isRecurring = [_rawText isMatch:RX(RecurrencePattern)];
if (_isRecurring) {
_recurrencePattern = [rawText firstMatch:RX(RecurrencePattern)];
}
// is hidden
_isHidden = [_rawText isMatch:RX(HiddenPattern)];
}
- (NSString*)rawText {
return _rawText;
}
- (NSAttributedString*)displayText:(BOOL)selected
font:(NSFont*)font
useHighlightColorsInTaskList:(BOOL)useHighlightColorsInTaskList
completedColor:(NSColor*)completedColor
dueTodayColor:(NSColor*)dueTodayColor
overdueColor:(NSColor*)overdueColor
projectColor:(NSColor*)projectColor
contextColor:(NSColor*)contextColor
tagColor:(NSColor*)tagColor
dueDateColor:(NSColor*)dueDateColor
thresholdDateColor:(NSColor*)thresholdDateColor
creationDateColor:(NSColor*)creationDateColor {
NSMutableAttributedString *as = [[NSMutableAttributedString alloc] initWithString:self.rawText];
NSRange fullStringRange = NSMakeRange(0, [as length]);
[as beginEditing];
// Apply font to the entire string.
// This was added because applying boldface to the task priority was resetting the font
// of the priority substring to the default font.
[as addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, as.length)];
// Apply strikethrough and light gray color to completed tasks when they are displayed
// in the tableView.
if (self.isCompleted) {
[as addAttribute:NSStrikethroughStyleAttributeName
value:(NSNumber*)kCFBooleanTrue
range:fullStringRange];
[as addAttribute:NSForegroundColorAttributeName
value:[NSColor lightGrayColor]
range:fullStringRange];
return as;
}
// Apply boldface to the task priority.
if (self.isPrioritized) {
[as applyFontTraits:NSBoldFontMask range:NSMakeRange(0, 3)];
}
// Only change colors if row is not selected and user wants to see highlight colors.
if (selected || !useHighlightColorsInTaskList) {
return as;
}
// Color due texts.
if (self.dueState == DueToday) {
[as applyColorToFullStringRange:dueTodayColor];
}
// Color overdue texts.
if (self.dueState == Overdue) {
[as applyColorToFullStringRange:overdueColor];
}
// Color projects.
[as applyColor:projectColor toRegexPatternMatches:ProjectPattern];
// Color contexts.
[as applyColor:contextColor toRegexPatternMatches:ContextPattern];
// Color tags.
[as applyColor:tagColor toRegexPatternMatches:TagPattern];
// Color due dates.
[as applyColor:dueDateColor toRegexPatternMatches:FullDueDatePatternBeginning];
[as applyColor:dueDateColor toRegexPatternMatches:FullDueDatePatternMiddleOrEnd];
// Color threshold dates.
[as applyColor:thresholdDateColor toRegexPatternMatches:FullThresholdDatePatternBeginning];
[as applyColor:thresholdDateColor toRegexPatternMatches:FullThresholdDatePatternMiddleOrEnd];
// Color creation dates (incomplete tasks only).
[as applyColor:creationDateColor toRegexPatternMatches:CreationDatePatternIncomplete];
[as endEditing];
return [as copy];
}
#pragma mark - Append and Prepend Methods
- (void)appendText:(NSString*)textToAppend {
if (self.isBlank) {
self.rawText = textToAppend;
return;
}
self.rawText = [self.rawText stringByAppendingFormat:@"%c%@", ' ', textToAppend];
}
- (void)prependText:(NSString*)textToPrepend {
if (self.isBlank) {
self.rawText = textToPrepend;
return;
}
NSUInteger insertionIndex;
if (self.isCompleted && [self.creationDateText length] > 0) {
// For completed tasks with creation date, prepend text after the completion date and creation date
insertionIndex = 24;
} else if (self.isCompleted && [self.creationDateText length] == 0) {
// For completed tasks with no creation date, prepend text after the completion date
insertionIndex = 13;
} else if (self.isPrioritized && [self.creationDateText length] > 0) {
// For incomplete tasks with a creation date, prepend text after priority and creation date.
insertionIndex = 15;
} else if (self.isPrioritized && [self.creationDateText length] == 0) {
// For incomplete tasks with a priority and no creation date, prepend text after priority.
insertionIndex = 4;
} else if ([self.creationDateText length] > 0) {
// For incomplete tasks with a creation date, prepend text after creation date.
insertionIndex = 11;
} else {
// For all other types of tasks, prepend text to the beginning of the task.
insertionIndex = 0;
}
if (insertionIndex == 0)
{
self.rawText = [NSString stringWithFormat:@"%@%@%@", textToPrepend, @" ", self.rawText];
return;
}
NSString *rawTextPrefix = [self.rawText substringWithRange:NSMakeRange(0, insertionIndex - 1)];
NSString *rawTextRemainder = [self.rawText substringFromIndex:insertionIndex];
NSArray *rawTextComponents = @[rawTextPrefix, textToPrepend, rawTextRemainder];
self.RawText = [rawTextComponents componentsJoinedByString:@" "];
// NSString *separator = @" ";
// NSString *rawTextRemainder = self.rawText;
// NSArray *stringComponents = nil;
// NSString *trimmedPriorityText = [self.fullPriorityText substringToIndex:3];
//
// if (self.isPrioritized && self.creationDateText != nil) {
// rawTextRemainder = [self.rawText substringFromIndex:15];
// stringComponents = @[trimmedPriorityText, self.creationDateText,
// textToPrepend, rawTextRemainder ];
// } else if (self.isPrioritized && self.creationDateText == nil) {
// rawTextRemainder = [self.rawText substringFromIndex:4];
// stringComponents = @[trimmedPriorityText, textToPrepend, rawTextRemainder];
// } else if (self.creationDateText != nil) {
// rawTextRemainder = [self.rawText substringFromIndex:11];
// stringComponents = @[self.creationDateText, textToPrepend, rawTextRemainder];
// } else {
// rawTextRemainder = self.rawText;
// stringComponents = @[textToPrepend, rawTextRemainder];
// }
// self.rawText = [stringComponents componentsJoinedByString:separator];
}
#pragma Find/replace Method
- (void)replaceText:(NSString*)textToReplace withText:(NSString*)replacementText {
self.rawText = [self.rawText stringByReplacingOccurrencesOfString:textToReplace
withString:replacementText];
}
#pragma mark - Due/Not Due Method
- (TTMDueState)getDueState {
// tasks with no due dates
if (nil == _dueDateText ||
([_dueDate isEqualToDate:[TTMDateUtility convertStringToDate:@"9999-12-31"]] &&
[_dueDateText isEqualToString:@""])) {
return NoDueDate;
}
// If there is a due date, compare it to today's date to determine
// if the task is overdue, not due, or due today.
NSDate *todaysDate = [TTMDateUtility today];
NSInteger interval = [[[NSCalendar currentCalendar] components:NSCalendarUnitDay
fromDate:todaysDate
toDate:self.dueDate
options:0] day];
if (interval < 0) {
return Overdue;
} else if (interval > 0) {
return NotDue;
} else {
return DueToday;
}
}
#pragma mark - Threshold Date Methods
- (void)setThresholdDate:(NSDate *)thresholdDate {
NSString *newThresholdDateText = [TTMDateUtility convertDateToString:thresholdDate];
// If the item has a threshold date, exchange the current threshold date with the new.
// Else if the item does not have a threshold date, append the new threshold date to the task.
self.rawText = (self.thresholdDateText != nil) ?
[self.rawText replace:RX(ThresholdDatePattern) with:newThresholdDateText] :
[self.rawText stringByAppendingFormat:@" t:%@", newThresholdDateText];
}
- (void)removeThresholdDate {
// Blank and tasks without a threshold date do not get updated.
if (self.isBlank || !self.thresholdDate) {
return;
}
NSString *newRawText = [self.rawText replace:RX(FullThresholdDatePatternBeginning) with:@""];
self.rawText = [newRawText replace:RX(FullThresholdDatePatternMiddleOrEnd) with:@""];
}
- (void)incrementThresholdDate:(NSInteger)days {
// Blank tasks don't get updated threshold dates.
if (self.isBlank) {
return;
}
if (days == 0) {
return;
}
// Get threshold date of the selected task.
// If the selected task doesn't have a threshold date, use today as the due date.
NSDate *oldThresholdDate = (self.thresholdDateText != nil) ?
self.thresholdDate :
[TTMDateUtility today];
// Add days to that date to create the new due date.
NSDate *newThresholdDate = [TTMDateUtility addDays:days toDate:oldThresholdDate];
self.thresholdDate = newThresholdDate;
}
- (void)decrementThresholdDate:(NSInteger)days {
[self incrementThresholdDate:(-1 * days)];
}
- (TTMThresholdState)getThresholdState {
if (_thresholdDateText == nil) {
return NoThresholdDate;
}
// If there is a threshold date, compare it to today's date to determine
// if the task is overdue, not due, or due today.
NSDate *todaysDate = [TTMDateUtility today];
NSInteger interval = [[[NSCalendar currentCalendar] components:NSCalendarUnitDay
fromDate:todaysDate
toDate:self.thresholdDate
options:0] day];
if (interval < 0) {
return ThresholdBeforeToday;
} else if (interval > 0) {
return ThresholdAfterToday;
} else {
return ThresholdIsToday;
}
}
#pragma mark - Priority Methods
- (void)setPriority:(unichar)priority {
// Blanks and completed tasks don't get priorities.
if (self.isBlank || self.isCompleted) {
return;
}
// Test whether priority parameter is a valid character [A-Z].
NSCharacterSet *letters = [NSCharacterSet uppercaseLetterCharacterSet];
if (![letters characterIsMember:priority]) {
return;
}
// If there is a priority, find it and replace it with the new priority.
// If there is no priority, prepend it to the beginning of rawText
// and update all class properties.
if (self.isPrioritized) {
NSRange oldPriority = [self.rawText rangeOfString:self.fullPriorityText];
if (NSNotFound != oldPriority.location) {
self.rawText = [self.rawText stringByReplacingCharactersInRange:oldPriority
withString:[NSString stringWithFormat:
@"%c%c%c%c", '(', priority, ')', ' ']];
}
} else {
self.rawText = [NSString stringWithFormat:@"%c%c%c %@", '(', priority, ')', self.rawText];
}
}
- (void)increasePriority {
// Blank and completed tasks don't get priorities
if (self.isBlank || self.isCompleted) {
return;
}
// Non-prioritized tasks automatically get the top priority
if (!self.isPrioritized) {
return [self setPriority:'A'];
}
// There is no priority greater than 'A'.
if (self.priority == 'A') {
return;
}
// increase priority of task (e.g. 'B' - 1 = 'A')
self.priority = self.priority - 1;
}
- (void)decreasePriority {
// Blank and completed tasks don't get priorities
if (self.isBlank || self.isCompleted) {
return;
}
// There is no priority less than 'Z'.
if (self.priority == 'Z') {
return;
}
// non-prioritized tasks automatically get the top priority
if (!self.isPrioritized) {
[self setPriority:'A'];
return;
}
// decrease priority of task (e.g. 'A' + 1 = 'B')
self.priority = self.priority + 1;
}
- (void)removePriority {
// Blank, completed, and non-prioritized tasks don't have priorities.
if (self.isBlank || self.isCompleted || !self.isPrioritized) {
return;
}
// Remove the priority substring and update all class properties.
self.rawText = [RX(PriorityTextPattern) replace:self.rawText with:@""];
}
#pragma mark - Completion Methods
- (void)markComplete {
// Completed tasks don't need to be completed again. Blank tasks can't be completed.
if (self.isBlank || self.isCompleted) {
return;
}
// Build new task rawText by removing priority and prepending "x" and today's date.
// Remove priority if it exists.
NSString *rawTextWithoutPriority = (self.isPrioritized) ?
[self.rawText replace:RX(PriorityTextPattern) with:@""] :
self.rawText;
// Prepend the new raw task string with "x yyyy-MM-dd " (note the trailing space),
// with today's date as "yyyy-MM-dd".
NSString *newRawText = [NSString stringWithFormat:@"%@%c%@%c%@", @"x", ' ',
[TTMDateUtility todayAsString], ' ', rawTextWithoutPriority];
// Update the task's raw text.
self.rawText = newRawText;
}
- (void)markIncomplete {
// Incomplete tasks don't need to be marked incomplete again.
// Blank tasks can't be marked incompleted.
if (self.isBlank || !self.isCompleted) {
return;
}
// Remove the completed task prepended substring and update all class properties.
self.rawText = [RX(CompletedPattern) replace:self.rawText with:@""];
}
- (void)toggleCompletionStatus {
if (self.isCompleted) {
[self markIncomplete];
} else {
[self markComplete];
}
}
# pragma mark - Postpone and Set Due Date Methods
- (void)postponeTask:(NSInteger)daysToPostpone {
// Blank and completed tasks don't get postponed.
if (self.isBlank || self.isCompleted) {
return;
}
if (daysToPostpone == 0) {
return;
}
// Get due date of the selected task.
// If the selected task doesn't have a due date, use today as the due date.
NSDate *oldDueDate = (self.dueDateText != nil) ? self.dueDate : [TTMDateUtility today];
// Add days to that date to create the new due date.
NSDate *newDueDate = [TTMDateUtility addDays:daysToPostpone toDate:oldDueDate];
self.dueDate = newDueDate;
}
- (void)incrementDueDate:(NSInteger)days {
[self postponeTask:days];
}
- (void)decrementDueDate:(NSInteger)days {
[self postponeTask:(-1 * days)];
}
- (void)setDueDate:(NSDate *)dueDate {
// Blank tasks don't get due dates.
if (self.isBlank) {
return;
}
NSString *newDueDateText = [TTMDateUtility convertDateToString:dueDate];
// If the item has a due date, exchange the current due date with the new.
// Else if the item does not have a due date, append the new due date to the task.
self.rawText = (self.dueDateText != nil) ?
[self.rawText replace:RX(DueDatePattern) with:newDueDateText] :
[self.rawText stringByAppendingFormat:@" due:%@", newDueDateText];
}
- (void)removeDueDate {
// Blank and tasks without a due date do not get updated.
if (self.isBlank || !self.dueDate) {
return;
}
NSString *newRawText = [self.rawText replace:RX(FullDueDatePatternBeginning) with:@""];
self.rawText = [newRawText replace:RX(FullDueDatePatternMiddleOrEnd) with:@""];
}
#pragma mark - NSCopying Methods
- (TTMTask*)copyWithZone:(NSZone *)zone {
TTMTask *copy = [[self class] allocWithZone:zone];
if (copy) {
return [copy initWithRawText:self.rawText withTaskId:self.taskId];
}
return copy;
}
#pragma mark - IsEqual Methods
-(BOOL)isEqual:(id)object {
if (object == self) {
return YES;
}
if (!object || ![object isKindOfClass:[self class]]) {
return NO;
}
return [self isEqualToTTMTask:object];
}
- (BOOL)isEqualToTTMTask:(TTMTask*)otherTask {
if (!otherTask) {
return NO;
}
BOOL haveEqualRawText = [self.rawText isEqualToString:otherTask.rawText];
BOOL haveEqualTaskId = (self.taskId == otherTask.taskId);
return haveEqualRawText && haveEqualTaskId;
}
- (NSUInteger)hash {
return [self.rawText hash] ^ [@(self.taskId) hash];
}
#pragma mark - Recurrence Methods
- (TTMTask*)newRecurringTask {
if (!self.isRecurring) {
return nil;
}
TTMTask *newTask = [self copy];
[newTask advanceDueDateBasedOnReccurencePattern:[TTMDateUtility today]];
if (_thresholdDateText != nil) {
NSInteger numberOfDaysThresholdDateIsBeforeDueDate = 0;
if (_dueDateText == nil) {
numberOfDaysThresholdDateIsBeforeDueDate = [TTMDateUtility daysBetweenDate:self.thresholdDate andEndDate:[TTMDateUtility today]];
} else if (_dueDateText != nil && _thresholdDateText != nil) {
numberOfDaysThresholdDateIsBeforeDueDate = [TTMDateUtility daysBetweenDate:self.thresholdDate andEndDate:self.dueDate];
}
if (numberOfDaysThresholdDateIsBeforeDueDate < 0) {
numberOfDaysThresholdDateIsBeforeDueDate = 0;
}
[newTask setThresholdDateBasedDaysBetweenThresholdDateAndDueDate:numberOfDaysThresholdDateIsBeforeDueDate];
}
return newTask;
}
- (void)advanceDueDateBasedOnReccurencePattern:(NSDate*)completionDate {
NSDate *oldDueDate;
if (_dueDateText == nil || ![self recurrencePatternIsStrict]) {
oldDueDate = completionDate;
} else {
oldDueDate = self.dueDate;
}
NSDate *newDueDate = [self relativeDateBasedOnRecurrencePattern:oldDueDate];
[self setDueDate:newDueDate];
}
- (void)setThresholdDateBasedDaysBetweenThresholdDateAndDueDate:(NSInteger)daysBetweenThresholdAndDueDates {
NSInteger dateAdjustment = (daysBetweenThresholdAndDueDates > 0) ? -1 * daysBetweenThresholdAndDueDates : 0;
NSDate* newThresholdDate = [self.dueDate advanceDateByNumberOfCalendarUnits:dateAdjustment calendarUnit:NSCalendarUnitDay];
[self setThresholdDate:newThresholdDate];
}
- (BOOL)recurrencePatternIsStrict {
return [self.recurrencePattern hasPrefix:@"+"];
}
- (NSCalendarUnit)calendarUnitFromRecurrencePattern {
if (!self.recurrencePattern) {
return NSCalendarUnitEra; // not a real return value
}
NSString *lastChar = [[self.recurrencePattern uppercaseString] substringFromIndex:self.recurrencePattern.length - 1];
if ([lastChar isEqualToString:@"D"]) {
return NSCalendarUnitDay;
}
if ([lastChar isEqualToString:@"W"]) {
return NSCalendarUnitWeekOfYear;
}
if ([lastChar isEqualToString:@"M"]) {
return NSCalendarUnitMonth;
}
if ([lastChar isEqualToString:@"Y"]) {
return NSCalendarUnitYear;
}
if ([lastChar isEqualToString:@"B"]) {
return NSCalendarUnitWeekday;
}
return NSCalendarUnitEra; // not a real return value
}
- (NSUInteger)numberOfCalendarUnitsFromRecurrencePattern {
NSUInteger rangeStart = [self recurrencePatternIsStrict] ? 1 : 0;
NSUInteger rangeEnd = self.recurrencePattern.length - 1;
NSRange rng = NSMakeRange(rangeStart, rangeEnd);
return [[self.recurrencePattern substringWithRange:rng] integerValue];
}
- (NSDate*)relativeDateBasedOnRecurrencePattern:(NSDate*)date {
NSCalendarUnit calendarUnit = [self calendarUnitFromRecurrencePattern];
if (calendarUnit == NSCalendarUnitEra) {
return nil;
}
NSInteger numberOfCalendarUnits = [self numberOfCalendarUnitsFromRecurrencePattern];
if (calendarUnit == NSCalendarUnitWeekday) {
return [date advanceDateByWeekdays:numberOfCalendarUnits];
} else {
return [date advanceDateByNumberOfCalendarUnits:numberOfCalendarUnits calendarUnit:calendarUnit];
}
}
- (void)removeCreationDate {
// Blank and tasks without a threshold date do not get updated.
if (self.isBlank || !self.creationDate) {
return;
}
NSString *newRawText;
if (!self.isCompleted) {
newRawText = [self.rawText replace:RX(CreationDatePatternIncompletePlusTrailingSpace) with:@""];
} else {
newRawText = [self.rawText replace:RX(CreationDatePatternCompletedPlusTrailingSpace) with:@""];
}
self.rawText = newRawText;
}
@end
================================================
FILE: TodoTxtMac/TTMTasklistMetadata.h
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
@class TTMTask;
@interface TTMTasklistMetadata : NSObject
#pragma mark - Properties
@property (nonatomic) NSMutableSet *projectsSet;
@property (nonatomic) NSMutableSet *contextsSet;
@property (nonatomic) NSMutableSet *prioritiesSet;
@property (nonatomic) NSArray *contextsArray;
@property (nonatomic) NSArray *projectsArray;
@property (nonatomic) NSArray *prioritiesArray;
@property (nonatomic) NSMutableDictionary *projectTaskCounts;
@property (nonatomic) NSMutableDictionary *contextTaskCounts;
@property (nonatomic) NSMutableDictionary *priorityTaskCounts;
@property (readonly) NSString *projects;
@property (readonly) NSString *contexts;
@property (nonatomic) NSInteger allTaskCount;
@property (nonatomic) NSInteger completedTaskCount;
@property (nonatomic) NSInteger incompleteTaskCount;
@property (nonatomic) NSInteger dueTodayTaskCount;
@property (nonatomic) NSInteger overdueTaskCount;
@property (nonatomic) NSInteger notDueTaskCount;
@property (nonatomic) NSInteger noDueDateTaskCount;
@property (nonatomic) NSInteger projectsCount;
@property (nonatomic) NSInteger contextsCount;
@property (nonatomic) NSInteger prioritiesCount;
@property (nonatomic) NSInteger hiddenCount;
/*!
* @method updateMetadataFromTaskArray:
* @abstract Generates metadata from a list of tasks.
* @param taskArray An array of TTMTask objects.
*/
- (void)updateMetadataFromTaskArray:(NSArray*)taskArray;
/*!
* @method initialize:
* @abstract Initializes the class. Called in method updateMetadataFromTaskArray:.
*/
- (void)initialize;
/*!
* @method initialize:
* @abstract Helper function to populate task counts in the properties projectTaskCounts,
* contextTaskCounts, and priorityTaskCounts. Called in method updateMetadataFromTaskArray:.
*/
- (void)incrementCountsInDictionary:(NSMutableDictionary*)dictionary FromArray:(NSArray*)array;
@end
================================================
FILE: TodoTxtMac/TTMTasklistMetadata.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import "TTMTasklistMetadata.h"
#import "TTMTask.h"
@implementation TTMTasklistMetadata
- (void)updateMetadataFromTaskArray:(NSArray*)taskArray {
[self initialize];
for (TTMTask *task in taskArray) {
// update task counts
self.allTaskCount++;
self.completedTaskCount += (task.isCompleted ? 1 : 0);
self.incompleteTaskCount += (task.isCompleted ? 0 : 1);
self.dueTodayTaskCount += (task.dueState == DueToday ? 1 : 0);
self.overdueTaskCount += (task.dueState == Overdue ? 1 : 0);
self.notDueTaskCount += (task.dueState == NotDue ? 1 : 0);
self.noDueDateTaskCount += (task.dueState == NoDueDate ? 1 : 0);
self.hiddenCount += (task.isHidden ? 1 : 0);
// update task counts by project and context
[self incrementCountsInDictionary:self.projectTaskCounts FromArray:task.projectsArray];
[self incrementCountsInDictionary:self.contextTaskCounts FromArray:task.contextsArray];
// add all projects and contexts to sets
[self.projectsSet addObjectsFromArray:task.projectsArray];
[self.contextsSet addObjectsFromArray:task.contextsArray];
// update task count by priority, and add priority to set
if (task.priorityText != nil) {
[self incrementCountsInDictionary:self.priorityTaskCounts
FromArray:@[task.priorityText]];
[self.prioritiesSet addObject:task.priorityText];
}
}
// Convert the sets to case-insensitive-sorted arrays.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]
initWithKey:@""
ascending:YES
selector:@selector(caseInsensitiveCompare:)];
NSArray *sortDescriptorArray = @[sortDescriptor];
self.projectsArray = [self.projectsSet sortedArrayUsingDescriptors:sortDescriptorArray];
self.contextsArray = [self.contextsSet sortedArrayUsingDescriptors:sortDescriptorArray];
self.prioritiesArray = [self.prioritiesSet sortedArrayUsingDescriptors:sortDescriptorArray];
// update counts of projects, contexts, and priorities
self.projectsCount = [self.projectsSet count];
self.contextsCount = [self.contextsSet count];
self.prioritiesCount = [self.prioritiesSet count];
}
- (void)initialize {
self.allTaskCount = 0;
self.completedTaskCount = 0;
self.incompleteTaskCount = 0;
self.dueTodayTaskCount = 0;
self.overdueTaskCount = 0;
self.notDueTaskCount = 0;
self.noDueDateTaskCount = 0;
self.hiddenCount = 0;
self.projectTaskCounts = [NSMutableDictionary dictionary];
self.contextTaskCounts = [NSMutableDictionary dictionary];
self.priorityTaskCounts = [NSMutableDictionary dictionary];
self.projectsSet = [NSMutableSet set];
self.contextsSet = [NSMutableSet set];
self.prioritiesSet = [NSMutableSet set];
self.projectsArray = [NSArray array];
self.contextsArray = [NSArray array];
self.prioritiesArray = [NSArray array];
self.projectsCount = 0;
self.contextsCount = 0;
self.prioritiesCount = 0;
}
- (void)incrementCountsInDictionary:(NSMutableDictionary*)dictionary FromArray:(NSArray*)array {
for (NSString *key in array) {
if (dictionary[key] == nil) {
dictionary[key] = @1;
} else {
dictionary[key] = @([dictionary[key] integerValue] + 1);
}
}
}
- (NSString*)projects {
return [self.projectsArray componentsJoinedByString:@"\n"];
}
- (NSString*)contexts {
return [self.contextsArray componentsJoinedByString:@"\n"];
}
@end
================================================
FILE: TodoTxtMac/TTMTasklistMetadata.xib
================================================
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
================================================
FILE: TodoTxtMac/TodoTxtMac-Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleDocumentTypes
CFBundleTypeExtensions
txt
CFBundleTypeIconFile
CFBundleTypeName
DocumentType
CFBundleTypeOSTypes
????
CFBundleTypeRole
Editor
NSDocumentClass
TTMDocument
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleIconFile
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
${PRODUCT_NAME}
CFBundlePackageType
APPL
CFBundleShortVersionString
2.4.0
CFBundleSignature
????
CFBundleVersion
2032
LSApplicationCategoryType
public.app-category.productivity
LSMinimumSystemVersion
${MACOSX_DEPLOYMENT_TARGET}
NSHumanReadableCopyright
Copyright © 2014-2016 Michael Descy. Dual licensed under the GPL and MIT License.
NSMainNibFile
MainMenu
NSPrincipalClass
NSApplication
SU
SUAllowsAutomaticUpdates
SUFeedURL
https://mjdescy.github.io/TodoTxtMac/todotxtmac-appcast.xml
SUPublicDSAKeyFile
dsa_pub.pem
SUShowReleaseNotes
================================================
FILE: TodoTxtMac/TodoTxtMac-Prefix.pch
================================================
//
// Prefix header
//
// The contents of this file are implicitly included at the beginning of every source file.
//
#ifdef __OBJC__
#import
#endif
================================================
FILE: TodoTxtMac/TodoTxtMac.entitlements
================================================
================================================
FILE: TodoTxtMac/en.lproj/Credits.rtf
================================================
{\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;\f2\fnil\fcharset0 Consolas;
}
{\colortbl;\red255\green255\blue255;}
\vieww9600\viewh8400\viewkind0
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\partightenfactor0
\f0\b\fs24 \cf0 TodoTxtMac:\
A Todo.txt todo manager for Mac OS X
\b0 \
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\partightenfactor0
\cf0 \
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\partightenfactor0
\cf0 Copyright \'a9 2014-2016 Michael Descy\
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\partightenfactor0
\cf0 \
This application is dual-licensed under the GNU General Public License and the MIT License. See below for full license information. Source code is available at {\field{\*\fldinst{HYPERLINK "https://github.com/mjdescy/TodoTxtMac"}}{\fldrslt https://github.com/mjdescy/TodoTxtMac}}.\
\
\
\
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\partightenfactor0
\b \cf0 Thanks
\b0 \
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
\cf0 Thanks to Gina Trapani who created the {\field{\*\fldinst{HYPERLINK "http://www.todotxt.com"}}{\fldrslt Todo.txt}} format and the community of developers who created the command line tools and iOS/Android apps.\
\
Thanks to Ben Hughes whose Windows application {\field{\*\fldinst{HYPERLINK "http://benrhughes.github.io/todotxt.net/"}}{\fldrslt Todotxt.net}} formed the basis of this application's design and feature set. Todotxt.net is a fantastic program and did not have an analog on the Mac. After starting my application, I contributed some patches to todotxt.net and am happy to be a contributor on such a great project.\
\
Thanks to Josh Wright <@BendyTree> for his {\field{\*\fldinst{HYPERLINK "https://github.com/bendytree/Objective-C-RegEx-Categories"}}{\fldrslt RegExCategories}} library.\
\
Thanks to Sam Daitzman <@sdaitzman> for the application icon.\
\
Thanks to Andy Matuschak and the other contributors for the {\field{\*\fldinst{HYPERLINK "http://sparkle.andymatuschak.org/"}}{\fldrslt Sparkle framework}}.\
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\partightenfactor0
\cf0 \
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\partightenfactor0
\b \cf0 \
TodoTxtMac License
\b0 \
\
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\partightenfactor0
\f1 \cf0 GNU General Public License\
\
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\
\
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\
\
You should have received a copy of the GNU General Public License along with this program. If not, see .\
\
\
The MIT License (MIT)\
\
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\
\
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\
\
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\f0 \
\
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\partightenfactor0
\b \cf0 Sparkle License
\b0 \
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
\cf0 \
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
\f1 \cf0 Copyright (c) 2006 Andy Matuschak\
\
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\
\
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\
\
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\
\
=================\
EXTERNAL LICENSES\
=================\
\
License for bspatch.c and bsdiff.c, from bsdiff 4.3 (:\
/*-\
\'a0* Copyright 2003-2005 Colin Percival\
\'a0* All rights reserved\
\'a0*\
\'a0* Redistribution and use in source and binary forms, with or without\
\'a0* modification, are permitted providing that the following conditions \
\'a0* are met:\
\'a0* 1. Redistributions of source code must retain the above copyright\
\'a0* notice, this list of conditions and the following disclaimer.\
\'a0* 2. Redistributions in binary form must reproduce the above copyright\
\'a0* notice, this list of conditions and the following disclaimer in the\
\'a0* documentation and/or other materials provided with the distribution.\
\'a0*\
\'a0* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\
\'a0* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\
\'a0* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\
\'a0* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\
\'a0* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\
\'a0* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\
\'a0* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\
\'a0* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\
\'a0* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\
\'a0* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\
\'a0* POSSIBILITY OF SUCH DAMAGE.\
\'a0*/
\f2 \
}
================================================
FILE: TodoTxtMac/en.lproj/InfoPlist.strings
================================================
/* Localized versions of Info.plist keys */
================================================
FILE: TodoTxtMac/main.m
================================================
//
// main.m
// TodoTxtMac
//
// Created by Michael Descy on 2/18/14.
// Copyright (c) 2014 Michael Descy. All rights reserved.
//
#import
int main(int argc, const char * argv[])
{
return NSApplicationMain(argc, argv);
}
================================================
FILE: TodoTxtMac.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
00165B2618DBD1EC00E137B8 /* TTMFiltersController.m in Sources */ = {isa = PBXBuildFile; fileRef = 00165B2518DBD1EC00E137B8 /* TTMFiltersController.m */; };
002218D81AA0D80800D6F3A0 /* TTMTask_Init_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 002218D71AA0D80800D6F3A0 /* TTMTask_Init_UnitTests.m */; };
002218DA1AA0EB3200D6F3A0 /* TTMTask_IsCompleted_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 002218D91AA0EB3200D6F3A0 /* TTMTask_IsCompleted_UnitTests.m */; };
002218DC1AA0F48D00D6F3A0 /* TTMTask_DueDate_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 002218DB1AA0F48D00D6F3A0 /* TTMTask_DueDate_UnitTests.m */; };
002218DE1AA107F600D6F3A0 /* TTMTask_CompletionDate_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 002218DD1AA107F600D6F3A0 /* TTMTask_CompletionDate_UnitTests.m */; };
002218E01AA1387900D6F3A0 /* TTMTask_ThresholdDate_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 002218DF1AA1387900D6F3A0 /* TTMTask_ThresholdDate_UnitTests.m */; };
002218E21AA139EB00D6F3A0 /* TTMTask_CreationDate_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 002218E11AA139EB00D6F3A0 /* TTMTask_CreationDate_UnitTests.m */; };
002218E41AA1704B00D6F3A0 /* TTMTask_DueState_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 002218E31AA1704B00D6F3A0 /* TTMTask_DueState_UnitTests.m */; };
002218E61AA173D100D6F3A0 /* TTMTask_ThresholdState_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 002218E51AA173D100D6F3A0 /* TTMTask_ThresholdState_UnitTests.m */; };
002218E81AA179CD00D6F3A0 /* TTMTask_MarkComplete_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 002218E71AA179CD00D6F3A0 /* TTMTask_MarkComplete_UnitTests.m */; };
002218EA1AA17B9B00D6F3A0 /* TTMTask_MarkIncomplete_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 002218E91AA17B9B00D6F3A0 /* TTMTask_MarkIncomplete_UnitTests.m */; };
002EAE5918DBD24C008E7517 /* TTMAppController.m in Sources */ = {isa = PBXBuildFile; fileRef = 002EAE5818DBD24C008E7517 /* TTMAppController.m */; };
002EAE5E18DCAE5C008E7517 /* TTMFilterPredicates.m in Sources */ = {isa = PBXBuildFile; fileRef = 002EAE5D18DCAE5C008E7517 /* TTMFilterPredicates.m */; };
00308E161C90FD260007681C /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 00308E131C90FD120007681C /* Sparkle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
00308E171C90FD390007681C /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00308E131C90FD120007681C /* Sparkle.framework */; };
003647E1193D562900FDF67A /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = 003647E0193D562900FDF67A /* dsa_pub.pem */; };
003F958F1AA2948D00A1FF47 /* TTMTask_ToggleCompletion_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F958E1AA2948D00A1FF47 /* TTMTask_ToggleCompletion_UnitTests.m */; };
003F95911AA2965600A1FF47 /* TTMDateUtility_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95901AA2965600A1FF47 /* TTMDateUtility_UnitTests.m */; };
003F95931AA296F300A1FF47 /* TTMTask_Priority_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95921AA296F300A1FF47 /* TTMTask_Priority_UnitTests.m */; };
003F95951AA2A35A00A1FF47 /* TTMTask_Projects_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95941AA2A35A00A1FF47 /* TTMTask_Projects_UnitTests.m */; };
003F95971AA2A44800A1FF47 /* TTMTask_Contexts_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95961AA2A44800A1FF47 /* TTMTask_Contexts_UnitTests.m */; };
003F95991AA2A64100A1FF47 /* TTMTask_SetDueDate_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95981AA2A64100A1FF47 /* TTMTask_SetDueDate_UnitTests.m */; };
003F959B1AA2B7A600A1FF47 /* TTMTask_RemoveDueDate_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F959A1AA2B7A600A1FF47 /* TTMTask_RemoveDueDate_UnitTests.m */; };
003F959E1AA2C42700A1FF47 /* NSMutableAttributableString+ColorRegExMatches.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F959D1AA2C42700A1FF47 /* NSMutableAttributableString+ColorRegExMatches.m */; };
003F95A01AA3F04C00A1FF47 /* TTMTask_Postpone_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F959F1AA3F04C00A1FF47 /* TTMTask_Postpone_UnitTests.m */; };
003F95A21AA3F41400A1FF47 /* TTMTask_IncreasePriority_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95A11AA3F41400A1FF47 /* TTMTask_IncreasePriority_UnitTests.m */; };
003F95A41AA3F5DC00A1FF47 /* TTMTask_DecreasePriority_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95A31AA3F5DC00A1FF47 /* TTMTask_DecreasePriority_UnitTests.m */; };
003F95A61AA3F68200A1FF47 /* TTMTask_RemovePriority_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95A51AA3F68200A1FF47 /* TTMTask_RemovePriority_UnitTests.m */; };
003F95A81AA3F83D00A1FF47 /* TTMTask_SetThresholdDate_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95A71AA3F83D00A1FF47 /* TTMTask_SetThresholdDate_UnitTests.m */; };
003F95AA1AA3F9C700A1FF47 /* TTMTask_IncrementThresholdDate_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95A91AA3F9C700A1FF47 /* TTMTask_IncrementThresholdDate_UnitTests.m */; };
003F95AC1AA3FBDA00A1FF47 /* TTMTask_DecrementThresholdDate_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95AB1AA3FBDA00A1FF47 /* TTMTask_DecrementThresholdDate_UnitTests.m */; };
003F95AE1AA3FC9600A1FF47 /* TTMTask_RemoveThresholdDate_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95AD1AA3FC9600A1FF47 /* TTMTask_RemoveThresholdDate_UnitTests.m */; };
003F95B01AA3FE4400A1FF47 /* TTMTask_AppendText_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95AF1AA3FE4400A1FF47 /* TTMTask_AppendText_UnitTests.m */; };
003F95B21AA4016200A1FF47 /* TTMTask_PrependText_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95B11AA4016200A1FF47 /* TTMTask_PrependText_UnitTests.m */; };
003F95B41AA40EC700A1FF47 /* TTMTask_IncrementDueDate_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95B31AA40EC700A1FF47 /* TTMTask_IncrementDueDate_UnitTests.m */; };
003F95B61AA40FB400A1FF47 /* TTMTask_DecrementDueDate_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 003F95B51AA40FB400A1FF47 /* TTMTask_DecrementDueDate_UnitTests.m */; };
0050D6841996AA38008F349B /* TTMTasklistMetadata_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0050D6831996AA38008F349B /* TTMTasklistMetadata_UnitTests.m */; };
006062D818EC6B0800D147F2 /* NSUserDefaults+myColorSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 006062D718EC6B0800D147F2 /* NSUserDefaults+myColorSupport.m */; };
0064E6441C9CEE6600B9A6C0 /* NSDate+RelativeDates.m in Sources */ = {isa = PBXBuildFile; fileRef = 0064E6431C9CEE6600B9A6C0 /* NSDate+RelativeDates.m */; };
006B26461A81C82D00B0E47A /* TTMFindReplace.xib in Resources */ = {isa = PBXBuildFile; fileRef = 006B26451A81C82D00B0E47A /* TTMFindReplace.xib */; };
006BA79E19DB9CFD00C8F408 /* TTMTasklistMetadata.xib in Resources */ = {isa = PBXBuildFile; fileRef = 006BA79D19DB9CFD00C8F408 /* TTMTasklistMetadata.xib */; };
007B835F1A5A415300A4D5F7 /* TTMPredicateEditorThresholdRowTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = 007B835E1A5A415300A4D5F7 /* TTMPredicateEditorThresholdRowTemplate.m */; };
0080EAA518D3E96C0014DDD1 /* TTMPreferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0080EAA418D3E96C0014DDD1 /* TTMPreferences.xib */; };
0086C98518B54F1A00A427AA /* TTMTableViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0086C98418B54F1A00A427AA /* TTMTableViewDelegate.m */; };
00930EAA18B536B00064D41B /* RegExCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = 00930EA918B536B00064D41B /* RegExCategories.m */; };
00930EAD18B5371B0064D41B /* TTMTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 00930EAC18B5371B0064D41B /* TTMTask.m */; };
00930EB118B537C10064D41B /* TTMDateUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = 00930EB018B537C10064D41B /* TTMDateUtility.m */; };
00B4CB9C18B43E8400313DAA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00B4CB9B18B43E8400313DAA /* Cocoa.framework */; settings = {ATTRIBUTES = (Required, ); }; };
00B4CBA618B43E8400313DAA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 00B4CBA418B43E8400313DAA /* InfoPlist.strings */; };
00B4CBA818B43E8400313DAA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 00B4CBA718B43E8400313DAA /* main.m */; };
00B4CBAC18B43E8400313DAA /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 00B4CBAA18B43E8400313DAA /* Credits.rtf */; };
00B4CBAF18B43E8400313DAA /* TTMDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = 00B4CBAE18B43E8400313DAA /* TTMDocument.m */; };
00B4CBB218B43E8400313DAA /* TTMDocument.xib in Resources */ = {isa = PBXBuildFile; fileRef = 00B4CBB018B43E8400313DAA /* TTMDocument.xib */; };
00B4CBB518B43E8500313DAA /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 00B4CBB318B43E8500313DAA /* MainMenu.xib */; };
00B4CBB718B43E8500313DAA /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 00B4CBB618B43E8500313DAA /* Images.xcassets */; };
00B4CBBE18B43E8500313DAA /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00B4CBBD18B43E8500313DAA /* XCTest.framework */; };
00B4CBBF18B43E8500313DAA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00B4CB9B18B43E8400313DAA /* Cocoa.framework */; };
00B4CBC718B43E8500313DAA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 00B4CBC518B43E8500313DAA /* InfoPlist.strings */; };
00B4CBC918B43E8500313DAA /* TTMTask_ReplaceText_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00B4CBC818B43E8500313DAA /* TTMTask_ReplaceText_UnitTests.m */; };
00B8C82518E48FFF008D9E48 /* TTMFieldEditor.m in Sources */ = {isa = PBXBuildFile; fileRef = 00B8C82418E48FFF008D9E48 /* TTMFieldEditor.m */; };
00D102B61991ABBE00D30237 /* TTMTasklistMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 00D102B51991ABBE00D30237 /* TTMTasklistMetadata.m */; };
00D531271CACA285007EF487 /* TTMTask_IsHidden_UnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00D531261CACA285007EF487 /* TTMTask_IsHidden_UnitTests.m */; };
00D5312A1CACC3C7007EF487 /* TTMPredicateEditorHiddenRowTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = 00D531291CACC3C7007EF487 /* TTMPredicateEditorHiddenRowTemplate.m */; };
00DA4A1D1D5BBEB600CFF2B1 /* TTMPredicateEditorTextRowTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = 00DA4A1C1D5BBEB600CFF2B1 /* TTMPredicateEditorTextRowTemplate.m */; };
00EAAB9718E0C168009CBE8C /* TTMPredicateEditorDateRowTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = 00EAAB9618E0C168009CBE8C /* TTMPredicateEditorDateRowTemplate.m */; };
00EAAB9A18E1CF79009CBE8C /* TTMPredicateEditorDueRowTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = 00EAAB9918E1CF79009CBE8C /* TTMPredicateEditorDueRowTemplate.m */; };
00EAAB9D18E1CF92009CBE8C /* TTMPredicateEditorCompletedRowTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = 00EAAB9C18E1CF92009CBE8C /* TTMPredicateEditorCompletedRowTemplate.m */; };
00EC5EA118E3BC920021242B /* TTMAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 00EC5EA018E3BC920021242B /* TTMAppDelegate.m */; };
00F3961218C6AC010002EA3F /* TTMTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 00F3961118C6AC010002EA3F /* TTMTableView.m */; };
00F811EF18D53F7300379B99 /* TTMPreferencesController.m in Sources */ = {isa = PBXBuildFile; fileRef = 00F811ED18D53F7300379B99 /* TTMPreferencesController.m */; };
00FA1D2818F1EF340066A437 /* FontNameTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 00FA1D2718F1EF340066A437 /* FontNameTransformer.m */; };
00FA1D2A18F1EF4C0066A437 /* RelativeDates.strings in Resources */ = {isa = PBXBuildFile; fileRef = 00FA1D2918F1EF4C0066A437 /* RelativeDates.strings */; };
00FB47861A733E6100F8D2B3 /* TTMDocumentStatusBarText.m in Sources */ = {isa = PBXBuildFile; fileRef = 00FB47851A733E6100F8D2B3 /* TTMDocumentStatusBarText.m */; };
00FCB2F918DB64510070BD4A /* TTMFilters.xib in Resources */ = {isa = PBXBuildFile; fileRef = 00FCB2F818DB64510070BD4A /* TTMFilters.xib */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
00B4CBC018B43E8500313DAA /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 00B4CB9018B43E8400313DAA /* Project object */;
proxyType = 1;
remoteGlobalIDString = 00B4CB9718B43E8400313DAA;
remoteInfo = TodoTxtMac;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
003647DD193D50DA00FDF67A /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
00308E161C90FD260007681C /* Sparkle.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
00165B2418DBD1EC00E137B8 /* TTMFiltersController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMFiltersController.h; sourceTree = ""; };
00165B2518DBD1EC00E137B8 /* TTMFiltersController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMFiltersController.m; sourceTree = ""; };
002218D71AA0D80800D6F3A0 /* TTMTask_Init_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_Init_UnitTests.m; sourceTree = ""; };
002218D91AA0EB3200D6F3A0 /* TTMTask_IsCompleted_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_IsCompleted_UnitTests.m; sourceTree = ""; };
002218DB1AA0F48D00D6F3A0 /* TTMTask_DueDate_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_DueDate_UnitTests.m; sourceTree = ""; };
002218DD1AA107F600D6F3A0 /* TTMTask_CompletionDate_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_CompletionDate_UnitTests.m; sourceTree = ""; };
002218DF1AA1387900D6F3A0 /* TTMTask_ThresholdDate_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_ThresholdDate_UnitTests.m; sourceTree = ""; };
002218E11AA139EB00D6F3A0 /* TTMTask_CreationDate_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_CreationDate_UnitTests.m; sourceTree = ""; };
002218E31AA1704B00D6F3A0 /* TTMTask_DueState_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_DueState_UnitTests.m; sourceTree = ""; };
002218E51AA173D100D6F3A0 /* TTMTask_ThresholdState_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_ThresholdState_UnitTests.m; sourceTree = ""; };
002218E71AA179CD00D6F3A0 /* TTMTask_MarkComplete_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_MarkComplete_UnitTests.m; sourceTree = ""; };
002218E91AA17B9B00D6F3A0 /* TTMTask_MarkIncomplete_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_MarkIncomplete_UnitTests.m; sourceTree = ""; };
002EAE5718DBD24C008E7517 /* TTMAppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMAppController.h; sourceTree = ""; };
002EAE5818DBD24C008E7517 /* TTMAppController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMAppController.m; sourceTree = ""; };
002EAE5C18DCAE5C008E7517 /* TTMFilterPredicates.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMFilterPredicates.h; sourceTree = ""; };
002EAE5D18DCAE5C008E7517 /* TTMFilterPredicates.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMFilterPredicates.m; sourceTree = ""; };
00308E131C90FD120007681C /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Sparkle.framework; sourceTree = ""; };
003647E0193D562900FDF67A /* dsa_pub.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dsa_pub.pem; sourceTree = ""; };
003F958E1AA2948D00A1FF47 /* TTMTask_ToggleCompletion_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_ToggleCompletion_UnitTests.m; sourceTree = ""; };
003F95901AA2965600A1FF47 /* TTMDateUtility_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMDateUtility_UnitTests.m; sourceTree = ""; };
003F95921AA296F300A1FF47 /* TTMTask_Priority_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_Priority_UnitTests.m; sourceTree = ""; };
003F95941AA2A35A00A1FF47 /* TTMTask_Projects_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_Projects_UnitTests.m; sourceTree = ""; };
003F95961AA2A44800A1FF47 /* TTMTask_Contexts_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_Contexts_UnitTests.m; sourceTree = ""; };
003F95981AA2A64100A1FF47 /* TTMTask_SetDueDate_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_SetDueDate_UnitTests.m; sourceTree = ""; };
003F959A1AA2B7A600A1FF47 /* TTMTask_RemoveDueDate_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_RemoveDueDate_UnitTests.m; sourceTree = ""; };
003F959C1AA2C42700A1FF47 /* NSMutableAttributableString+ColorRegExMatches.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableAttributableString+ColorRegExMatches.h"; sourceTree = ""; };
003F959D1AA2C42700A1FF47 /* NSMutableAttributableString+ColorRegExMatches.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableAttributableString+ColorRegExMatches.m"; sourceTree = ""; };
003F959F1AA3F04C00A1FF47 /* TTMTask_Postpone_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_Postpone_UnitTests.m; sourceTree = ""; };
003F95A11AA3F41400A1FF47 /* TTMTask_IncreasePriority_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_IncreasePriority_UnitTests.m; sourceTree = ""; };
003F95A31AA3F5DC00A1FF47 /* TTMTask_DecreasePriority_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_DecreasePriority_UnitTests.m; sourceTree = ""; };
003F95A51AA3F68200A1FF47 /* TTMTask_RemovePriority_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_RemovePriority_UnitTests.m; sourceTree = ""; };
003F95A71AA3F83D00A1FF47 /* TTMTask_SetThresholdDate_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_SetThresholdDate_UnitTests.m; sourceTree = ""; };
003F95A91AA3F9C700A1FF47 /* TTMTask_IncrementThresholdDate_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_IncrementThresholdDate_UnitTests.m; sourceTree = ""; };
003F95AB1AA3FBDA00A1FF47 /* TTMTask_DecrementThresholdDate_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_DecrementThresholdDate_UnitTests.m; sourceTree = ""; };
003F95AD1AA3FC9600A1FF47 /* TTMTask_RemoveThresholdDate_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_RemoveThresholdDate_UnitTests.m; sourceTree = ""; };
003F95AF1AA3FE4400A1FF47 /* TTMTask_AppendText_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_AppendText_UnitTests.m; sourceTree = ""; };
003F95B11AA4016200A1FF47 /* TTMTask_PrependText_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_PrependText_UnitTests.m; sourceTree = ""; };
003F95B31AA40EC700A1FF47 /* TTMTask_IncrementDueDate_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_IncrementDueDate_UnitTests.m; sourceTree = ""; };
003F95B51AA40FB400A1FF47 /* TTMTask_DecrementDueDate_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_DecrementDueDate_UnitTests.m; sourceTree = ""; };
0050D6831996AA38008F349B /* TTMTasklistMetadata_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTasklistMetadata_UnitTests.m; sourceTree = ""; };
006062D618EC6B0800D147F2 /* NSUserDefaults+myColorSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSUserDefaults+myColorSupport.h"; sourceTree = ""; };
006062D718EC6B0800D147F2 /* NSUserDefaults+myColorSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSUserDefaults+myColorSupport.m"; sourceTree = ""; };
0064E6421C9CEE6600B9A6C0 /* NSDate+RelativeDates.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+RelativeDates.h"; sourceTree = ""; };
0064E6431C9CEE6600B9A6C0 /* NSDate+RelativeDates.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+RelativeDates.m"; sourceTree = ""; };
006B26451A81C82D00B0E47A /* TTMFindReplace.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TTMFindReplace.xib; sourceTree = ""; };
006BA79D19DB9CFD00C8F408 /* TTMTasklistMetadata.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TTMTasklistMetadata.xib; sourceTree = ""; };
007B835D1A5A415300A4D5F7 /* TTMPredicateEditorThresholdRowTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMPredicateEditorThresholdRowTemplate.h; sourceTree = ""; };
007B835E1A5A415300A4D5F7 /* TTMPredicateEditorThresholdRowTemplate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMPredicateEditorThresholdRowTemplate.m; sourceTree = ""; };
0080EAA418D3E96C0014DDD1 /* TTMPreferences.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TTMPreferences.xib; sourceTree = ""; };
0086C98318B54F1A00A427AA /* TTMTableViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMTableViewDelegate.h; sourceTree = ""; };
0086C98418B54F1A00A427AA /* TTMTableViewDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTableViewDelegate.m; sourceTree = ""; };
00930EA818B536B00064D41B /* RegExCategories.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExCategories.h; sourceTree = ""; };
00930EA918B536B00064D41B /* RegExCategories.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RegExCategories.m; sourceTree = ""; };
00930EAB18B5371B0064D41B /* TTMTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMTask.h; sourceTree = ""; };
00930EAC18B5371B0064D41B /* TTMTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask.m; sourceTree = ""; };
00930EAF18B537C10064D41B /* TTMDateUtility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMDateUtility.h; sourceTree = ""; };
00930EB018B537C10064D41B /* TTMDateUtility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMDateUtility.m; sourceTree = ""; };
00A4E02E18D1569700CEE0A8 /* TodoTxtMac.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = TodoTxtMac.entitlements; sourceTree = ""; };
00B4CB9818B43E8400313DAA /* TodoTxtMac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TodoTxtMac.app; sourceTree = BUILT_PRODUCTS_DIR; };
00B4CB9B18B43E8400313DAA /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
00B4CB9E18B43E8400313DAA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
00B4CB9F18B43E8400313DAA /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
00B4CBA018B43E8400313DAA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
00B4CBA318B43E8400313DAA /* TodoTxtMac-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TodoTxtMac-Info.plist"; sourceTree = ""; };
00B4CBA518B43E8400313DAA /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
00B4CBA718B43E8400313DAA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
00B4CBA918B43E8400313DAA /* TodoTxtMac-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TodoTxtMac-Prefix.pch"; sourceTree = ""; };
00B4CBAB18B43E8400313DAA /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; };
00B4CBAD18B43E8400313DAA /* TTMDocument.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TTMDocument.h; sourceTree = ""; };
00B4CBAE18B43E8400313DAA /* TTMDocument.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TTMDocument.m; sourceTree = ""; };
00B4CBB118B43E8400313DAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/TTMDocument.xib; sourceTree = ""; };
00B4CBB418B43E8500313DAA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
00B4CBB618B43E8500313DAA /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
00B4CBBC18B43E8500313DAA /* TodoTxtMacTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TodoTxtMacTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00B4CBBD18B43E8500313DAA /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
00B4CBC418B43E8500313DAA /* TodoTxtMacTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TodoTxtMacTests-Info.plist"; sourceTree = ""; };
00B4CBC618B43E8500313DAA /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
00B4CBC818B43E8500313DAA /* TTMTask_ReplaceText_UnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TTMTask_ReplaceText_UnitTests.m; sourceTree = ""; };
00B8C82318E48FFF008D9E48 /* TTMFieldEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMFieldEditor.h; sourceTree = ""; };
00B8C82418E48FFF008D9E48 /* TTMFieldEditor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMFieldEditor.m; sourceTree = ""; };
00D102B41991ABBE00D30237 /* TTMTasklistMetadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMTasklistMetadata.h; sourceTree = ""; };
00D102B51991ABBE00D30237 /* TTMTasklistMetadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTasklistMetadata.m; sourceTree = ""; };
00D531261CACA285007EF487 /* TTMTask_IsHidden_UnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTask_IsHidden_UnitTests.m; sourceTree = ""; };
00D531281CACC3C7007EF487 /* TTMPredicateEditorHiddenRowTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMPredicateEditorHiddenRowTemplate.h; sourceTree = ""; };
00D531291CACC3C7007EF487 /* TTMPredicateEditorHiddenRowTemplate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMPredicateEditorHiddenRowTemplate.m; sourceTree = ""; };
00DA4A1B1D5BBEB600CFF2B1 /* TTMPredicateEditorTextRowTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMPredicateEditorTextRowTemplate.h; sourceTree = ""; };
00DA4A1C1D5BBEB600CFF2B1 /* TTMPredicateEditorTextRowTemplate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMPredicateEditorTextRowTemplate.m; sourceTree = ""; };
00EAAB9518E0C168009CBE8C /* TTMPredicateEditorDateRowTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMPredicateEditorDateRowTemplate.h; sourceTree = ""; };
00EAAB9618E0C168009CBE8C /* TTMPredicateEditorDateRowTemplate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMPredicateEditorDateRowTemplate.m; sourceTree = ""; };
00EAAB9818E1CF79009CBE8C /* TTMPredicateEditorDueRowTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMPredicateEditorDueRowTemplate.h; sourceTree = ""; };
00EAAB9918E1CF79009CBE8C /* TTMPredicateEditorDueRowTemplate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMPredicateEditorDueRowTemplate.m; sourceTree = ""; };
00EAAB9B18E1CF92009CBE8C /* TTMPredicateEditorCompletedRowTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMPredicateEditorCompletedRowTemplate.h; sourceTree = ""; };
00EAAB9C18E1CF92009CBE8C /* TTMPredicateEditorCompletedRowTemplate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMPredicateEditorCompletedRowTemplate.m; sourceTree = ""; };
00EC5E9F18E3BC920021242B /* TTMAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMAppDelegate.h; sourceTree = ""; };
00EC5EA018E3BC920021242B /* TTMAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMAppDelegate.m; sourceTree = ""; };
00F3961018C6AC010002EA3F /* TTMTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMTableView.h; sourceTree = ""; };
00F3961118C6AC010002EA3F /* TTMTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMTableView.m; sourceTree = ""; };
00F811EC18D53F7300379B99 /* TTMPreferencesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMPreferencesController.h; sourceTree = ""; };
00F811ED18D53F7300379B99 /* TTMPreferencesController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMPreferencesController.m; sourceTree = ""; };
00FA1D2618F1EF340066A437 /* FontNameTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FontNameTransformer.h; sourceTree = ""; };
00FA1D2718F1EF340066A437 /* FontNameTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FontNameTransformer.m; sourceTree = ""; };
00FA1D2918F1EF4C0066A437 /* RelativeDates.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = RelativeDates.strings; sourceTree = ""; };
00FB47841A733E6100F8D2B3 /* TTMDocumentStatusBarText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTMDocumentStatusBarText.h; sourceTree = ""; };
00FB47851A733E6100F8D2B3 /* TTMDocumentStatusBarText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTMDocumentStatusBarText.m; sourceTree = ""; };
00FCB2F818DB64510070BD4A /* TTMFilters.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TTMFilters.xib; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
00B4CB9518B43E8400313DAA /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
00B4CB9C18B43E8400313DAA /* Cocoa.framework in Frameworks */,
00308E171C90FD390007681C /* Sparkle.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
00B4CBB918B43E8500313DAA /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
00B4CBBF18B43E8500313DAA /* Cocoa.framework in Frameworks */,
00B4CBBE18B43E8500313DAA /* XCTest.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
00165B2218DBD11400E137B8 /* Preferences */ = {
isa = PBXGroup;
children = (
0080EAA418D3E96C0014DDD1 /* TTMPreferences.xib */,
00F811EC18D53F7300379B99 /* TTMPreferencesController.h */,
00F811ED18D53F7300379B99 /* TTMPreferencesController.m */,
);
name = Preferences;
sourceTree = "";
};
00165B2318DBD18C00E137B8 /* Filters */ = {
isa = PBXGroup;
children = (
00FCB2F818DB64510070BD4A /* TTMFilters.xib */,
00165B2418DBD1EC00E137B8 /* TTMFiltersController.h */,
00165B2518DBD1EC00E137B8 /* TTMFiltersController.m */,
002EAE5C18DCAE5C008E7517 /* TTMFilterPredicates.h */,
002EAE5D18DCAE5C008E7517 /* TTMFilterPredicates.m */,
00EAAB9518E0C168009CBE8C /* TTMPredicateEditorDateRowTemplate.h */,
00EAAB9618E0C168009CBE8C /* TTMPredicateEditorDateRowTemplate.m */,
00EAAB9B18E1CF92009CBE8C /* TTMPredicateEditorCompletedRowTemplate.h */,
00EAAB9C18E1CF92009CBE8C /* TTMPredicateEditorCompletedRowTemplate.m */,
00EAAB9818E1CF79009CBE8C /* TTMPredicateEditorDueRowTemplate.h */,
00EAAB9918E1CF79009CBE8C /* TTMPredicateEditorDueRowTemplate.m */,
007B835D1A5A415300A4D5F7 /* TTMPredicateEditorThresholdRowTemplate.h */,
007B835E1A5A415300A4D5F7 /* TTMPredicateEditorThresholdRowTemplate.m */,
00D531281CACC3C7007EF487 /* TTMPredicateEditorHiddenRowTemplate.h */,
00D531291CACC3C7007EF487 /* TTMPredicateEditorHiddenRowTemplate.m */,
00DA4A1B1D5BBEB600CFF2B1 /* TTMPredicateEditorTextRowTemplate.h */,
00DA4A1C1D5BBEB600CFF2B1 /* TTMPredicateEditorTextRowTemplate.m */,
);
name = Filters;
sourceTree = "";
};
003647DF193D55FF00FDF67A /* Resources */ = {
isa = PBXGroup;
children = (
003647E0193D562900FDF67A /* dsa_pub.pem */,
);
name = Resources;
sourceTree = "";
};
0080EAA118D388770014DDD1 /* Libraries */ = {
isa = PBXGroup;
children = (
00FA1D2618F1EF340066A437 /* FontNameTransformer.h */,
00FA1D2718F1EF340066A437 /* FontNameTransformer.m */,
00930EAF18B537C10064D41B /* TTMDateUtility.h */,
00930EB018B537C10064D41B /* TTMDateUtility.m */,
00930EA818B536B00064D41B /* RegExCategories.h */,
00930EA918B536B00064D41B /* RegExCategories.m */,
006062D618EC6B0800D147F2 /* NSUserDefaults+myColorSupport.h */,
006062D718EC6B0800D147F2 /* NSUserDefaults+myColorSupport.m */,
003F959C1AA2C42700A1FF47 /* NSMutableAttributableString+ColorRegExMatches.h */,
003F959D1AA2C42700A1FF47 /* NSMutableAttributableString+ColorRegExMatches.m */,
0064E6421C9CEE6600B9A6C0 /* NSDate+RelativeDates.h */,
0064E6431C9CEE6600B9A6C0 /* NSDate+RelativeDates.m */,
);
name = Libraries;
sourceTree = "";
};
00B4CB8F18B43E8400313DAA = {
isa = PBXGroup;
children = (
00B4CBA118B43E8400313DAA /* TodoTxtMac */,
00B4CBC218B43E8500313DAA /* TodoTxtMacTests */,
003647DF193D55FF00FDF67A /* Resources */,
00B4CB9A18B43E8400313DAA /* Frameworks */,
00B4CB9918B43E8400313DAA /* Products */,
);
sourceTree = "";
};
00B4CB9918B43E8400313DAA /* Products */ = {
isa = PBXGroup;
children = (
00B4CB9818B43E8400313DAA /* TodoTxtMac.app */,
00B4CBBC18B43E8500313DAA /* TodoTxtMacTests.xctest */,
);
name = Products;
sourceTree = "";
};
00B4CB9A18B43E8400313DAA /* Frameworks */ = {
isa = PBXGroup;
children = (
00308E131C90FD120007681C /* Sparkle.framework */,
00B4CB9B18B43E8400313DAA /* Cocoa.framework */,
00B4CBBD18B43E8500313DAA /* XCTest.framework */,
00B4CB9D18B43E8400313DAA /* Other Frameworks */,
);
name = Frameworks;
sourceTree = "";
};
00B4CB9D18B43E8400313DAA /* Other Frameworks */ = {
isa = PBXGroup;
children = (
00B4CB9E18B43E8400313DAA /* AppKit.framework */,
00B4CB9F18B43E8400313DAA /* CoreData.framework */,
00B4CBA018B43E8400313DAA /* Foundation.framework */,
);
name = "Other Frameworks";
sourceTree = "";
};
00B4CBA118B43E8400313DAA /* TodoTxtMac */ = {
isa = PBXGroup;
children = (
00F811F618D545AF00379B99 /* Application */,
00165B2218DBD11400E137B8 /* Preferences */,
00165B2318DBD18C00E137B8 /* Filters */,
00F811F518D5458000379B99 /* TaskList Document */,
00F811F418D5454900379B99 /* Task Model */,
00D102B31991AB8400D30237 /* Metadata Model */,
0080EAA118D388770014DDD1 /* Libraries */,
00B4CBA218B43E8400313DAA /* Supporting Files */,
00B4CBB618B43E8500313DAA /* Images.xcassets */,
00A4E02E18D1569700CEE0A8 /* TodoTxtMac.entitlements */,
);
path = TodoTxtMac;
sourceTree = "";
};
00B4CBA218B43E8400313DAA /* Supporting Files */ = {
isa = PBXGroup;
children = (
00FA1D2918F1EF4C0066A437 /* RelativeDates.strings */,
00B4CBA318B43E8400313DAA /* TodoTxtMac-Info.plist */,
00B4CBA418B43E8400313DAA /* InfoPlist.strings */,
00B4CBA718B43E8400313DAA /* main.m */,
00B4CBA918B43E8400313DAA /* TodoTxtMac-Prefix.pch */,
00B4CBAA18B43E8400313DAA /* Credits.rtf */,
);
name = "Supporting Files";
sourceTree = "";
};
00B4CBC218B43E8500313DAA /* TodoTxtMacTests */ = {
isa = PBXGroup;
children = (
00B4CBC318B43E8500313DAA /* Supporting Files */,
003F95901AA2965600A1FF47 /* TTMDateUtility_UnitTests.m */,
0050D6831996AA38008F349B /* TTMTasklistMetadata_UnitTests.m */,
002218D71AA0D80800D6F3A0 /* TTMTask_Init_UnitTests.m */,
003F95921AA296F300A1FF47 /* TTMTask_Priority_UnitTests.m */,
002218DD1AA107F600D6F3A0 /* TTMTask_CompletionDate_UnitTests.m */,
002218E11AA139EB00D6F3A0 /* TTMTask_CreationDate_UnitTests.m */,
002218DB1AA0F48D00D6F3A0 /* TTMTask_DueDate_UnitTests.m */,
002218E31AA1704B00D6F3A0 /* TTMTask_DueState_UnitTests.m */,
002218DF1AA1387900D6F3A0 /* TTMTask_ThresholdDate_UnitTests.m */,
002218E51AA173D100D6F3A0 /* TTMTask_ThresholdState_UnitTests.m */,
002218D91AA0EB3200D6F3A0 /* TTMTask_IsCompleted_UnitTests.m */,
002218E71AA179CD00D6F3A0 /* TTMTask_MarkComplete_UnitTests.m */,
002218E91AA17B9B00D6F3A0 /* TTMTask_MarkIncomplete_UnitTests.m */,
003F958E1AA2948D00A1FF47 /* TTMTask_ToggleCompletion_UnitTests.m */,
003F95941AA2A35A00A1FF47 /* TTMTask_Projects_UnitTests.m */,
003F95961AA2A44800A1FF47 /* TTMTask_Contexts_UnitTests.m */,
003F95981AA2A64100A1FF47 /* TTMTask_SetDueDate_UnitTests.m */,
003F959F1AA3F04C00A1FF47 /* TTMTask_Postpone_UnitTests.m */,
003F95B31AA40EC700A1FF47 /* TTMTask_IncrementDueDate_UnitTests.m */,
003F95B51AA40FB400A1FF47 /* TTMTask_DecrementDueDate_UnitTests.m */,
003F959A1AA2B7A600A1FF47 /* TTMTask_RemoveDueDate_UnitTests.m */,
003F95A11AA3F41400A1FF47 /* TTMTask_IncreasePriority_UnitTests.m */,
003F95A31AA3F5DC00A1FF47 /* TTMTask_DecreasePriority_UnitTests.m */,
003F95A51AA3F68200A1FF47 /* TTMTask_RemovePriority_UnitTests.m */,
003F95A71AA3F83D00A1FF47 /* TTMTask_SetThresholdDate_UnitTests.m */,
003F95A91AA3F9C700A1FF47 /* TTMTask_IncrementThresholdDate_UnitTests.m */,
003F95AB1AA3FBDA00A1FF47 /* TTMTask_DecrementThresholdDate_UnitTests.m */,
003F95AD1AA3FC9600A1FF47 /* TTMTask_RemoveThresholdDate_UnitTests.m */,
003F95AF1AA3FE4400A1FF47 /* TTMTask_AppendText_UnitTests.m */,
003F95B11AA4016200A1FF47 /* TTMTask_PrependText_UnitTests.m */,
00B4CBC818B43E8500313DAA /* TTMTask_ReplaceText_UnitTests.m */,
00D531261CACA285007EF487 /* TTMTask_IsHidden_UnitTests.m */,
);
path = TodoTxtMacTests;
sourceTree = "";
};
00B4CBC318B43E8500313DAA /* Supporting Files */ = {
isa = PBXGroup;
children = (
00B4CBC418B43E8500313DAA /* TodoTxtMacTests-Info.plist */,
00B4CBC518B43E8500313DAA /* InfoPlist.strings */,
);
name = "Supporting Files";
sourceTree = "";
};
00D102B31991AB8400D30237 /* Metadata Model */ = {
isa = PBXGroup;
children = (
00D102B41991ABBE00D30237 /* TTMTasklistMetadata.h */,
00D102B51991ABBE00D30237 /* TTMTasklistMetadata.m */,
);
name = "Metadata Model";
sourceTree = "";
};
00F811F418D5454900379B99 /* Task Model */ = {
isa = PBXGroup;
children = (
00930EAB18B5371B0064D41B /* TTMTask.h */,
00930EAC18B5371B0064D41B /* TTMTask.m */,
);
name = "Task Model";
sourceTree = "";
};
00F811F518D5458000379B99 /* TaskList Document */ = {
isa = PBXGroup;
children = (
00B4CBB018B43E8400313DAA /* TTMDocument.xib */,
006BA79D19DB9CFD00C8F408 /* TTMTasklistMetadata.xib */,
006B26451A81C82D00B0E47A /* TTMFindReplace.xib */,
00B4CBAD18B43E8400313DAA /* TTMDocument.h */,
00B4CBAE18B43E8400313DAA /* TTMDocument.m */,
0086C98318B54F1A00A427AA /* TTMTableViewDelegate.h */,
0086C98418B54F1A00A427AA /* TTMTableViewDelegate.m */,
00F3961018C6AC010002EA3F /* TTMTableView.h */,
00F3961118C6AC010002EA3F /* TTMTableView.m */,
00B8C82318E48FFF008D9E48 /* TTMFieldEditor.h */,
00B8C82418E48FFF008D9E48 /* TTMFieldEditor.m */,
00FB47841A733E6100F8D2B3 /* TTMDocumentStatusBarText.h */,
00FB47851A733E6100F8D2B3 /* TTMDocumentStatusBarText.m */,
);
name = "TaskList Document";
sourceTree = "";
};
00F811F618D545AF00379B99 /* Application */ = {
isa = PBXGroup;
children = (
00B4CBB318B43E8500313DAA /* MainMenu.xib */,
00EC5E9F18E3BC920021242B /* TTMAppDelegate.h */,
00EC5EA018E3BC920021242B /* TTMAppDelegate.m */,
002EAE5718DBD24C008E7517 /* TTMAppController.h */,
002EAE5818DBD24C008E7517 /* TTMAppController.m */,
);
name = Application;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
00B4CB9718B43E8400313DAA /* TodoTxtMac */ = {
isa = PBXNativeTarget;
buildConfigurationList = 00B4CBCC18B43E8500313DAA /* Build configuration list for PBXNativeTarget "TodoTxtMac" */;
buildPhases = (
00B4CB9418B43E8400313DAA /* Sources */,
00B4CB9518B43E8400313DAA /* Frameworks */,
00B4CB9618B43E8400313DAA /* Resources */,
003647DD193D50DA00FDF67A /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = TodoTxtMac;
productName = TodoTxtMac;
productReference = 00B4CB9818B43E8400313DAA /* TodoTxtMac.app */;
productType = "com.apple.product-type.application";
};
00B4CBBB18B43E8500313DAA /* TodoTxtMacTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 00B4CBCF18B43E8500313DAA /* Build configuration list for PBXNativeTarget "TodoTxtMacTests" */;
buildPhases = (
00B4CBB818B43E8500313DAA /* Sources */,
00B4CBB918B43E8500313DAA /* Frameworks */,
00B4CBBA18B43E8500313DAA /* Resources */,
);
buildRules = (
);
dependencies = (
00B4CBC118B43E8500313DAA /* PBXTargetDependency */,
);
name = TodoTxtMacTests;
productName = TodoTxtMacTests;
productReference = 00B4CBBC18B43E8500313DAA /* TodoTxtMacTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
00B4CB9018B43E8400313DAA /* Project object */ = {
isa = PBXProject;
attributes = {
CLASSPREFIX = TTM;
LastUpgradeCheck = 0820;
ORGANIZATIONNAME = "Michael Descy";
TargetAttributes = {
00B4CB9718B43E8400313DAA = {
SystemCapabilities = {
com.apple.Sandbox = {
enabled = 0;
};
};
};
00B4CBBB18B43E8500313DAA = {
TestTargetID = 00B4CB9718B43E8400313DAA;
};
};
};
buildConfigurationList = 00B4CB9318B43E8400313DAA /* Build configuration list for PBXProject "TodoTxtMac" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 00B4CB8F18B43E8400313DAA;
productRefGroup = 00B4CB9918B43E8400313DAA /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
00B4CB9718B43E8400313DAA /* TodoTxtMac */,
00B4CBBB18B43E8500313DAA /* TodoTxtMacTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
00B4CB9618B43E8400313DAA /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
006BA79E19DB9CFD00C8F408 /* TTMTasklistMetadata.xib in Resources */,
0080EAA518D3E96C0014DDD1 /* TTMPreferences.xib in Resources */,
00FCB2F918DB64510070BD4A /* TTMFilters.xib in Resources */,
00FA1D2A18F1EF4C0066A437 /* RelativeDates.strings in Resources */,
00B4CBB218B43E8400313DAA /* TTMDocument.xib in Resources */,
003647E1193D562900FDF67A /* dsa_pub.pem in Resources */,
00B4CBB718B43E8500313DAA /* Images.xcassets in Resources */,
00B4CBA618B43E8400313DAA /* InfoPlist.strings in Resources */,
00B4CBAC18B43E8400313DAA /* Credits.rtf in Resources */,
00B4CBB518B43E8500313DAA /* MainMenu.xib in Resources */,
006B26461A81C82D00B0E47A /* TTMFindReplace.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
00B4CBBA18B43E8500313DAA /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
00B4CBC718B43E8500313DAA /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
00B4CB9418B43E8400313DAA /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0064E6441C9CEE6600B9A6C0 /* NSDate+RelativeDates.m in Sources */,
002EAE5918DBD24C008E7517 /* TTMAppController.m in Sources */,
00EAAB9A18E1CF79009CBE8C /* TTMPredicateEditorDueRowTemplate.m in Sources */,
002EAE5E18DCAE5C008E7517 /* TTMFilterPredicates.m in Sources */,
006062D818EC6B0800D147F2 /* NSUserDefaults+myColorSupport.m in Sources */,
00930EAD18B5371B0064D41B /* TTMTask.m in Sources */,
00F3961218C6AC010002EA3F /* TTMTableView.m in Sources */,
00930EB118B537C10064D41B /* TTMDateUtility.m in Sources */,
00FA1D2818F1EF340066A437 /* FontNameTransformer.m in Sources */,
00D102B61991ABBE00D30237 /* TTMTasklistMetadata.m in Sources */,
00DA4A1D1D5BBEB600CFF2B1 /* TTMPredicateEditorTextRowTemplate.m in Sources */,
0086C98518B54F1A00A427AA /* TTMTableViewDelegate.m in Sources */,
007B835F1A5A415300A4D5F7 /* TTMPredicateEditorThresholdRowTemplate.m in Sources */,
00B4CBAF18B43E8400313DAA /* TTMDocument.m in Sources */,
00930EAA18B536B00064D41B /* RegExCategories.m in Sources */,
00B4CBA818B43E8400313DAA /* main.m in Sources */,
003F959E1AA2C42700A1FF47 /* NSMutableAttributableString+ColorRegExMatches.m in Sources */,
00EAAB9718E0C168009CBE8C /* TTMPredicateEditorDateRowTemplate.m in Sources */,
00EC5EA118E3BC920021242B /* TTMAppDelegate.m in Sources */,
00F811EF18D53F7300379B99 /* TTMPreferencesController.m in Sources */,
00165B2618DBD1EC00E137B8 /* TTMFiltersController.m in Sources */,
00FB47861A733E6100F8D2B3 /* TTMDocumentStatusBarText.m in Sources */,
00D5312A1CACC3C7007EF487 /* TTMPredicateEditorHiddenRowTemplate.m in Sources */,
00B8C82518E48FFF008D9E48 /* TTMFieldEditor.m in Sources */,
00EAAB9D18E1CF92009CBE8C /* TTMPredicateEditorCompletedRowTemplate.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
00B4CBB818B43E8500313DAA /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
003F95911AA2965600A1FF47 /* TTMDateUtility_UnitTests.m in Sources */,
002218DA1AA0EB3200D6F3A0 /* TTMTask_IsCompleted_UnitTests.m in Sources */,
003F95971AA2A44800A1FF47 /* TTMTask_Contexts_UnitTests.m in Sources */,
003F958F1AA2948D00A1FF47 /* TTMTask_ToggleCompletion_UnitTests.m in Sources */,
003F95A41AA3F5DC00A1FF47 /* TTMTask_DecreasePriority_UnitTests.m in Sources */,
002218EA1AA17B9B00D6F3A0 /* TTMTask_MarkIncomplete_UnitTests.m in Sources */,
002218E41AA1704B00D6F3A0 /* TTMTask_DueState_UnitTests.m in Sources */,
003F95A81AA3F83D00A1FF47 /* TTMTask_SetThresholdDate_UnitTests.m in Sources */,
003F95B61AA40FB400A1FF47 /* TTMTask_DecrementDueDate_UnitTests.m in Sources */,
002218DC1AA0F48D00D6F3A0 /* TTMTask_DueDate_UnitTests.m in Sources */,
002218E61AA173D100D6F3A0 /* TTMTask_ThresholdState_UnitTests.m in Sources */,
002218E21AA139EB00D6F3A0 /* TTMTask_CreationDate_UnitTests.m in Sources */,
002218E81AA179CD00D6F3A0 /* TTMTask_MarkComplete_UnitTests.m in Sources */,
00B4CBC918B43E8500313DAA /* TTMTask_ReplaceText_UnitTests.m in Sources */,
003F95A61AA3F68200A1FF47 /* TTMTask_RemovePriority_UnitTests.m in Sources */,
003F95AE1AA3FC9600A1FF47 /* TTMTask_RemoveThresholdDate_UnitTests.m in Sources */,
003F95A21AA3F41400A1FF47 /* TTMTask_IncreasePriority_UnitTests.m in Sources */,
003F95951AA2A35A00A1FF47 /* TTMTask_Projects_UnitTests.m in Sources */,
003F95B41AA40EC700A1FF47 /* TTMTask_IncrementDueDate_UnitTests.m in Sources */,
003F95AC1AA3FBDA00A1FF47 /* TTMTask_DecrementThresholdDate_UnitTests.m in Sources */,
0050D6841996AA38008F349B /* TTMTasklistMetadata_UnitTests.m in Sources */,
003F95B21AA4016200A1FF47 /* TTMTask_PrependText_UnitTests.m in Sources */,
003F959B1AA2B7A600A1FF47 /* TTMTask_RemoveDueDate_UnitTests.m in Sources */,
002218D81AA0D80800D6F3A0 /* TTMTask_Init_UnitTests.m in Sources */,
00D531271CACA285007EF487 /* TTMTask_IsHidden_UnitTests.m in Sources */,
003F95AA1AA3F9C700A1FF47 /* TTMTask_IncrementThresholdDate_UnitTests.m in Sources */,
002218E01AA1387900D6F3A0 /* TTMTask_ThresholdDate_UnitTests.m in Sources */,
003F95B01AA3FE4400A1FF47 /* TTMTask_AppendText_UnitTests.m in Sources */,
002218DE1AA107F600D6F3A0 /* TTMTask_CompletionDate_UnitTests.m in Sources */,
003F95A01AA3F04C00A1FF47 /* TTMTask_Postpone_UnitTests.m in Sources */,
003F95991AA2A64100A1FF47 /* TTMTask_SetDueDate_UnitTests.m in Sources */,
003F95931AA296F300A1FF47 /* TTMTask_Priority_UnitTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
00B4CBC118B43E8500313DAA /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 00B4CB9718B43E8400313DAA /* TodoTxtMac */;
targetProxy = 00B4CBC018B43E8500313DAA /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
00B4CBA418B43E8400313DAA /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
00B4CBA518B43E8400313DAA /* en */,
);
name = InfoPlist.strings;
sourceTree = "";
};
00B4CBAA18B43E8400313DAA /* Credits.rtf */ = {
isa = PBXVariantGroup;
children = (
00B4CBAB18B43E8400313DAA /* en */,
);
name = Credits.rtf;
sourceTree = "";
};
00B4CBB018B43E8400313DAA /* TTMDocument.xib */ = {
isa = PBXVariantGroup;
children = (
00B4CBB118B43E8400313DAA /* Base */,
);
name = TTMDocument.xib;
sourceTree = "";
};
00B4CBB318B43E8500313DAA /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
00B4CBB418B43E8500313DAA /* Base */,
);
name = MainMenu.xib;
sourceTree = "";
};
00B4CBC518B43E8500313DAA /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
00B4CBC618B43E8500313DAA /* en */,
);
name = InfoPlist.strings;
sourceTree = "";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
00B4CBCA18B43E8500313DAA /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
ONLY_ACTIVE_ARCH = YES;
"OTHER_LDFLAGS[arch=*]" = "-Wl,-rpath,@loader_path/../Frameworks";
SDKROOT = macosx;
};
name = Debug;
};
00B4CBCB18B43E8500313DAA /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
ONLY_ACTIVE_ARCH = YES;
"OTHER_LDFLAGS[arch=*]" = "-Wl,-rpath,@loader_path/../Frameworks";
SDKROOT = macosx;
};
name = Release;
};
00B4CBCD18B43E8500313DAA /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
BUNDLE_LOADER = "";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "TodoTxtMac/TodoTxtMac-Prefix.pch";
INFOPLIST_FILE = "TodoTxtMac/TodoTxtMac-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "com.descy.michael.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
TEST_HOST = "";
WRAPPER_EXTENSION = app;
};
name = Debug;
};
00B4CBCE18B43E8500313DAA /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "TodoTxtMac/TodoTxtMac-Prefix.pch";
INFOPLIST_FILE = "TodoTxtMac/TodoTxtMac-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "com.descy.michael.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
TEST_HOST = "$(BUNDLE_LOADER)";
WRAPPER_EXTENSION = app;
};
name = Release;
};
00B4CBD018B43E8500313DAA /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/TodoTxtMac.app/Contents/MacOS/TodoTxtMac";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "TodoTxtMac/TodoTxtMac-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = "TodoTxtMacTests/TodoTxtMacTests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "com.descy.michael.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUNDLE_LOADER)";
WRAPPER_EXTENSION = xctest;
};
name = Debug;
};
00B4CBD118B43E8500313DAA /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/TodoTxtMac.app/Contents/MacOS/TodoTxtMac";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "TodoTxtMac/TodoTxtMac-Prefix.pch";
INFOPLIST_FILE = "TodoTxtMacTests/TodoTxtMacTests-Info.plist";
PRODUCT_BUNDLE_IDENTIFIER = "com.descy.michael.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUNDLE_LOADER)";
WRAPPER_EXTENSION = xctest;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
00B4CB9318B43E8400313DAA /* Build configuration list for PBXProject "TodoTxtMac" */ = {
isa = XCConfigurationList;
buildConfigurations = (
00B4CBCA18B43E8500313DAA /* Debug */,
00B4CBCB18B43E8500313DAA /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
00B4CBCC18B43E8500313DAA /* Build configuration list for PBXNativeTarget "TodoTxtMac" */ = {
isa = XCConfigurationList;
buildConfigurations = (
00B4CBCD18B43E8500313DAA /* Debug */,
00B4CBCE18B43E8500313DAA /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
00B4CBCF18B43E8500313DAA /* Build configuration list for PBXNativeTarget "TodoTxtMacTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
00B4CBD018B43E8500313DAA /* Debug */,
00B4CBD118B43E8500313DAA /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 00B4CB9018B43E8400313DAA /* Project object */;
}
================================================
FILE: TodoTxtMac.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: TodoTxtMac.xcodeproj/project.xcworkspace/xcshareddata/TodoTxtMac.xccheckout
================================================
IDESourceControlProjectFavoriteDictionaryKey
IDESourceControlProjectIdentifier
C3E3AF9F-0812-4964-A2D4-47471DD4BF13
IDESourceControlProjectName
TodoTxtMac
IDESourceControlProjectOriginsDictionary
7466FF582706CDEEDB6FB7E39AC879FD99CC9718
https://github.com/mjdescy/TodoTxtMac.git
IDESourceControlProjectPath
TodoTxtMac.xcodeproj
IDESourceControlProjectRelativeInstallPathDictionary
7466FF582706CDEEDB6FB7E39AC879FD99CC9718
../..
IDESourceControlProjectURL
https://github.com/mjdescy/TodoTxtMac.git
IDESourceControlProjectVersion
111
IDESourceControlProjectWCCIdentifier
7466FF582706CDEEDB6FB7E39AC879FD99CC9718
IDESourceControlProjectWCConfigurations
IDESourceControlRepositoryExtensionIdentifierKey
public.vcs.git
IDESourceControlWCCIdentifierKey
7466FF582706CDEEDB6FB7E39AC879FD99CC9718
IDESourceControlWCCName
TodoTxtMac
================================================
FILE: TodoTxtMacTests/TTMDateUtility_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMDateUtility.h"
@interface TTMDateUtility_UnitTests : XCTestCase
@end
@implementation TTMDateUtility_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testDateConversions_WithNormalDate {
NSDate *firstDate = [TTMDateUtility convertStringToDate:@"2014-01-01"];
NSLog(@"firstDate: %@", firstDate);
NSString *firstDateString = [TTMDateUtility convertDateToString:firstDate];
NSLog(@"firstDateString: %@", firstDateString);
NSDate *secondDate = [TTMDateUtility convertStringToDate:firstDateString];
NSLog(@"secondDate: %@", secondDate);
XCTAssertEqualObjects(firstDate, secondDate);
}
- (void)testDateConversions_WithHighDate {
NSDate *firstDate = [TTMDateUtility convertStringToDate:@"9999-12-31"];
NSLog(@"firstDate: %@", firstDate);
NSString *firstDateString = [TTMDateUtility convertDateToString:firstDate];
NSLog(@"firstDateString: %@", firstDateString);
NSDate *secondDate = [TTMDateUtility convertStringToDate:firstDateString];
NSLog(@"secondDate: %@", secondDate);
XCTAssertEqualObjects(firstDate, secondDate);
}
- (void)testDateConversions_WithLowDate {
NSDate *firstDate = [TTMDateUtility convertStringToDate:@"1900-01-01"];
NSLog(@"firstDate: %@", firstDate);
NSString *firstDateString = [TTMDateUtility convertDateToString:firstDate];
NSLog(@"firstDateString: %@", firstDateString);
NSDate *secondDate = [TTMDateUtility convertStringToDate:firstDateString];
NSLog(@"secondDate: %@", secondDate);
XCTAssertEqualObjects(firstDate, secondDate);
}
- (void)testAddDaysToDate {
NSDate *firstDate = [TTMDateUtility convertStringToDate:@"2014-01-01"];
NSDate *secondDate = [TTMDateUtility convertStringToDate:@"2014-01-02"];
NSDate *firstDateModified = [TTMDateUtility addDays:1 toDate:firstDate];
NSLog(@"new date: %@", firstDateModified);
XCTAssertEqualObjects(firstDateModified, secondDate);
}
- (void)testAddDaysToDate_DayLightSavingsTimeUSStart2015 {
NSDate *firstDate = [TTMDateUtility convertStringToDate:@"2015-03-08"];
NSDate *secondDate = [TTMDateUtility convertStringToDate:@"2015-03-09"];
NSDate *firstDateModified = [TTMDateUtility addDays:1 toDate:firstDate];
NSLog(@"new date: %@", firstDateModified);
XCTAssertEqualObjects(firstDateModified, secondDate);
}
- (void)testAddNegativeDaysToDate {
NSDate *firstDate = [TTMDateUtility convertStringToDate:@"2014-01-02"];
NSDate *secondDate = [TTMDateUtility convertStringToDate:@"2014-01-01"];
NSDate *firstDateModified = [TTMDateUtility addDays:-1 toDate:firstDate];
NSLog(@"new date: %@", firstDateModified);
XCTAssertEqualObjects(firstDateModified, secondDate);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_AppendText_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
@interface TTMTask_AppendText_UnitTests : XCTestCase
@property NSUInteger taskId;
@property NSString *textToAppend;
@end
@implementation TTMTask_AppendText_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
self.textToAppend = @"[text to append]";
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_AppendText_WhenTaskIsNotBlank_ShouldAppendTextToEnd {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task appendText:self.textToAppend];
NSString *expectedRawText = @"pick up groceries [text to append]";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_AppendText_WhenTaskIsBlank_ShouldAppendTextToEnd {
NSString *rawText = @"";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task appendText:self.textToAppend];
XCTAssertEqualObjects(self.textToAppend, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_CompletionDate_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_CompletionDate_UnitTests : XCTestCase
@property NSString *rawText;
@property NSUInteger taskId;
@property NSDate *completionDate;
@property NSDate *highDate;
@end
@implementation TTMTask_CompletionDate_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.rawText = @"pick up groceries";
self.taskId = 10;
self.completionDate = [TTMDateUtility convertStringToDate:@"2020-01-31"];
self.highDate = [TTMDateUtility convertStringToDate:@"9999-12-31"];
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_CompletionDate_WhenCompleted_ShouldBeCompletionDate {
NSString *rawText = @"x 2020-01-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.completionDate, task.completionDate);
}
- (void)test_CompletionDate_WhenNotCompleted_ShouldBeHighDate {
NSString *rawText = @"pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.completionDate);
}
- (void)test_CompletionDate_WhenCompletedFormatHasCapitalX_ShouldBeHighDate {
NSString *rawText = @"X 2020-01-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.completionDate);
}
- (void)test_CompletionDate_WhenCompletedFormatHasNoDate_ShouldBeHighDate {
NSString *rawText = @"x pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.completionDate);
}
- (void)test_CompletionDate_WhenCompletedDateHasNoLeadingSpace_ShouldBeHighDate {
NSString *rawText = @"x2020-01-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.completionDate);
}
- (void)test_CompletionDate_WhenCompletedDateHasNoTrailingSpace_ShouldBeHighDate {
NSString *rawText = @"x 2020-01-31pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.completionDate);
}
- (void)test_CompletionDate_WhenCompletedDateHasTwoLeadingSpaces_ShouldBeHighDate {
NSString *rawText = @"x 2020-01-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.completionDate);
}
- (void)test_CompletionDate_WhenCompletedDateMonthInvalid_ShouldBeHighDate {
NSString *rawText = @"x 2020-13-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.completionDate);
}
- (void)test_CompletionDate_WhenCompletedDateDayInvalid_ShouldBeHighDate {
NSString *rawText = @"x 2020-12-32 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.completionDate);
}
- (void)test_CompletionDate_WhenCompletedFormatHasLeadingSpace_ShouldBeHighDate {
NSString *rawText = @" x 2020-01-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.completionDate);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_Contexts_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
@interface TTMTask_Contexts_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_Contexts_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_contexts_WhenTaskHasOneProject_ShouldBeOneProject {
NSString *rawText = @"pick up groceries @Chores";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(@"@Chores", task.contexts);
}
- (void)test_contexts_WhenTaskHasMultipleContexts_ShouldBeAllcontextsAlphabetized {
NSString *rawText = @"pick up groceries @Shopping @Chores @Errands";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(@"@Chores, @Errands, @Shopping", task.contexts);
}
- (void)test_contexts_WhenTaskHasMultipleContextsWithOddPunctuation_ShouldBeAllcontextsAlphabetized {
NSString *rawText = @"pick up groceries @Shopping; @Chores@Personal @-Errands-";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(@"@-Errands-, @Chores@Personal, @Shopping;", task.contexts);
}
- (void)test_Projects_WhenTaskHasNoContexts_ShouldBeEmptyString {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(@"", task.contexts);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_CreationDate_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_CreationDate_UnitTests : XCTestCase
@property NSUInteger taskId;
@property NSDate *creationDate;
@property NSDate *highDate;
@end
@implementation TTMTask_CreationDate_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
self.creationDate = [TTMDateUtility convertStringToDate:@"2020-01-01"];
self.highDate = [TTMDateUtility convertStringToDate:@"9999-12-31"];
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_CreationDate_WhenIncompleteWithCreationDateAndNoPriority_ShouldBeCreationDate {
NSString *rawText = @"2020-01-01 test task due:2020-12-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.creationDate, task.creationDate);
}
- (void)test_CreationDate_WhenIncompleteWithCreationDateAndPriority_ShouldBeCreationDate {
NSString *rawText = @"(A) 2020-01-01 test task due:2020-12-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.creationDate, task.creationDate);
}
- (void)test_CreationDate_WhenIncompleteWithNoCreationDate_ShouldBeHighDate {
NSString *rawText = @"(A) test task due:2020-12-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.creationDate);
}
- (void)test_CreationDate_WhenCompleteWithCreationDate_ShouldBeCreationDate {
NSString *rawText = @"x 2013-12-31 2020-01-01 test task due:2020-12-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.creationDate, task.creationDate);
}
- (void)test_CreationDate_WhenCompleteWithCreationDateWithNoLeadingSpace_ShouldBeHighDate {
NSString *rawText = @"x 2020-12-312020-01-01 test task due:2020-12-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.creationDate);
}
- (void)test_CreationDate_WhenCompleteWithCreationDateWithNoTrailingSpace_ShouldBeHighDate {
NSString *rawText = @"x 2020-01-01 2020-01-01test task due:2020-12-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.creationDate);
}
- (void)test_CreationDate_WhenIncompleteWithCreationDateWithNoLeadingSpace_ShouldBeHighDate {
NSString *rawText = @"(A)2020-01-01 test task due:2020-12-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.creationDate);
}
- (void)test_CreationDate_WhenIncompleteWithCreationDateWithNoTrailingSpace_ShouldBeHighDate {
NSString *rawText = @"(A) 2020-01-01test task due:2020-12-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.creationDate);
}
- (void)test_CreationDate_WhenCompleteWithNoCreationDate_ShouldBeHighDate {
NSString *rawText = @"x 2020-12-31 test task due:2020-12-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.creationDate);
}
- (void)test_DueDate_WhenCreationDateMonthInvalid_ShouldBeHighDate {
NSString *rawText = @"(A) 9999-13-31 test task +Project1";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.creationDate);
}
- (void)test_DueDate_WhenCreationDateDayInvalid_ShouldBeHighDate {
NSString *rawText = @"(A) 9999-12-32 test task due:9999-12-32 +Project1";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.highDate, task.creationDate);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_DecreasePriority_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
@interface TTMTask_DecreasePriority_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_DecreasePriority_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_DecreasePriority_WhenPriorityIsC_ShouldSetPriorityToD {
NSString *rawText = @"(C) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decreasePriority];
NSString *expectedRawText = @"(D) pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_DecreasePriority_WhenPriorityIsZ_ShouldDoNothing {
NSString *rawText = @"(Z) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decreasePriority];
XCTAssertEqualObjects(rawText, task.rawText);
}
- (void)test_DecreasePriority_WhenNoPriority_ShouldSetPriorityToA {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decreasePriority];
NSString *expectedRawText = @"(A) pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_IncreasePriority_WhenTaskIsComplete_ShouldDoNothing {
NSString *rawText = @"x 2020-01-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decreasePriority];
XCTAssertEqualObjects(rawText, task.rawText);
}
- (void)test_IncreasePriority_WhenTaskIsBlank_ShouldDoNothing {
NSString *rawText = @"";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decreasePriority];
XCTAssertEqualObjects(rawText, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_DecrementDueDate_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_DecrementDueDate_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_DecrementDueDate_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_DecrementDueDate_ByOneDayWhenTaskHasDueDateAtEnd_ShouldDecrementDueDateByOneDay {
NSString *rawText = @"pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decrementDueDate:1];
NSString *expectedRawText = @"pick up groceries due:2020-01-30";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_DecrementDueDate_ByOneDayWhenTaskHasDueDateInMiddle_ShouldDecrementDueDateByOneDay {
NSString *rawText = @"pick up groceries due:2020-01-31 +Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decrementDueDate:1];
NSString *expectedRawText = @"pick up groceries due:2020-01-30 +Personal";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_DecrementDueDate_ByOneDayWhenTaskHasDueDateAtBeginning_ShouldDecrementDueDateByOneDay {
NSString *rawText = @"due:2020-01-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decrementDueDate:1];
NSString *expectedRawText = @"due:2020-01-30 pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_DecrementDueDate_ByOneDayWhenTaskHasNoDueDate_ShouldAppendDueDateOfTomorrow {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decrementDueDate:1];
NSDate *yesterday = [TTMDateUtility addDays:-1 toDate:[TTMDateUtility today]];
NSString *expectedRawText = [NSString stringWithFormat:@"%@%@%@",
rawText,
@" due:",
[TTMDateUtility convertDateToString:yesterday]];
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_DecrementDueDate_ByNegativeOneDayWhenTaskHasDueDateAtEnd_ShouldDIncrementDueDateByOneDay {
NSString *rawText = @"pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decrementDueDate:-1];
NSString *expectedRawText = @"pick up groceries due:2020-02-01";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_DecrementDueDate_ByNegativeOneDayWhenTaskHasDueDateInMiddle_ShouldIncrementDueDateByOneDay {
NSString *rawText = @"pick up groceries due:2020-01-31 +Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decrementDueDate:-1];
NSString *expectedRawText = @"pick up groceries due:2020-02-01 +Personal";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_DecrementDueDate_ByNegativeOneDayWhenTaskHasDueDateAtBeginning_ShouldDecrementDueDateByOneDay {
NSString *rawText = @"due:2020-01-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decrementDueDate:-1];
NSString *expectedRawText = @"due:2020-02-01 pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_DecrementDueDate_ByNegativeOneDayWhenTaskHasNoDueDate_ShouldAppendDueDateOfTomorrow {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decrementDueDate:-1];
NSDate *tomorrow = [TTMDateUtility addDays:1 toDate:[TTMDateUtility today]];
NSString *expectedRawText = [NSString stringWithFormat:@"%@%@%@",
rawText,
@" due:",
[TTMDateUtility convertDateToString:tomorrow]];
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_DecrementThresholdDate_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_DecrementThresholdDate_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_DecrementThresholdDate_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_DecrementThresholdDate_WhenTaskHasNoThresholdDate_ShouldIncrementThresholdDateByOneDay {
NSString *rawText = @"pick up groceries t:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decrementThresholdDate:1];
NSString *expectedRawText = @"pick up groceries t:2020-01-30";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_DecrementThresholdDate_WhenTaskHasNoThresholdDate_ShouldAppendThresholdDateOfYesterday {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task decrementThresholdDate:1];
NSDate *yesterday = [TTMDateUtility addDays:-1 toDate:[TTMDateUtility today]];
NSString *expectedRawText = [NSString stringWithFormat:@"%@%@%@",
rawText,
@" t:",
[TTMDateUtility convertDateToString:yesterday]];
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_DueDate_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_DueDate_UnitTests : XCTestCase
@property NSUInteger taskId;
@property NSDate *dueDate;
@property NSDate *highDate;
@end
@implementation TTMTask_DueDate_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
self.dueDate = [TTMDateUtility convertStringToDate:@"2020-01-31"];
self.highDate = [TTMDateUtility convertStringToDate:@"9999-12-31"];
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_DueDate_WhenAtEndOfTask_ShouldBeDueDate {
NSString *rawText = @"pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(task.dueDate, self.dueDate);
}
- (void)test_DueDate_WhenInMiddleOfTask_ShouldBeDueDate {
NSString *rawText = @"pick up groceries due:2020-01-31 +Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(task.dueDate, self.dueDate);
}
- (void)test_DueDate_WhenAtStartOfTask_ShouldBeDueDate {
NSString *rawText = @"due:2020-01-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(task.dueDate, self.dueDate);
}
- (void)test_DueDate_WhenIsEntireTask_ShouldBeDueDate {
NSString *rawText = @"due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(task.dueDate, self.dueDate);
}
- (void)test_DueDate_WhenMissingLeadingSpace_ShouldBeHighDate {
NSString *rawText = @"pick up groceries-due:2020-01-31 +Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(task.dueDate, self.highDate);
}
- (void)test_DueDate_WhenMissingTrailingSpace_ShouldBeHighDate {
NSString *rawText = @"pick up groceries due:2020-01-31+Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(task.dueDate, self.highDate);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_DueState_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_DueState_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_DueState_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_DueState_WhenTaskContainsNoDueDate_ShouldBeNoDueDate {
NSString *rawText = @"(A) test task";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual(NoDueDate, task.dueState);
}
- (void)test_DueState_WhenTaskContainsFutureDueDate_ShouldBeNotDue {
NSString *rawText = @"(A) pick up groceries due:9999-01-01";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual(NotDue, task.dueState);
}
- (void)test_DueState_WhenTaskContainsTodayDueDate_ShouldBeDueToday {
NSString *rawTextPart1 = @"(A) pick up groceries due:";
NSString *rawTextPart2 = [TTMDateUtility todayAsString];
NSString *rawText = [rawTextPart1 stringByAppendingString:rawTextPart2];
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual(DueToday, task.dueState);
}
- (void)test_DueState_WhenTaskContainsPastDueDate_ShouldBeOverdue {
NSString *rawText = @"(A) pick up groceries due:2001-01-01";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual(Overdue, task.dueState);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_IncreasePriority_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
@interface TTMTask_IncreasePriority_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_IncreasePriority_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_IncreasePriority_WhenPriorityIsC_ShouldSetPriorityToB {
NSString *rawText = @"(C) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task increasePriority];
NSString *expectedRawText = @"(B) pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_IncreasePriority_WhenPriorityIsA_ShouldDoNothing {
NSString *rawText = @"(A) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task increasePriority];
XCTAssertEqualObjects(rawText, task.rawText);
}
- (void)test_IncreasePriority_WhenNoPriority_ShouldSetPriorityToA {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task increasePriority];
NSString *expectedRawText = @"(A) pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_IncreasePriority_WhenTaskIsComplete_ShouldDoNothing {
NSString *rawText = @"x 2020-01-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task increasePriority];
XCTAssertEqualObjects(rawText, task.rawText);
}
- (void)test_IncreasePriority_WhenTaskIsBlank_ShouldDoNothing {
NSString *rawText = @"";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task increasePriority];
XCTAssertEqualObjects(rawText, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_IncrementDueDate_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_IncrementDueDate_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_IncrementDueDate_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_IncrementDueDate_ByOneDayWhenTaskHasDueDateAtEnd_ShouldIncrementDueDateByOneDay {
NSString *rawText = @"pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task incrementDueDate:1];
NSString *expectedRawText = @"pick up groceries due:2020-02-01";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_IncrementDueDate_ByOneDayWhenTaskHasDueDateInMiddle_ShouldIncrementDueDateByOneDay {
NSString *rawText = @"pick up groceries due:2020-01-31 +Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task incrementDueDate:1];
NSString *expectedRawText = @"pick up groceries due:2020-02-01 +Personal";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_IncrementDueDate_ByOneDayWhenTaskHasDueDateAtBeginning_ShouldIncrementDueDateByOneDay {
NSString *rawText = @"due:2020-01-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task incrementDueDate:1];
NSString *expectedRawText = @"due:2020-02-01 pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_IncrementDueDate_ByOneDayWhenTaskHasNoDueDate_ShouldAppendDueDateOfTomorrow {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task incrementDueDate:1];
NSDate *tomorrow = [TTMDateUtility addDays:1 toDate:[TTMDateUtility today]];
NSString *expectedRawText = [NSString stringWithFormat:@"%@%@%@",
rawText,
@" due:",
[TTMDateUtility convertDateToString:tomorrow]];
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_IncrementDueDate_ByNegativeOneDayWhenTaskHasDueDateAtEnd_ShouldDecrementDueDateByOneDay {
NSString *rawText = @"pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task incrementDueDate:-1];
NSString *expectedRawText = @"pick up groceries due:2020-01-30";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_IncrementDueDate_ByNegativeOneDayWhenTaskHasDueDateInMiddle_ShouldDecrementDueDateByOneDay {
NSString *rawText = @"pick up groceries due:2020-01-31 +Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task incrementDueDate:-1];
NSString *expectedRawText = @"pick up groceries due:2020-01-30 +Personal";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_IncrementDueDate_ByNegativeOneDayWhenTaskHasDueDateAtBeginning_ShouldDecrementDueDateByOneDay {
NSString *rawText = @"due:2020-01-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task incrementDueDate:-1];
NSString *expectedRawText = @"due:2020-01-30 pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_IncrementDueDate_ByNegativeOneDayWhenTaskHasNoDueDate_ShouldAppendDueDateOfYesterday {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task incrementDueDate:-1];
NSDate *yesterday = [TTMDateUtility addDays:-1 toDate:[TTMDateUtility today]];
NSString *expectedRawText = [NSString stringWithFormat:@"%@%@%@",
rawText,
@" due:",
[TTMDateUtility convertDateToString:yesterday]];
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_IncrementThresholdDate_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_IncrementThresholdDate_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_IncrementThresholdDate_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_IncrementThresholdDate_WhenTaskHasNoThresholdDate_ShouldIncrementThresholdDateByOneDay {
NSString *rawText = @"pick up groceries t:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task incrementThresholdDate:1];
NSString *expectedRawText = @"pick up groceries t:2020-02-01";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_IncrementThresholdDate_WhenTaskHasNoThresholdDate_ShouldAppendThresholdDateOfTomorrow {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task incrementThresholdDate:1];
NSDate *tomorrow = [TTMDateUtility addDays:1 toDate:[TTMDateUtility today]];
NSString *expectedRawText = [NSString stringWithFormat:@"%@%@%@",
rawText,
@" t:",
[TTMDateUtility convertDateToString:tomorrow]];
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_Init_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_Init_UnitTests : XCTestCase
@property NSString *rawText;
@property NSUInteger taskId;
@property NSDate *prependedDate;
@end
@implementation TTMTask_Init_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.rawText = @"pick up groceries";
self.taskId = 10;
self.prependedDate = [TTMDateUtility today];
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_init_WhenGivenRawTextAndTaskId_RawTextShouldEqualRawText {
TTMTask *task = [[TTMTask alloc] initWithRawText:self.rawText withTaskId:self.taskId];
XCTAssertEqualObjects(self.rawText, task.rawText);
}
- (void)test_init_WhenGivenBlankRawTextAndTaskId_RawTextShouldBeBlank {
TTMTask *task = [[TTMTask alloc] initWithRawText:@"" withTaskId:self.taskId];
XCTAssertEqualObjects(@"", task.rawText);
}
- (void)test_init_WhenGivenRawTextAndTaskId_IdShouldEqualId {
TTMTask *task = [[TTMTask alloc] initWithRawText:self.rawText withTaskId:self.taskId];
XCTAssertEqual(self.taskId, task.taskId);
}
- (void)test_init_WhenGivenRawTextAndTaskIdAndPrependedDate_RawTextShouldEqualRawTextWithPrependedDate {
TTMTask *task = [[TTMTask alloc] initWithRawText:self.rawText
withTaskId:self.taskId
withPrependedDate:self.prependedDate];
NSString *rawText = [NSString stringWithFormat:@"%@%c%@",
[TTMDateUtility convertDateToString:self.prependedDate],
' ',
self.rawText];
XCTAssertEqualObjects(rawText, task.rawText);
}
- (void)test_init_WhenGivenRawTextAndTaskIdAndPrependedDate_IdShouldEqualId {
TTMTask *task = [[TTMTask alloc] initWithRawText:self.rawText
withTaskId:self.taskId
withPrependedDate:self.prependedDate];
XCTAssertEqual(self.taskId, task.taskId);
}
- (void)test_init_WhenGivenRawTextAndTaskIdAndPrependedDate_CreationDateShouldEqualPrependedDate {
TTMTask *task = [[TTMTask alloc] initWithRawText:self.rawText
withTaskId:self.taskId
withPrependedDate:self.prependedDate];
XCTAssertEqualObjects(self.prependedDate, task.creationDate);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_IsCompleted_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
@interface TTMTask_IsCompleted_UnitTests : XCTestCase
@property NSString *rawText;
@property NSUInteger taskId;
@end
@implementation TTMTask_IsCompleted_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.rawText = @"pick up groceries";
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_IsCompleted_WhenCompleted_ShouldBeTrue {
NSString *rawText = @"x 2020-01-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertTrue(task.isCompleted);
}
- (void)test_IsCompleted_WhenNotCompleted_ShouldBeFalse {
NSString *rawText = @"pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertFalse(task.isCompleted);
}
- (void)test_IsCompleted_WhenCompletedFormatHasCapitalX_ShouldBeFalse {
NSString *rawText = @"X 2020-01-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertFalse(task.isCompleted);
}
- (void)test_IsCompleted_WhenCompletedFormatHasNoDate_ShouldBeFalse {
NSString *rawText = @"x pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertFalse(task.isCompleted);
}
- (void)test_IsCompleted_WhenCompletedDateHasNoLeadingSpace_ShouldBeFalse {
NSString *rawText = @"x2020-01-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertFalse(task.isCompleted);
}
- (void)test_IsCompleted_WhenCompletedDateHasNoTrailingSpace_ShouldBeFalse {
NSString *rawText = @"x 2020-01-31pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertFalse(task.isCompleted);
}
- (void)test_IsCompleted_WhenCompletedDateHasTwoLeadingSpaces_ShouldBeFalse {
NSString *rawText = @"x 2020-01-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertFalse(task.isCompleted);
}
- (void)test_IsCompleted_WhenCompletedFormatHasInvalidDate_ShouldBeFalse {
NSString *rawText = @"x 2020-13-32 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertFalse(task.isCompleted);
}
- (void)test_IsCompleted_WhenCompletedFormatHasLeadingSpace_ShouldBeFalse {
NSString *rawText = @" x 2020-01-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertFalse(task.isCompleted);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_IsHidden_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2016 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
@interface TTMTask_IsHidden_UnitTests : XCTestCase
@property NSString *rawText;
@property NSUInteger taskId;
@end
@implementation TTMTask_IsHidden_UnitTests
- (void)setUp {
[super setUp];
self.taskId = 10;
}
- (void)tearDown {
[super tearDown];
}
- (void)test_IsHidden_WhenHidden_ShouldBeTrue_Case1 {
NSString *rawText = @"h:1 x 2020-01-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertTrue(task.isHidden);
}
- (void)test_IsHidden_WhenHidden_ShouldBeTrue_Case2 {
NSString *rawText = @"x 2020-01-31 h:1 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertTrue(task.isHidden);
}
- (void)test_IsHidden_WhenHidden_ShouldBeTrue_Case3 {
NSString *rawText = @"h:1 x 2020-01-31 pick up groceries due:2020-01-31 h:1";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertTrue(task.isHidden);
}
- (void)test_IsHidden_WhenHidden_ShouldBeFalse_Case1 {
NSString *rawText = @"x 2020-01-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertFalse(task.isHidden);
}
- (void)test_IsHidden_WhenHidden_ShouldBeFalse_Case2 {
NSString *rawText = @"h:1x 2020-01-31 pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertFalse(task.isHidden);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_MarkComplete_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_MarkComplete_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_MarkComplete_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_MarkComplete_WhenTaskIsNotComplete_ShouldMarkComplete {
NSString *rawText = @"(A) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task markComplete];
XCTAssertTrue(task.isCompleted);
}
- (void)test_MarkComplete_WhenTaskIsNotComplete_ShouldSetCompletionDateToToday {
NSString *rawText = @"(A) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task markComplete];
XCTAssertEqualObjects([TTMDateUtility today], task.completionDate);
}
- (void)test_MarkComplete_WhenTaskIsComplete_ShouldDoNothing {
NSString *rawText = @"x 2020-12-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task markComplete];
XCTAssertTrue(task.isCompleted);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_MarkIncomplete_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
@interface TTMTask_MarkIncomplete_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_MarkIncomplete_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_MarkComplete_WhenTaskIsIncomplete_ShouldDoNothing {
NSString *rawText = @"(A) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task markIncomplete];
XCTAssertFalse(task.isCompleted);
}
- (void)test_MarkComplete_WhenTaskIsComplete_ShouldMarkIncomplete {
NSString *rawText = @"x 2020-12-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task markIncomplete];
XCTAssertFalse(task.isCompleted);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_Postpone_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_Postpone_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_Postpone_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_Postpone_ByOneDayWhenTaskHasDueDateAtEnd_ShouldIncrementDueDateByOneDay {
NSString *rawText = @"pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task postponeTask:1];
NSString *expectedRawText = @"pick up groceries due:2020-02-01";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_Postpone_ByOneDayWhenTaskHasDueDateInMiddle_ShouldIncrementDueDateByOneDay {
NSString *rawText = @"pick up groceries due:2020-01-31 +Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task postponeTask:1];
NSString *expectedRawText = @"pick up groceries due:2020-02-01 +Personal";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_Postpone_ByOneDayWhenTaskHasDueDateAtBeginning_ShouldIncrementDueDateByOneDay {
NSString *rawText = @"due:2020-01-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task postponeTask:1];
NSString *expectedRawText = @"due:2020-02-01 pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_Postpone_ByOneDayWhenTaskHasNoDueDate_ShouldAppendDueDateOfTomorrow {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task postponeTask:1];
NSDate *tomorrow = [TTMDateUtility addDays:1 toDate:[TTMDateUtility today]];
NSString *expectedRawText = [NSString stringWithFormat:@"%@%@%@",
rawText,
@" due:",
[TTMDateUtility convertDateToString:tomorrow]];
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_Postpone_ByNegativeOneDayWhenTaskHasDueDateAtEnd_ShouldDecrementDueDateByOneDay {
NSString *rawText = @"pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task postponeTask:-1];
NSString *expectedRawText = @"pick up groceries due:2020-01-30";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_Postpone_ByNegativeOneDayWhenTaskHasDueDateInMiddle_ShouldDecrementDueDateByOneDay {
NSString *rawText = @"pick up groceries due:2020-01-31 +Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task postponeTask:-1];
NSString *expectedRawText = @"pick up groceries due:2020-01-30 +Personal";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_Postpone_ByNegativeOneDayWhenTaskHasDueDateAtBeginning_ShouldDecrementDueDateByOneDay {
NSString *rawText = @"due:2020-01-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task postponeTask:-1];
NSString *expectedRawText = @"due:2020-01-30 pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_Postpone_ByNegativeOneDayWhenTaskHasNoDueDate_ShouldAppendDueDateOfYesterday {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task postponeTask:-1];
NSDate *yesterday = [TTMDateUtility addDays:-1 toDate:[TTMDateUtility today]];
NSString *expectedRawText = [NSString stringWithFormat:@"%@%@%@",
rawText,
@" due:",
[TTMDateUtility convertDateToString:yesterday]];
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_PrependText_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
@interface TTMTask_PrependText_UnitTests : XCTestCase
@property NSUInteger taskId;
@property NSString *textToPrepend;
@end
@implementation TTMTask_PrependText_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
self.textToPrepend = @"[text to prepend]";
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_PrependText_WhenCompleteWithCreationDate_ShouldPrependAfterCreationDate {
NSString *rawText = @"x 2020-01-31 2020-01-01 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task prependText:self.textToPrepend];
NSString *expectedRawText = @"x 2020-01-31 2020-01-01 [text to prepend] pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_PrependText_WhenCompleteWithNoCreationDate_ShouldPrependAfterCompletionDate {
NSString *rawText = @"x 2020-01-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task prependText:self.textToPrepend];
NSString *expectedRawText = @"x 2020-01-31 [text to prepend] pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_PrependText_WhenIncompleteWithNoCreationDate_ShouldPrependAtBeginning {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task prependText:self.textToPrepend];
NSString *expectedRawText = @"[text to prepend] pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_PrependText_WhenIncompleteWithPriorityAndNoCreationDate_ShouldPrependAfterPriority {
NSString *rawText = @"(A) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task prependText:self.textToPrepend];
NSString *expectedRawText = @"(A) [text to prepend] pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_PrependText_WhenIncompleteWithPriorityAndCreationDate_ShouldPrependAfterCreationDate {
NSString *rawText = @"(A) 2020-01-01 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task prependText:self.textToPrepend];
NSString *expectedRawText = @"(A) 2020-01-01 [text to prepend] pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_PrependText_WhenTaskIsBlank_ShouldPrependAtBeginning {
NSString *rawText = @"";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task prependText:self.textToPrepend];
XCTAssertEqualObjects(self.textToPrepend, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_Priority_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
@interface TTMTask_Priority_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_Priority_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_Priority_WhenPriorityIsUppercaseA_ShouldBeA {
NSString *rawText = @"(A) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual('A', task.priority);
}
- (void)test_Priority_WhenPriorityIsLowercaseA_ShouldBeTilde {
NSString *rawText = @"(a) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual('~', task.priority);
}
- (void)test_Priority_WhenPriorityIsNotAnUppercaseLetter_ShouldBeTilde {
NSString *rawText = @"(1) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual('~', task.priority);
}
- (void)test_Priority_WhenPriorityIsNotAtBeginningOfRawText_ShouldBeTilde {
NSString *rawText = @" (A) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual('~', task.priority);
}
- (void)test_Priority_WhenPriorityHasNoSpaceAfter_ShouldBeTilde {
NSString *rawText = @"(A)pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual('~', task.priority);
}
- (void)test_Priority_WhenNoPriority_ShouldBeTilde {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual('~', task.priority);
}
- (void)test_Priority_WhenRawTextIsBlank_ShouldBeTilde {
NSString *rawText = @"";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual('~', task.priority);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_Projects_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
@interface TTMTask_Projects_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_Projects_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_Projects_WhenTaskHasOneProject_ShouldBeOneProject {
NSString *rawText = @"pick up groceries +Chores";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(@"+Chores", task.projects);
}
- (void)test_Projects_WhenTaskHasMultipleProjects_ShouldBeAllProjectsAlphabetized {
NSString *rawText = @"pick up groceries +Shopping +Chores +Errands";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(@"+Chores, +Errands, +Shopping", task.projects);
}
- (void)test_Projects_WhenTaskHasMultipleProjectsWithOddPunctuation_ShouldBeAllProjectsAlphabetized {
NSString *rawText = @"pick up groceries +Shopping; +Chores+Personal +-Errands-";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(@"+-Errands-, +Chores+Personal, +Shopping;", task.projects);
}
- (void)test_Projects_WhenTaskHasNoProjects_ShouldBeEmptyString {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(@"", task.projects);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_RemoveDueDate_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_RemoveDueDate_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_RemoveDueDate_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_RemoveDueDate_WhenTaskHasDueDateAtEnd_ShouldRemoveDueDate {
NSString *rawText = @"pick up groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removeDueDate];
NSString *expectedRawText = @"pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_RemoveDueDate_WhenTaskHasDueDateAtBeginning_ShouldRemoveDueDate {
NSString *rawText = @"due:2020-01-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removeDueDate];
NSString *expectedRawText = @"pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_RemoveDueDate_WhenTaskHasDueDateInMiddle_ShouldRemoveDueDate {
NSString *rawText = @"pick up due:2020-01-31 groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removeDueDate];
NSString *expectedRawText = @"pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_RemoveDueDate__WhenTaskIsOnlyTheDueDate_ShouldRemoveDueDate {
NSString *rawText = @"due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removeDueDate];
NSString *expectedRawText = @"";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_RemoveDueDate_WhenTaskHasMultipleDueDates_ShouldRemoveAllDueDates {
NSString *rawText = @"due:2020-01-31 pick up due:2020-01-31 groceries due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removeDueDate];
NSString *expectedRawText = @"pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_RemoveDueDate_WhenTaskIsOnlyDueDate_ShouldRemoveDueDate {
NSString *rawText = @"due:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removeDueDate];
NSString *expectedRawText = @"";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_RemovePriority_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
@interface TTMTask_RemovePriority_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_RemovePriority_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_RemovePriority_WhenTaskHasPriority_ShouldRemovePriority {
NSString *rawText = @"(C) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removePriority];
NSString *expectedRawText = @"pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)testRemovePriority_WhenTaskHasNoPriority_ShouldDoNothing {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removePriority];
XCTAssertEqualObjects(rawText, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_RemoveThresholdDate_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_RemoveThresholdDate_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_RemoveThresholdDate_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_RemoveThresholdDate_WhenTaskHasThresholdDateAtEnd_ShouldRemoveThresholdDate {
NSString *rawText = @"pick up groceries t:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removeThresholdDate];
NSString *expectedRawText = @"pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_RemoveThresholdDate_WhenTaskHasThresholdDateAtBeginning_ShouldRemoveThresholdDate {
NSString *rawText = @"t:2020-01-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removeThresholdDate];
NSString *expectedRawText = @"pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_RemoveThresholdDate_WhenTaskHasThresholdDateInMiddle_ShouldRemoveThresholdDate {
NSString *rawText = @"pick up t:2020-01-31 groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removeThresholdDate];
NSString *expectedRawText = @"pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_RemoveThresholdDate__WhenTaskIsOnlyTheThresholdDate_ShouldRemoveThresholdDate {
NSString *rawText = @"t:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removeThresholdDate];
NSString *expectedRawText = @"";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_RemoveThresholdDate_WhenTaskHasMultipleThresholdDates_ShouldRemoveAllThresholdDates {
NSString *rawText = @"t:2020-01-31 pick up t:2020-01-31 groceries t:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removeThresholdDate];
NSString *expectedRawText = @"pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_RemoveThresholdDate_WhenTaskIsOnlyThresholdDate_ShouldRemoveThresholdDate {
NSString *rawText = @"t:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task removeThresholdDate];
NSString *expectedRawText = @"";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_ReplaceText_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import "TTMTask.h"
@interface TTMTask_ReplaceText_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_ReplaceText_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_ReplaceText_WhenSearchTextIsFound_ShouldReplaceSearchText {
NSString *rawText = @"pick up groceries @Errands";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
NSString *expectedRawText = @"pick up car @Errands";
[task replaceText:@"groceries" withText:@"car"];
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_ReplaceText_WhenSearchTextIsNotFound_ShouldDoNothing {
NSString *rawText = @"pick up groceries @Errands";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task replaceText:@"bananas" withText:@"car"];
XCTAssertEqualObjects(rawText, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_SetDueDate_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_SetDueDate_UnitTests : XCTestCase
@property NSUInteger taskId;
@property NSDate *dueDate;
@end
@implementation TTMTask_SetDueDate_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
self.dueDate = [TTMDateUtility convertStringToDate:@"2020-01-31"];
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testSetDueDate {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task setDueDate:self.dueDate];
NSString *expectedRawText = @"pick up groceries due:2020-01-31";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_SetDueDate_WhenTaskHasNoDueDate_ShouldAppendDueDate {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task setDueDate:self.dueDate];
NSString *expectedRawText = @"pick up groceries due:2020-01-31";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_SetDueDate_WhenTaskHasDueDateAtEnd_ShouldReplaceDueDate {
NSString *rawText = @"pick up groceries due:2020-01-01";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task setDueDate:self.dueDate];
NSString *expectedRawText = @"pick up groceries due:2020-01-31";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_SetDueDate_WhenTaskHasDueDateInMiddle_ShouldReplaceDueDate {
NSString *rawText = @"pick up groceries due:2020-01-01 +Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task setDueDate:self.dueDate];
NSString *expectedRawText = @"pick up groceries due:2020-01-31 +Personal";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_SetDueDate_WhenTaskHasDueDateAtBeginning_ShouldReplaceDueDate {
NSString *rawText = @"due:2020-01-01 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task setDueDate:self.dueDate];
NSString *expectedRawText = @"due:2020-01-31 pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_SetDueDate_WhenTaskHasMultipleDueDates_ShouldReplaceAllDueDates {
NSString *rawText = @"pick up groceries due:2015-12-15 due:2015-12-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task setDueDate:self.dueDate];
NSString *expectedRawText = @"pick up groceries due:2020-01-31 due:2020-01-31";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_SetThresholdDate_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_SetThresholdDate_UnitTests : XCTestCase
@property NSUInteger taskId;
@property NSDate *thresholdDate;
@end
@implementation TTMTask_SetThresholdDate_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
self.thresholdDate = [TTMDateUtility convertStringToDate:@"2020-01-31"];
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_SetThresholdDate_WhenTaskHasNoThresholdDate_ShouldAppendThresholdDate {
NSString *rawText = @"pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task setThresholdDate:self.thresholdDate];
NSString *expectedRawText = @"pick up groceries t:2020-01-31";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_SetThresholdDate_WhenTaskHasThresholdDateAtEnd_ShouldReplaceThresholdDate {
NSString *rawText = @"pick up groceries t:2020-01-01";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task setThresholdDate:self.thresholdDate];
NSString *expectedRawText = @"pick up groceries t:2020-01-31";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_SetThresholdDate_WhenTaskHasThresholdDateInMiddle_ShouldReplaceThresholdDate {
NSString *rawText = @"pick up groceries t:2020-01-01 +Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task setThresholdDate:self.thresholdDate];
NSString *expectedRawText = @"pick up groceries t:2020-01-31 +Personal";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_SetThresholdDate_WhenTaskHasThresholdDateAtBeginning_ShouldReplaceThresholdDate {
NSString *rawText = @"t:2020-01-01 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task setThresholdDate:self.thresholdDate];
NSString *expectedRawText = @"t:2020-01-31 pick up groceries";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
- (void)test_SetThresholdDate_WhenTaskHasMultipleThresholdDates_ShouldReplaceAllThresholdDates {
NSString *rawText = @"pick up groceries t:2015-12-15 t:2015-12-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task setThresholdDate:self.thresholdDate];
NSString *expectedRawText = @"pick up groceries t:2020-01-31 t:2020-01-31";
XCTAssertEqualObjects(expectedRawText, task.rawText);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_ThresholdDate_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_ThresholdDate_UnitTests : XCTestCase
@property NSUInteger taskId;
@property NSDate *thresholdDate;
@property NSDate *lowDate;
@end
@implementation TTMTask_ThresholdDate_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
self.thresholdDate = [TTMDateUtility convertStringToDate:@"2020-01-31"];
self.lowDate = [TTMDateUtility convertStringToDate:@"1900-01-01"];
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_ThresholdDate_WhenAtEndOfTask_ShouldBeThresholdDate {
NSString *rawText = @"pick up groceries t:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(task.thresholdDate, self.thresholdDate);
}
- (void)test_ThresholdDate_WhenInMiddleOfTask_ShouldBeThresholdDate {
NSString *rawText = @"pick up groceries t:2020-01-31 +Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(task.thresholdDate, self.thresholdDate);
}
- (void)test_ThresholdDate_WhenAtStartOfTask_ShouldBeThresholdDate {
NSString *rawText = @"t:2020-01-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(task.thresholdDate, self.thresholdDate);
}
- (void)test_ThresholdDate_WhenIsEntireTask_ShouldBeThresholdDate {
NSString *rawText = @"t:2020-01-31";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(task.thresholdDate, self.thresholdDate);
}
- (void)test_ThresholdDate_WhenMissingLeadingSpace_ShouldBeLowDate {
NSString *rawText = @"pick up groceries-t:2020-01-31 +Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(task.thresholdDate, self.lowDate);
}
- (void)test_ThresholdDate_WhenMissingTrailingSpace_ShouldBeLowDate {
NSString *rawText = @"pick up groceries t:2020-01-31+Personal";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqualObjects(task.thresholdDate, self.lowDate);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_ThresholdState_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
#import "TTMDateUtility.h"
@interface TTMTask_ThresholdState_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_ThresholdState_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testThresholdStateBefore {
NSString *rawText = @"(A) pick up groceries t:2020-01-31 due:2020-01-31";
NSUInteger taskId = 0;
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:taskId];
XCTAssertEqual(ThresholdAfterToday, task.thresholdState);
}
- (void)testThresholdStateOn {
NSString *rawTextPart1 = @"(A) pick up groceries t:";
NSString *rawTextPart2 = [TTMDateUtility todayAsString];
NSString *rawText = [rawTextPart1 stringByAppendingString:rawTextPart2];
NSUInteger taskId = 0;
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:taskId];
XCTAssertEqual(ThresholdIsToday, task.thresholdState);
}
- (void)testThresholdStateAfter {
NSString *rawText = @"(A) pick up groceries t:2001-01-01 due:2020-01-31";
NSUInteger taskId = 0;
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:taskId];
XCTAssertEqual(ThresholdBeforeToday, task.thresholdState);
}
- (void)test_ThresholdState_WhenTaskContainsNoThresholdDate_ShouldBeNoThresholdDate {
NSString *rawText = @"(A) test task";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual(NoThresholdDate, task.thresholdState);
}
- (void)test_ThresholdState_WhenTaskContainsFutureThresholdDate_ShouldBeThresholdAfterToday {
NSString *rawText = @"(A) pick up groceries t:9999-01-01";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual(ThresholdAfterToday, task.thresholdState);
}
- (void)test_ThresholdState_WhenTaskContainsTodayThresholdDate_ShouldBeThresholdIsToday {
NSString *rawTextPart1 = @"(A) pick up groceries t:";
NSString *rawTextPart2 = [TTMDateUtility todayAsString];
NSString *rawText = [rawTextPart1 stringByAppendingString:rawTextPart2];
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual(ThresholdIsToday, task.thresholdState);
}
- (void)test_ThresholdState_WhenTaskContainsPastThresholdDate_ShouldBeThresholdBeforeToday {
NSString *rawText = @"(A) pick up groceries t:2001-01-01";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
XCTAssertEqual(ThresholdBeforeToday, task.thresholdState);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTask_ToggleCompletion_UnitTests.m
================================================
/**
* @author Michael Descy
* @copyright 2014-2015 Michael Descy
* @discussion Dual-licensed under the GNU General Public License and the MIT License
*
*
*
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
*
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#import
#import
#import "TTMTask.h"
@interface TTMTask_ToggleCompletionStatus_UnitTests : XCTestCase
@property NSUInteger taskId;
@end
@implementation TTMTask_ToggleCompletionStatus_UnitTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.taskId = 10;
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)test_ToggleCompletionStatus_WhenTaskIsNotComplete_ShouldMarkComplete {
NSString *rawText = @"(A) pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task toggleCompletionStatus];
XCTAssertTrue(task.isCompleted);
}
- (void)test_ToggleCompletionStatus_WhenTaskIsComplete_ShouldMarkIncomplete {
NSString *rawText = @"x 2020-12-31 pick up groceries";
TTMTask *task = [[TTMTask alloc] initWithRawText:rawText withTaskId:self.taskId];
[task toggleCompletionStatus];
XCTAssertFalse(task.isCompleted);
}
@end
================================================
FILE: TodoTxtMacTests/TTMTasklistMetadata_UnitTests.m
================================================
//
// TTMMetadataTests.m
// TodoTxtMac
//
// Created by Michael Descy on 8/9/14.
// Copyright (c) 2014 Michael Descy. All rights reserved.
//
#import
#import "TTMTask.h"
#import "TTMTasklistMetadata.h"
@interface TTMTasklistMetadataTests : XCTestCase
@property NSMutableArray *taskList;
@property TTMTasklistMetadata *tasklistMetadata;
@end
@implementation TTMTasklistMetadataTests
- (void)setUp
{
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
NSArray *rawTaskList = @[
@"(A) Task 1 @Context1 +Project1",
@"x 2014-10-01 Task 2 +Project1 due:2014-01-31",
@"(C) Task 3 +Project1 @Context1 due:9999-01-01",
@"(C) Task 4 +Project2 due:9999-12-31",
@"(A) Task 5 +Project2 @Context2 due:2014-01-31"
];
self.taskList = [NSMutableArray array];
NSInteger i = 0;
for (NSString *rawTaskText in rawTaskList) {
TTMTask *task = [[TTMTask alloc] initWithRawText:rawTaskText withTaskId:i];
[self.taskList addObject:task];
i++;
}
self.tasklistMetadata = [[TTMTasklistMetadata alloc] init];
[self.tasklistMetadata updateMetadataFromTaskArray:self.taskList];
}
- (void)tearDown
{
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testAllTaskCount
{
XCTAssertEqual(self.tasklistMetadata.allTaskCount, 5);
}
- (void)testIncompleteTaskCount
{
XCTAssertEqual(self.tasklistMetadata.incompleteTaskCount, 4);
}
- (void)testCompletedTaskCount
{
XCTAssertEqual(self.tasklistMetadata.completedTaskCount, 1);
}
- (void)testDueTodayTaskCount
{
XCTAssertEqual(self.tasklistMetadata.dueTodayTaskCount, 0);
}
- (void)testOverdueTaskCount
{
XCTAssertEqual(self.tasklistMetadata.overdueTaskCount, 2);
}
- (void)testNotDueTaskCount
{
XCTAssertEqual(self.tasklistMetadata.notDueTaskCount, 2);
}
- (void)testNoDueDateTaskCount
{
XCTAssertEqual(self.tasklistMetadata.noDueDateTaskCount, 1);
}
- (void)testProjectsArray
{
NSArray *projects = @[
@"+Project1",
@"+Project2"
];
XCTAssertEqualObjects(self.tasklistMetadata.projectsArray, projects);
}
- (void)testContextsArray
{
NSArray *contexts = @[
@"@Context1",
@"@Context2"
];
XCTAssertEqualObjects(self.tasklistMetadata.contextsArray, contexts);
}
- (void)testPrioritiesArray
{
NSArray *priorities = @[
@"A",
@"C"
];
XCTAssertEqualObjects(self.tasklistMetadata.prioritiesArray, priorities);
}
- (void)testProjectTaskCounts
{
NSDictionary *projectTaskCounts = @{
@"+Project1" : @3,
@"+Project2" : @2
};
XCTAssertEqualObjects(self.tasklistMetadata.projectTaskCounts, projectTaskCounts);
}
- (void)testContextTaskCounts
{
NSDictionary *contextTaskCounts = @{
@"@Context1" : @2,
@"@Context2" : @1
};
XCTAssertEqualObjects(self.tasklistMetadata.contextTaskCounts, contextTaskCounts);
}
- (void)testPriorityTaskCounts
{
NSDictionary *priorityTaskCounts = @{
@"A" : @2,
@"C" : @2
};
XCTAssertEqualObjects(self.tasklistMetadata.priorityTaskCounts, priorityTaskCounts);
}
- (void)testProjectsCount
{
XCTAssertEqual(self.tasklistMetadata.projectsCount, 2);
}
- (void)testContextsCount
{
XCTAssertEqual(self.tasklistMetadata.contextsCount, 2);
}
- (void)testPrioritiesCount
{
XCTAssertEqual(self.tasklistMetadata.prioritiesCount, 2);
}
@end
================================================
FILE: TodoTxtMacTests/TodoTxtMacTests-Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundlePackageType
BNDL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1
================================================
FILE: TodoTxtMacTests/en.lproj/InfoPlist.strings
================================================
/* Localized versions of Info.plist keys */
================================================
FILE: dsa_pub.pem
================================================
-----BEGIN PUBLIC KEY-----
MIIDOjCCAi0GByqGSM44BAEwggIgAoIBAQDhCUQCiF8i1StxL9w/t3t7H8hYn19U
cpzRmdTCL3w84xFpYSrmTSUoa/7lOaYt6z0/irUQBEYp6yE3+Qe3hv6xTNe80rgz
xlv8XAUjMccIQxvlQWBj0M4fh9TI52YBmGCTmeoQhf4YKiEx5+lk8xiy0SjFW4Tx
DwCgg7MkwAV7vPqFq/3DSsPSo950Xx7Phif0uW16Y6vtADFjf7quUJftbTPwNR1P
goIKEFvcR2MAj+Xw+s8nLiTe8EJzb1HGQZ7ZEd6Z/HwF5U3m2tSMPcodZpgKO1LX
HkMnnmuCx0JHhrHQWOEMjCX8iba/s+pKJ4Y3dEBzG9CeqOEcpumdKi9HAhUAwRIE
6jsm2ec8ZfnFDPLJlIPEyLECggEABS1CCoP8PP3I75onrpa5tjfZ98dElHfJmVzg
8FD8j2XqQ51CgAMOLWoEpnyPe9DdpUNK5v/OseSwHtFWL1K6hYLe1HOPAfDrfC2q
w/aAaWQJkZcKY9nvMBzYshPi4JZ9kHvGWYkWAvL0JfRPKLmqHdBkU4oeskFRPd9+
a3O/Py77P4iFqiHm8Ilxcev3QXkw+VzQjLGy+smkQUjIBQgBI0JWbrZaT7zt9xVU
6FNcUdiLs5GotWy0eYxvO2rrq+dvh6mgwn3Zrdg5w6MuqlHpXQAOXatWfnyTEqmI
x4LWC3as77F+YXI4c9QQ5+kB+1/qmbkqKOiTxLGQPPAFdd6gXQOCAQUAAoIBAG9v
gZCk1XpV3jSOjFwVnh5fVeo22GAR7oU+X4gzpO2xfb48i/W/wwRoW81NH9ELmLCK
TCVaGpaWhtuVJQ3h41aFPlCtrK7s1b+sk8PWTWag970VMk2Wz0uDNkeQhvNHg1KN
rCMT2erKgxcBQfKo/RI4SJd+viMNDbJJVf5qKAOOvPCv28HHIBZPVYPsKTZGjVno
vHmBJ17jUyvRo6MLHjIoY+sGmLNIpqNJSVf7e0TCblpzwOkzdAdPQyAlysZHaBud
pJI80jSxiOVmk04ROZv16AJ/X/hi+cIYZoK4Els1Jp0GyTgeFIADLX5JuOlav8Ya
/jTI45avbJdJd/MewCw=
-----END PUBLIC KEY-----