Skip to content

Commit

Permalink
Updated with suggested fix for finding Omnifocus icon path from @dean…
Browse files Browse the repository at this point in the history
…ishe; checked workflow works with Alfred 3
  • Loading branch information
Rhyd Lewis committed May 21, 2016
1 parent 174531a commit 12638bc
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 121 deletions.
215 changes: 105 additions & 110 deletions factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
from datetime import datetime
from omnifocus import DEFAULT_PERSPECTIVES

ACTIVE = 'active'
DONE = 'done'
DROPPED = 'dropped'
INACTIVE = 'inactive'


class Item(object):
def __init__(self, item_type, persistent_id, name, subtitle, icon):
Expand All @@ -17,116 +22,106 @@ def __repr__(self):
self.subtitle, self.icon)


OF_ICON_ROOT = '/Applications/OmniFocus.app/Contents/Resources'
if not os.path.isdir(OF_ICON_ROOT):
# see https://github.com/rhydlewis/search-omnifocus/issues/8
OF_ICON_ROOT = '/Applications/OmniFocus.localized/OmniFocus.app/Contents/Resources'

ICON_DROPPED = os.path.join(OF_ICON_ROOT, 'dropped@2x.png')
ICON_FLAGGED = os.path.join(OF_ICON_ROOT, 'flagged@2x.png')
ICON_ON_HOLD = os.path.join(OF_ICON_ROOT, 'on-hold@2x.png')
ICON_ACTIVE = os.path.join(OF_ICON_ROOT, 'active-small@2x.png')
ICON_COMPLETED = os.path.join(OF_ICON_ROOT, 'completed@2x.png')
ICON_CONTEXT = os.path.join(OF_ICON_ROOT, 'quickopen-context@2x.png')
ICON_INBOX = os.path.join(OF_ICON_ROOT, 'tab-inbox-selected@2x.png')
ICON_PERSPECTIVE = os.path.join(OF_ICON_ROOT, 'Perspectives@2x.png')
ICON_DEFERRED = os.path.join('.', 'deferred.png')
ICON_FOLDER = os.path.join(OF_ICON_ROOT, 'quickopen-folder@2x.png')

ICON_PERSPECTIVE_INBOX = os.path.join(OF_ICON_ROOT, 'tab-inbox-selected@2x.png')
ICON_PERSPECTIVE_PROJECTS = os.path.join(OF_ICON_ROOT, 'tab-projects-selected@2x.png')
ICON_PERSPECTIVE_CONTEXTS = os.path.join(OF_ICON_ROOT, 'tab-contexts-selected@2x.png')
ICON_PERSPECTIVE_FORECAST = os.path.join(OF_ICON_ROOT, 'tab-forecast-selected@2x.png')
ICON_PERSPECTIVE_FLAGGED = os.path.join(OF_ICON_ROOT, 'tab-flagged-selected@2x.png')
ICON_PERSPECTIVE_REVIEW = os.path.join(OF_ICON_ROOT, 'tab-review-selected@2x.png')

DEFAULT_PERSPECTIVE_ICONS = [ICON_PERSPECTIVE_INBOX, ICON_PERSPECTIVE_PROJECTS,
ICON_PERSPECTIVE_CONTEXTS, ICON_PERSPECTIVE_FORECAST,
ICON_PERSPECTIVE_FLAGGED, ICON_PERSPECTIVE_REVIEW]

ICON_LOOKUP = dict(zip(DEFAULT_PERSPECTIVES, DEFAULT_PERSPECTIVE_ICONS))

ACTIVE = 'active'
DONE = 'done'
DROPPED = 'dropped'
INACTIVE = 'inactive'

PROJECT_ICONS = {ACTIVE: ICON_ACTIVE, DONE: ICON_COMPLETED, DROPPED: ICON_DROPPED,
INACTIVE: ICON_ON_HOLD}
CONTEXT_ICONS = {1: ICON_ACTIVE, 0: ICON_ON_HOLD}


def create_project(raw_data):
pid = raw_data[0]
name = raw_data[1]
status = raw_data[2]
folder = raw_data[6]
datetostart = deferred_date(raw_data[7], raw_data[8])

icon = PROJECT_ICONS[status]

if status == 'active' and is_deferred(datetostart):
icon = ICON_DEFERRED

return Item(item_type='Project', persistent_id=pid, name=name, icon=icon, subtitle=folder)


def create_task(raw_data):
pid = raw_data[0]
# completed = raw_data[2] == 1
blocked_by_future_date = raw_data[3] == 1
name = raw_data[1]
project = raw_data[5]
inbox = (raw_data[8] == 1 or raw_data[9] == 1)
datetostart = deferred_date(raw_data[7], raw_data[10])

blocked = raw_data[11] == 1
children = raw_data[12]
parent_status = raw_data[13]

icon = ICON_ACTIVE

if blocked_by_future_date or (blocked and not children) or parent_status != ACTIVE:
icon = ICON_ON_HOLD
if is_deferred(datetostart):
icon = ICON_DEFERRED
if inbox:
icon = ICON_INBOX

return Item(item_type='Task', persistent_id=pid, name=name, icon=icon, subtitle=project)


def create_context(raw_data):
pid = raw_data[0]
name = raw_data[1]
allows_next_action = raw_data[2]
available_tasks = raw_data[4]
if available_tasks == 1:
subtitle = "1 task available"
else:
subtitle = "{0} tasks available".format(available_tasks)

icon = CONTEXT_ICONS[allows_next_action]

return Item(item_type='Context', persistent_id=pid, name=name, icon=icon, subtitle=subtitle)


def create_perspective(name):
icon = ICON_PERSPECTIVE
perspective_type = 'Custom'
if name in DEFAULT_PERSPECTIVES:
icon = ICON_LOOKUP[name]
perspective_type = 'Default'

return Item(item_type='Perspective', persistent_id='', name=name, icon=icon,
subtitle="Omnifocus {0} Perspective".format(perspective_type))


def create_folder(raw_data):
pid = raw_data[0]
name = raw_data[1]

return Item(item_type='Folder', persistent_id=pid, name=name, icon=ICON_FOLDER, subtitle='')
class Factory:
def __init__(self, icon_root):
self.dropped_icon = os.path.join(icon_root, 'dropped@2x.png')
self.flagged_icon = os.path.join(icon_root, 'flagged@2x.png')
self.on_hold_icon = os.path.join(icon_root, 'on-hold@2x.png')
self.active_icon = os.path.join(icon_root, 'active-small@2x.png')
self.completed_icon = os.path.join(icon_root, 'completed@2x.png')
self.context_icon = os.path.join(icon_root, 'quickopen-context@2x.png')
self.inbox_icon = os.path.join(icon_root, 'tab-inbox-selected@2x.png')
self.perspective_icon = os.path.join(icon_root, 'Perspectives@2x.png')
self.deferred_icon = os.path.join('.', 'deferred.png')
self.folder_icon = os.path.join(icon_root, 'quickopen-folder@2x.png')

self.inbox_perspective_icon = os.path.join(icon_root, 'tab-inbox-selected@2x.png')
self.projects_perspective_icon = os.path.join(icon_root, 'tab-projects-selected@2x.png')
self.contexts_perspective_icon = os.path.join(icon_root, 'tab-contexts-selected@2x.png')
self.forecast_perspective_icon = os.path.join(icon_root, 'tab-forecast-selected@2x.png')
self.flagged_perspective_icon = os.path.join(icon_root, 'tab-flagged-selected@2x.png')
self.review_perspective_icon = os.path.join(icon_root, 'tab-review-selected@2x.png')

self.default_perspective_icons = [self.inbox_perspective_icon,
self.projects_perspective_icon,
self.contexts_perspective_icon,
self.forecast_perspective_icon,
self.flagged_perspective_icon,
self.review_perspective_icon]

self.icon_lookup = dict(zip(DEFAULT_PERSPECTIVES, self.default_perspective_icons))

self.project_icons = {ACTIVE: self.active_icon, DONE: self.completed_icon,
DROPPED: self.dropped_icon, INACTIVE: self.on_hold_icon}
self.context_icons = {1: self.active_icon, 0: self.on_hold_icon}

def create_project(self, raw_data):
pid = raw_data[0]
name = raw_data[1]
status = raw_data[2]
folder = raw_data[6]
datetostart = deferred_date(raw_data[7], raw_data[8])

icon = self.project_icons[status]

if status == 'active' and is_deferred(datetostart):
icon = self.deferred_icon

return Item(item_type='Project', persistent_id=pid, name=name, icon=icon, subtitle=folder)

def create_task(self, raw_data):
pid = raw_data[0]
# completed = raw_data[2] == 1
blocked_by_future_date = raw_data[3] == 1
name = raw_data[1]
project = raw_data[5]
inbox = (raw_data[8] == 1 or raw_data[9] == 1)
datetostart = deferred_date(raw_data[7], raw_data[10])

blocked = raw_data[11] == 1
children = raw_data[12]
parent_status = raw_data[13]

icon = self.active_icon

if blocked_by_future_date or (blocked and not children) or parent_status != ACTIVE:
icon = self.on_hold_icon
if is_deferred(datetostart):
icon = self.deferred_icon
if inbox:
icon = self.inbox_icon

return Item(item_type='Task', persistent_id=pid, name=name, icon=icon, subtitle=project)

def create_context(self, raw_data):
pid = raw_data[0]
name = raw_data[1]
allows_next_action = raw_data[2]
available_tasks = raw_data[4]
if available_tasks == 1:
subtitle = "1 task available"
else:
subtitle = "{0} tasks available".format(available_tasks)

icon = self.context_icons[allows_next_action]

return Item(item_type='Context', persistent_id=pid, name=name, icon=icon, subtitle=subtitle)

def create_perspective(self, name):
icon = self.perspective_icon
perspective_type = 'Custom'
if name in DEFAULT_PERSPECTIVES:
icon = self.icon_lookup[name]
perspective_type = 'Default'

return Item(item_type='Perspective', persistent_id='', name=name, icon=icon,
subtitle="Omnifocus {0} Perspective".format(perspective_type))

def create_folder(self, raw_data):
pid = raw_data[0]
name = raw_data[1]

return Item(item_type='Folder', persistent_id=pid, name=name, icon=self.folder_icon, subtitle='')


def deferred_date(datetostart, effectivedatetostart):
Expand Down
18 changes: 15 additions & 3 deletions omnifocus.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@
end try
end tell
'''
LOCATION_SCRIPT = 'tell application "Finder" to get (POSIX path of (path to application "OmniFocus"))'


def list_perspectives():
# thanks Dr Drang: http://www.leancrew.com/all-this/2013/03/combining-python-and-applescript/
osa = subprocess.Popen(['osascript', '-'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
results = osa.communicate(PERSPECTIVE_SEARCH_SCRIPT)[0].split(', ')
results = run_script(PERSPECTIVE_SEARCH_SCRIPT)
results = [result.rstrip("\n").decode('utf-8', 'ignore') for result in results
if result != "missing value"]
names = DEFAULT_PERSPECTIVES + results
Expand All @@ -31,3 +30,16 @@ def list_perspectives():
def search_perspectives(query):
return [perspective for perspective in list_perspectives()
if query.lower() in perspective.lower()]


# see suggestion from deanishe at:
# http://www.alfredforum.com/topic/5934-search-omnifocus-free-text-search-your-omnifocus-data
def find_install_location():
results = run_script(LOCATION_SCRIPT)
return results[0].rstrip("\n")


def run_script(query):
# thanks Dr Drang: http://www.leancrew.com/all-this/2013/03/combining-python-and-applescript/
osa = subprocess.Popen(['osascript', '-'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
return osa.communicate(query)[0].split(', ')
30 changes: 23 additions & 7 deletions search.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
import datetime

from workflow import Workflow, ICON_WARNING, ICON_SYNC
import factory

from factory import Factory
import queries
import omnifocus

DB_KEY = 'db_path'
ICON_ROOT = 'icon_path'
DB_LOCATION = ("/Library/Containers/com.omnigroup.OmniFocus2/"
"Data/Library/Caches/com.omnigroup.OmniFocus2/OmniFocusDatabase2")
MAS_DB_LOCATION = DB_LOCATION.replace('.OmniFocus2', '.OmniFocus2.MacAppStore')
OF_ICON_ROOT = '/Applications/OmniFocus.app1/Contents/Resources'

# Update workflow from GitHub repo
UPDATE_SETTINGS = {'github_slug': 'rhydlewis/search-omnifocus'}
Expand All @@ -35,6 +38,7 @@

def main(wf):
log.debug('Started workflow')
factory = Factory(find_omnifocus_icons())
args = parse_args()

if SHOW_UPDATES and workflow.update_available:
Expand All @@ -45,14 +49,14 @@ def main(wf):

if args.type != PERSPECTIVE:
sql = populate_query(args)
get_results(sql, args.type)
get_results(sql, args.type, factory)
else:
get_perspectives(args)
get_perspectives(args, factory)

workflow.send_feedback()


def get_results(sql, query_type):
def get_results(sql, query_type, factory):
results = run_query(sql)

if not results:
Expand All @@ -73,7 +77,7 @@ def get_results(sql, query_type):
arg=item.persistent_id, valid=True)


def get_perspectives(args):
def get_perspectives(args, factory):
if args.query:
query = args.query[0]
log.debug("Searching perspectives for '{0}'".format(query))
Expand Down Expand Up @@ -139,7 +143,19 @@ def parse_args():
return args


def find_omnifocus():
def find_omnifocus_icons():
icon_root = workflow.stored_data(ICON_ROOT)
if not icon_root:
icon_root = OF_ICON_ROOT
if not os.path.isdir(icon_root):
icon_root = omnifocus.find_install_location() + "Contents/Resources"
log.debug("Storing icon_root as '{0}'".format(icon_root))
else:
log.debug("Using stored icon_root:'{0}'".format(icon_root))
return icon_root


def find_omnifocus_db():
home = os.path.expanduser("~")
db = "{0}{1}".format(home, DB_LOCATION)
mas = "{0}{1}".format(home, MAS_DB_LOCATION)
Expand Down Expand Up @@ -167,7 +183,7 @@ def mod_date(filename):
def run_query(sql):
db_path = workflow.stored_data(DB_KEY)
if not db_path:
db_path = find_omnifocus()
db_path = find_omnifocus_db()
workflow.store_data(DB_KEY, db_path)
else:
log.debug(db_path)
Expand Down
2 changes: 1 addition & 1 deletion version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.1.14
1.1.15

0 comments on commit 12638bc

Please sign in to comment.