[meego-commits] 10659: Changes to devel:contentfw/libcontentaction
Mishra Maitrey
no_reply at build.meego.com
Tue Dec 7 14:04:43 UTC 2010
Hi,
I have made the following changes to libcontentaction in project devel:contentfw. Please review and accept ASAP.
Thank You,
Mishra Maitrey
[This message was auto-generated]
---
Request #10659:
submit: home:maimishr/libcontentaction(r14) -> devel:contentfw/libcontentaction
Message:
Feature number - 10498
* Tue Dec 07 2010 Mishra Maitrey <maitrey.mishra at nokia.com> - 0.1.35
- Feature number - 10498
- API addition: Action::actionsForString(const QString&)
- API addition: Action::defaultActionForString(const QString&)
- Enabling defining regexps specialCaseOf="another-regexp"
- Configuration update: regexp for phone number
- Configuration update: added feed-url, ftp-url, ovi-store-url
- Fixes 2 digits numbers or more than 20 digits number are recognized as tel links
in Text Message Viewer / IM Viewer
- QT_NO_KEYWORDS
- Don't use QDBusInterface when triggering D-Bus actions
- Doc update
- Making regexps case-insensitive
- Storing regexps in order; enables prioritizing specific ones over generic ones
- Added missing _aegis file for tests
- Configuration update: regexp for ovi music urls
- Re-reading mimeinfo.cache
- Configuration update: e-mail address regexps
- API file contains interfaces that are frozen
- Fixes regular expression for urls in libcontentaction
- Fixes regular expression for emails in libcontentaction
- Added 2 Action::launcherAction functions
- Merging the highlighter tool hl1 into lca-tool (lca-tool --highlight)
- libcontentaction declared 'scope: Platform' in the API file
- Default actions are defined for the content with the '#' in the filename
- Numbers with area code enclosed in "()" are parsed, and not intrepreted as
two distinct set of numbers.
- Numbers seperated by '.' are parsed, not intepreted as distinct set of numbers
- lca doesn't get confused if defaults.list contains nonexistent applications
- Fixes Text Message Viewer / IM Message Viewer - phone number link support
State: new 2010-12-07T06:04:42 maimishr
Comment: None
changes files:
--------------
--- libcontentaction.changes
+++ libcontentaction.changes
@@ -0,0 +1,45 @@
+* Tue Dec 07 2010 Mishra Maitrey <maitrey.mishra at nokia.com> - 0.1.35
+- Feature number - 10498
+- API addition: Action::actionsForString(const QString&)
+- API addition: Action::defaultActionForString(const QString&)
+- Enabling defining regexps specialCaseOf="another-regexp"
+- Configuration update: regexp for phone number
+- Configuration update: added feed-url, ftp-url, ovi-store-url
+- Fixes 2 digits numbers or more than 20 digits number are recognized as tel links
+ in Text Message Viewer / IM Viewer
+- QT_NO_KEYWORDS
+- Don't use QDBusInterface when triggering D-Bus actions
+- Doc update
+- Making regexps case-insensitive
+- Storing regexps in order; enables prioritizing specific ones over generic ones
+- Added missing _aegis file for tests
+- Configuration update: regexp for ovi music urls
+- Re-reading mimeinfo.cache
+- Configuration update: e-mail address regexps
+- API file contains interfaces that are frozen
+- Fixes regular expression for urls in libcontentaction
+- Fixes regular expression for emails in libcontentaction
+- Added 2 Action::launcherAction functions
+- Merging the highlighter tool hl1 into lca-tool (lca-tool --highlight)
+- libcontentaction declared 'scope: Platform' in the API file
+- Default actions are defined for the content with the '#' in the filename
+- Numbers with area code enclosed in "()" are parsed, and not intrepreted as
+ two distinct set of numbers.
+- Numbers seperated by '.' are parsed, not intepreted as distinct set of numbers
+- lca doesn't get confused if defaults.list contains nonexistent applications
+- Fixes Text Message Viewer / IM Message Viewer - phone number link support
+- Fixes Links, phone numbers not highlighted, nor recognised in MMS Viewer
+- Fixing double %-escaping of special characters
+- Defaults.list update
+- Configuration update: http-url regexp
+- Configuration update
+- Fixes music suite service interface changes
+- Small doc fix: .desktop keys were out of date
+- Remove duplicate actions: now it's ok to declare both x-maemo-nepomuk
+ mime types and the corresponding real mime types in a .desktop file
+- Fixes libcontentaction passes a wrong parameter to the music-suite service interface
+- Assume "file" scheme if none given
+- Fixes Method mimeForFile is not returning the mime-type of given file
+- Add autoconf to build-deps
+- Return Icon and Name even for invalid actions
+
old:
----
fix_glib_ftbfs.patch
libcontentaction-0.1.15.tar.gz
new:
----
0001-Fix-python-version-for-tests.patch
libcontentaction-0.1.35.tar.gz
spec files:
-----------
--- libcontentaction.spec
+++ libcontentaction.spec
@@ -1,20 +1,20 @@
#
# Do NOT Edit the Auto-generated Part!
-# Generated by: spectacle version 0.18
+# Generated by: spectacle version 0.20
#
# >> macros
# << macros
Name: libcontentaction
Summary: Library for associating content with actions
-Version: 0.1.15
+Version: 0.1.35
Release: 1
Group: System/Desktop
License: LGPLv2.1
URL: http://maemo.gitorious.org/maemo-af/libcontentaction
Source0: %{name}-%{version}.tar.gz
Source100: libcontentaction.yaml
-Patch0: fix_glib_ftbfs.patch
+Patch0: 0001-Fix-python-version-for-tests.patch
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
BuildRequires: pkgconfig(glib-2.0) >= 2.12.0
@@ -54,7 +54,7 @@
%prep
%setup -q -n %{name}-%{version}
-# fix_glib_ftbfs.patch
+# 0001-Fix-python-version-for-tests.patch
%patch0 -p1
# >> setup
# << setup
other changes:
--------------
++++++ 0001-Fix-python-version-for-tests.patch (new)
--- 0001-Fix-python-version-for-tests.patch
+++ 0001-Fix-python-version-for-tests.patch
+diff -Naur ../libcontentaction-0.1.35//t/applications/ubermeego.desktop libcontentaction-0.1.35//t/applications/ubermeego.desktop
+--- ../libcontentaction-0.1.35//t/applications/ubermeego.desktop 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/applications/ubermeego.desktop 2010-12-03 10:58:55.329381001 +0200
+@@ -6,7 +6,7 @@
+ GenericName=Uber Program
+ Icon=ubericon
+ Comment=View ANYTHING
+-Exec=/usr/bin/python2.5 -c "import sys; print \"uberalles:\", sys.argv[1:]"
++Exec=/usr/bin/python -c "import sys; print \"uberalles:\", sys.argv[1:]"
+ Terminal=false
+ Type=Application
+ MimeType=text/plain;
+diff -Naur ../libcontentaction-0.1.35//t/applications/ubermimeopen.desktop libcontentaction-0.1.35//t/applications/ubermimeopen.desktop
+--- ../libcontentaction-0.1.35//t/applications/ubermimeopen.desktop 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/applications/ubermimeopen.desktop 2010-12-03 10:26:33.517381001 +0200
+@@ -6,7 +6,7 @@
+ GenericName=Uber Program
+ Icon=mimeopenicon
+ Comment=View ANYTHING
+-Exec=/usr/bin/python2.5 -c "import sys; print \"uberalles:\", sys.argv[1:]"
++Exec=/usr/bin/python2.6 -c "import sys; print \"uberalles:\", sys.argv[1:]"
+ Terminal=false
+ Type=Application
+ MimeType=text/plain;
+diff -Naur ../libcontentaction-0.1.35//t/cltool.py libcontentaction-0.1.35//t/cltool.py
+--- ../libcontentaction-0.1.35//t/cltool.py 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/cltool.py 2010-12-03 10:59:39.013381001 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python2.5
++#!/usr/bin/python
+ ##
+ ## Copyright (C) 2009 Nokia. All rights reserved.
+ ##
+diff -Naur ../libcontentaction-0.1.35//t/gallery.py libcontentaction-0.1.35//t/gallery.py
+--- ../libcontentaction-0.1.35//t/gallery.py 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/gallery.py 2010-12-03 10:58:15.173381002 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python2.5
++#!/usr/bin/python
+ import dbus, dbus.service, dbus.mainloop.glib
+ import gobject
+ from sys import stdout, argv
+diff -Naur ../libcontentaction-0.1.35//t/sandbox.sh libcontentaction-0.1.35//t/sandbox.sh
+--- ../libcontentaction-0.1.35//t/sandbox.sh 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/sandbox.sh 2010-12-07 14:24:21.761380992 +0200
+@@ -13,7 +13,6 @@
+
+ case "$1" in
+ --start)
+- exec >/tmp/lca-sandbox-start.log 2>&1
+ echo "Starting"
+ echo "Importing data to tracker"
+ # reset tracker
+diff -Naur ../libcontentaction-0.1.35//t/servicemapper.py libcontentaction-0.1.35//t/servicemapper.py
+--- ../libcontentaction-0.1.35//t/servicemapper.py 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/servicemapper.py 2010-12-03 11:00:16.101381002 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python2.5
++#!/usr/bin/python
+ import os
+ import dbus, dbus.service, dbus.mainloop.glib
+ import gobject
+diff -Naur ../libcontentaction-0.1.35//t/test-defaults.py libcontentaction-0.1.35//t/test-defaults.py
+--- ../libcontentaction-0.1.35//t/test-defaults.py 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/test-defaults.py 2010-12-03 10:55:25.365381002 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python2.5
++#!/usr/bin/python
+ ##
+ ## Copyright (C) 2008, 2009 Nokia. All rights reserved.
+ ##
+diff -Naur ../libcontentaction-0.1.35//t/test-desktop-launching.py libcontentaction-0.1.35//t/test-desktop-launching.py
+--- ../libcontentaction-0.1.35//t/test-desktop-launching.py 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/test-desktop-launching.py 2010-12-03 10:57:08.537381000 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python2.5
++#!/usr/bin/python
+ ##
+ ## Copyright (C) 2010 Nokia. All rights reserved.
+ ##
+diff -Naur ../libcontentaction-0.1.35//t/test-fixed-params.py libcontentaction-0.1.35//t/test-fixed-params.py
+--- ../libcontentaction-0.1.35//t/test-fixed-params.py 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/test-fixed-params.py 2010-12-03 10:57:18.317381001 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python2.5
++#!/usr/bin/python
+ ##
+ ## Copyright (C) 2010 Nokia. All rights reserved.
+ ##
+diff -Naur ../libcontentaction-0.1.35//t/test-invalid-defaults.py libcontentaction-0.1.35//t/test-invalid-defaults.py
+--- ../libcontentaction-0.1.35//t/test-invalid-defaults.py 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/test-invalid-defaults.py 2010-12-03 10:59:53.953381001 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python2.5
++#!/usr/bin/python
+ ##
+ ## Copyright (C) 2008, 2009 Nokia. All rights reserved.
+ ##
+diff -Naur ../libcontentaction-0.1.35//t/test-invoking.py libcontentaction-0.1.35//t/test-invoking.py
+--- ../libcontentaction-0.1.35//t/test-invoking.py 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/test-invoking.py 2010-12-03 10:57:31.385381003 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python2.5
++#!/usr/bin/python
+ ##
+ ## Copyright (C) 2008, 2009 Nokia. All rights reserved.
+ ##
+diff -Naur ../libcontentaction-0.1.35//t/test-mimes.py libcontentaction-0.1.35//t/test-mimes.py
+--- ../libcontentaction-0.1.35//t/test-mimes.py 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/test-mimes.py 2010-12-03 10:56:54.669381001 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python2.5
++#!/usr/bin/python
+ ##
+ ## Copyright (C) 2010 Nokia. All rights reserved.
+ ##
+diff -Naur ../libcontentaction-0.1.35//t/test-regexps.py libcontentaction-0.1.35//t/test-regexps.py
+--- ../libcontentaction-0.1.35//t/test-regexps.py 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/test-regexps.py 2010-12-03 10:58:04.013381002 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python2.5
++#!/usr/bin/python
+ ##
+ ## Copyright (C) 2008-2010 Nokia. All rights reserved.
+ ##
+diff -Naur ../libcontentaction-0.1.35//t/test-servicefw-signals.py libcontentaction-0.1.35//t/test-servicefw-signals.py
+--- ../libcontentaction-0.1.35//t/test-servicefw-signals.py 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/test-servicefw-signals.py 2010-12-03 11:00:31.981381002 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python2.5
++#!/usr/bin/python
+ ##
+ ## Copyright (C) 2008, 2009 Nokia. All rights reserved.
+ ##
+diff -Naur ../libcontentaction-0.1.35//t/test-special-chars.py libcontentaction-0.1.35//t/test-special-chars.py
+--- ../libcontentaction-0.1.35//t/test-special-chars.py 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/test-special-chars.py 2010-12-03 11:00:04.933381000 +0200
+@@ -1,4 +1,4 @@
+-#!/usr/bin/python2.5
++#!/usr/bin/python
+ ##
+ ## Copyright (C) 2008, 2009 Nokia. All rights reserved.
+ ##
+diff -Naur ../libcontentaction-0.1.35//t/tests.xml libcontentaction-0.1.35//t/tests.xml
+--- ../libcontentaction-0.1.35//t/tests.xml 2010-12-01 15:13:57.000000000 +0200
++++ libcontentaction-0.1.35//t/tests.xml 2010-12-07 14:24:00.345381001 +0200
+@@ -4,10 +4,9 @@
+ <set name="libcontentaction" description="Tests for libcontentaction">
+ <pre_steps>
+ <step expected_result="0">
+- . /tmp/session_bus_address.user; \
+- echo "[General]" > /home/user/.config/tracker/tracker-store.cfg; \
+- echo "Verbosity=3" >> /home/user/.config/tracker/tracker-store.cfg; \
+- echo "LowMemoryMode=false" >> /home/user/.config/tracker/tracker-store.cfg; \
++ echo "[General]" > /home/meego/.config/tracker/tracker-store.cfg; \
++ echo "Verbosity=3" >> /home/meego/.config/tracker/tracker-store.cfg; \
++ echo "LowMemoryMode=false" >> /home/meego/.config/tracker/tracker-store.cfg; \
+ cd /usr/share/libcontentaction-tests; \
+ ./sandbox.sh --start
+ </step>
+@@ -15,84 +14,72 @@
+
+ <case name="test-actions" description="A test of questionable value.">
+ <step expected_result="0">
+- . /tmp/session_bus_address.user; \
+ cd /usr/share/libcontentaction-tests; \
+ PATH=.:$PATH XDG_DATA_HOME=/usr/share/libcontentaction-tests ./test-actions.sh
+ </step>
+ </case>
+ <case name="test-mimetypes" description="A test of questionable value.">
+ <step expected_result="0">
+- . /tmp/session_bus_address.user; \
+ cd /usr/share/libcontentaction-tests; \
+ PATH=.:$PATH XDG_DATA_HOME=/usr/share/libcontentaction-tests ./test-mimetypes.sh
+ </step>
+ </case>
+ <case name="test-invoking" description="A test of questionable value.">
+ <step expected_result="0">
+- . /tmp/session_bus_address.user; \
+ cd /usr/share/libcontentaction-tests; \
+ PATH=.:$PATH XDG_DATA_HOME=/usr/share/libcontentaction-tests ./test-invoking.py
+ </step>
+ </case>
+ <case name="test-defaults" description="A test of questionable value.">
+ <step expected_result="0">
+- . /tmp/session_bus_address.user; \
+ cd /usr/share/libcontentaction-tests; \
+ PATH=.:$PATH XDG_DATA_HOME=/usr/share/libcontentaction-tests ./test-defaults.py
+ </step>
+ </case>
+ <case name="test-servicefw-signals" description="A test of questionable value.">
+ <step expected_result="0">
+- . /tmp/session_bus_address.user; \
+ cd /usr/share/libcontentaction-tests; \
+ PATH=.:/usr/lib/libcontentaction-tests:$PATH XDG_DATA_HOME=/usr/share/libcontentaction-tests ./test-servicefw-signals.py
+ </step>
+ </case>
+ <case name="test-mimes" description="A test of questionable value.">
(65 more lines skipped)
++++++ libcontentaction-0.1.15.tar.gz -> libcontentaction-0.1.35.tar.gz
--- .git
+++ .git
+(directory)
--- .git/HEAD
+++ .git/HEAD
+ref: refs/heads/m-branch
--- .git/branches
+++ .git/branches
+(directory)
--- .git/config
+++ .git/config
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+[remote "origin"]
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ url = git at gitorious.org:maemo-af/libcontentaction.git
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
--- .git/description
+++ .git/description
+Unnamed repository; edit this file 'description' to name the repository.
--- .git/hooks
+++ .git/hooks
+(directory)
--- .git/hooks/applypatch-msg.sample
+++ .git/hooks/applypatch-msg.sample
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit. The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/commit-msg" &&
+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
+:
--- .git/hooks/commit-msg.sample
+++ .git/hooks/commit-msg.sample
+#!/bin/sh
+#
+# An example hook script to check the commit log message.
+# Called by "git commit" with one argument, the name of the file
+# that has the commit message. The hook should exit with non-zero
+# status after issuing an appropriate message if it wants to stop the
+# commit. The hook is allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "commit-msg".
+
+# Uncomment the below to add a Signed-off-by line to the message.
+# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
+# hook is more suited to it.
+#
+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
+
+# This example catches duplicate Signed-off-by lines.
+
+test "" = "$(grep '^Signed-off-by: ' "$1" |
+ sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
+ echo >&2 Duplicate Signed-off-by lines.
+ exit 1
+}
--- .git/hooks/post-commit.sample
+++ .git/hooks/post-commit.sample
+#!/bin/sh
+#
+# An example hook script that is called after a successful
+# commit is made.
+#
+# To enable this hook, rename this file to "post-commit".
+
+: Nothing
--- .git/hooks/post-receive.sample
+++ .git/hooks/post-receive.sample
+#!/bin/sh
+#
+# An example hook script for the "post-receive" event.
+#
+# The "post-receive" script is run after receive-pack has accepted a pack
+# and the repository has been updated. It is passed arguments in through
+# stdin in the form
+# <oldrev> <newrev> <refname>
+# For example:
+# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
+#
+# see contrib/hooks/ for a sample, or uncomment the next line and
+# rename the file to "post-receive".
+
+#. /usr/share/doc/git-core/contrib/hooks/post-receive-email
--- .git/hooks/post-update.sample
+++ .git/hooks/post-update.sample
+#!/bin/sh
+#
+# An example hook script to prepare a packed repository for use over
+# dumb transports.
+#
+# To enable this hook, rename this file to "post-update".
+
+exec git update-server-info
--- .git/hooks/pre-applypatch.sample
+++ .git/hooks/pre-applypatch.sample
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed
+# by applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-applypatch".
+
+. git-sh-setup
+test -x "$GIT_DIR/hooks/pre-commit" &&
+ exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
+:
--- .git/hooks/pre-commit.sample
+++ .git/hooks/pre-commit.sample
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed.
+# Called by "git commit" with no arguments. The hook should
+# exit with non-zero status after issuing an appropriate message if
+# it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-commit".
+
+if git rev-parse --verify HEAD >/dev/null 2>&1
+then
+ against=HEAD
+else
+ # Initial commit: diff against an empty tree object
+ against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+fi
+
+# If you want to allow non-ascii filenames set this variable to true.
+allownonascii=$(git config hooks.allownonascii)
+
+# Cross platform projects tend to avoid non-ascii filenames; prevent
+# them from being added to the repository. We exploit the fact that the
+# printable range starts at the space character and ends with tilde.
+if [ "$allownonascii" != "true" ] &&
+ # Note that the use of brackets around a tr range is ok here, (it's
+ # even required, for portability to Solaris 10's /usr/bin/tr), since
+ # the square bracket bytes happen to fall in the designated range.
+ test "$(git diff --cached --name-only --diff-filter=A -z $against |
+ LC_ALL=C tr -d '[ -~]\0')"
+then
+ echo "Error: Attempt to add a non-ascii file name."
+ echo
+ echo "This can cause problems if you want to work"
+ echo "with people on other platforms."
+ echo
+ echo "To be portable it is advisable to rename the file ..."
+ echo
+ echo "If you know what you are doing you can disable this"
+ echo "check using:"
+ echo
+ echo " git config hooks.allownonascii true"
+ echo
+ exit 1
+fi
+
+exec git diff-index --check --cached $against --
--- .git/hooks/pre-rebase.sample
+++ .git/hooks/pre-rebase.sample
+#!/bin/sh
+#
+# Copyright (c) 2006, 2008 Junio C Hamano
+#
+# The "pre-rebase" hook is run just before "git rebase" starts doing
+# its job, and can prevent the command from running by exiting with
+# non-zero status.
+#
+# The hook is called with the following parameters:
+#
+# $1 -- the upstream the series was forked from.
+# $2 -- the branch being rebased (or empty when rebasing the current branch).
+#
+# This sample shows how to prevent topic branches that are already
+# merged to 'next' branch from getting rebased, because allowing it
+# would result in rebasing already published history.
+
+publish=next
+basebranch="$1"
+if test "$#" = 2
+then
+ topic="refs/heads/$2"
+else
+ topic=`git symbolic-ref HEAD` ||
+ exit 0 ;# we do not interrupt rebasing detached HEAD
+fi
+
+case "$topic" in
+refs/heads/??/*)
+ ;;
+*)
+ exit 0 ;# we do not interrupt others.
+ ;;
+esac
+
+# Now we are dealing with a topic branch being rebased
+# on top of master. Is it OK to rebase it?
+
+# Does the topic really exist?
+git show-ref -q "$topic" || {
+ echo >&2 "No such branch $topic"
+ exit 1
+}
+
+# Is topic fully merged to master?
+not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
+if test -z "$not_in_master"
+then
+ echo >&2 "$topic is fully merged to master; better remove it."
+ exit 1 ;# we could allow it, but there is no point.
+fi
+
+# Is topic ever merged to next? If so you should not be rebasing it.
+only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
+only_next_2=`git rev-list ^master ${publish} | sort`
+if test "$only_next_1" = "$only_next_2"
+then
+ not_in_topic=`git rev-list "^$topic" master`
+ if test -z "$not_in_topic"
+ then
+ echo >&2 "$topic is already up-to-date with master"
+ exit 1 ;# we could allow it, but there is no point.
+ else
+ exit 0
+ fi
+else
+ not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
+ /usr/bin/perl -e '
+ my $topic = $ARGV[0];
+ my $msg = "* $topic has commits already merged to public branch:\n";
+ my (%not_in_next) = map {
+ /^([0-9a-f]+) /;
+ ($1 => 1);
+ } split(/\n/, $ARGV[1]);
+ for my $elem (map {
+ /^([0-9a-f]+) (.*)$/;
+ [$1 => $2];
+ } split(/\n/, $ARGV[2])) {
+ if (!exists $not_in_next{$elem->[0]}) {
+ if ($msg) {
+ print STDERR $msg;
+ undef $msg;
+ }
+ print STDERR " $elem->[1]\n";
+ }
+ }
+ ' "$topic" "$not_in_next" "$not_in_master"
+ exit 1
+fi
+
+exit 0
+
+################################################################
+
+This sample hook safeguards topic branches that have been
+published from being rewound.
+
+The workflow assumed here is:
+
+ * Once a topic branch forks from "master", "master" is never
+ merged into it again (either directly or indirectly).
+
+ * Once a topic branch is fully cooked and merged into "master",
+ it is deleted. If you need to build on top of it to correct
+ earlier mistakes, a new topic branch is created by forking at
+ the tip of the "master". This is not strictly necessary, but
+ it makes it easier to keep your history simple.
+
+ * Whenever you need to test or publish your changes to topic
+ branches, merge them into "next" branch.
+
+The script, being an example, hardcodes the publish branch name
+to be "next", but it is trivial to make it configurable via
+$GIT_DIR/config mechanism.
+
+With this workflow, you would want to know:
+
+(1) ... if a topic branch has ever been merged to "next". Young
+ topic branches can have stupid mistakes you would rather
+ clean up before publishing, and things that have not been
+ merged into other branches can be easily rebased without
+ affecting other people. But once it is published, you would
+ not want to rewind it.
+
+(2) ... if a topic branch has been fully merged to "master".
+ Then you can delete it. More importantly, you should not
+ build on top of it -- other people may already want to
+ change things related to the topic as patches against your
+ "master", so if you need further changes, it is better to
+ fork the topic (perhaps with the same name) afresh from the
+ tip of "master".
+
+Let's look at this example:
+
+ o---o---o---o---o---o---o---o---o---o "next"
+ / / / /
+ / a---a---b A / /
+ / / / /
+ / / c---c---c---c B /
+ / / / \ /
+ / / / b---b C \ /
+ / / / / \ /
+ ---o---o---o---o---o---o---o---o---o---o---o "master"
+
+
+A, B and C are topic branches.
+
+ * A has one fix since it was merged up to "next".
+
+ * B has finished. It has been fully merged up to "master" and "next",
+ and is ready to be deleted.
+
+ * C has not merged to "next" at all.
+
+We would want to allow C to be rebased, refuse A, and encourage
+B to be deleted.
+
+To compute (1):
+
+ git rev-list ^master ^topic next
+ git rev-list ^master next
+
+ if these match, topic has not merged in next at all.
+
+To compute (2):
+
+ git rev-list master..topic
+
+ if this is empty, it is fully merged to "master".
--- .git/hooks/prepare-commit-msg.sample
+++ .git/hooks/prepare-commit-msg.sample
+#!/bin/sh
+#
+# An example hook script to prepare the commit log message.
+# Called by "git commit" with the name of the file that has the
+# commit message, followed by the description of the commit
+# message's source. The hook's purpose is to edit the commit
+# message file. If the hook fails with a non-zero status,
+# the commit is aborted.
+#
+# To enable this hook, rename this file to "prepare-commit-msg".
+
+# This hook includes three examples. The first comments out the
+# "Conflicts:" part of a merge commit.
+#
+# The second includes the output of "git diff --name-status -r"
+# into the message, just before the "git status" output. It is
+# commented because it doesn't cope with --amend or with squashed
+# commits.
+#
+# The third example adds a Signed-off-by line to the message, that can
+# still be edited. This is rarely a good idea.
+
+case "$2,$3" in
+ merge,)
+ /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
+
+# ,|template,)
+# /usr/bin/perl -i.bak -pe '
+# print "\n" . `git diff --cached --name-status -r`
+# if /^#/ && $first++ == 0' "$1" ;;
+
+ *) ;;
+esac
+
+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
--- .git/hooks/update.sample
+++ .git/hooks/update.sample
+#!/bin/sh
+#
+# An example hook script to blocks unannotated tags from entering.
+# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
+#
+# To enable this hook, rename this file to "update".
+#
+# Config
+# ------
+# hooks.allowunannotated
+# This boolean sets whether unannotated tags will be allowed into the
+# repository. By default they won't be.
+# hooks.allowdeletetag
+# This boolean sets whether deleting tags will be allowed in the
+# repository. By default they won't be.
+# hooks.allowmodifytag
+# This boolean sets whether a tag may be modified after creation. By default
+# it won't be.
+# hooks.allowdeletebranch
+# This boolean sets whether deleting branches will be allowed in the
+# repository. By default they won't be.
+# hooks.denycreatebranch
+# This boolean sets whether remotely creating branches will be denied
+# in the repository. By default this is allowed.
+#
+
+# --- Command line
+refname="$1"
+oldrev="$2"
+newrev="$3"
+
+# --- Safety check
+if [ -z "$GIT_DIR" ]; then
+ echo "Don't run this script from the command line." >&2
+ echo " (if you want, you could supply GIT_DIR then run" >&2
+ echo " $0 <ref> <oldrev> <newrev>)" >&2
+ exit 1
+fi
+
+if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
+ echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
+ exit 1
+fi
+
+# --- Config
+allowunannotated=$(git config --bool hooks.allowunannotated)
+allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
+denycreatebranch=$(git config --bool hooks.denycreatebranch)
+allowdeletetag=$(git config --bool hooks.allowdeletetag)
+allowmodifytag=$(git config --bool hooks.allowmodifytag)
+
+# check for no description
+projectdesc=$(sed -e '1q' "$GIT_DIR/description")
+case "$projectdesc" in
+"Unnamed repository"* | "")
+ echo "*** Project description file hasn't been set" >&2
+ exit 1
+ ;;
+esac
+
+# --- Check types
+# if $newrev is 0000...0000, it's a commit to delete a ref.
+zero="0000000000000000000000000000000000000000"
+if [ "$newrev" = "$zero" ]; then
+ newrev_type=delete
+else
+ newrev_type=$(git cat-file -t $newrev)
+fi
+
+case "$refname","$newrev_type" in
+ refs/tags/*,commit)
+ # un-annotated tag
+ short_refname=${refname##refs/tags/}
+ if [ "$allowunannotated" != "true" ]; then
+ echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
+ echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
+ exit 1
+ fi
+ ;;
+ refs/tags/*,delete)
+ # delete tag
+ if [ "$allowdeletetag" != "true" ]; then
+ echo "*** Deleting a tag is not allowed in this repository" >&2
+ exit 1
+ fi
+ ;;
+ refs/tags/*,tag)
+ # annotated tag
+ if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
+ then
+ echo "*** Tag '$refname' already exists." >&2
+ echo "*** Modifying a tag is not allowed in this repository." >&2
+ exit 1
+ fi
+ ;;
+ refs/heads/*,commit)
+ # branch
+ if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
+ echo "*** Creating a branch is not allowed in this repository" >&2
+ exit 1
+ fi
+ ;;
+ refs/heads/*,delete)
+ # delete branch
+ if [ "$allowdeletebranch" != "true" ]; then
+ echo "*** Deleting a branch is not allowed in this repository" >&2
+ exit 1
+ fi
+ ;;
+ refs/remotes/*,commit)
+ # tracking branch
+ ;;
+ refs/remotes/*,delete)
+ # delete tracking branch
+ if [ "$allowdeletebranch" != "true" ]; then
+ echo "*** Deleting a tracking branch is not allowed in this repository" >&2
+ exit 1
+ fi
+ ;;
+ *)
+ # Anything else (is there anything else?)
+ echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
+ exit 1
+ ;;
+esac
+
+# --- Finished
+exit 0
--- .git/info
+++ .git/info
+(directory)
--- .git/info/exclude
+++ .git/info/exclude
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
--- .git/logs
+++ .git/logs
+(directory)
--- .git/logs/HEAD
+++ .git/logs/HEAD
+0000000000000000000000000000000000000000 d28a7bcfd3d8cbf6094d67b6a38c8ec50be517ea maimishr <ext-maitrey.mishra at nokia.com> 1291209237 +0200 clone: from git at gitorious.org:maemo-af/libcontentaction.git
+d28a7bcfd3d8cbf6094d67b6a38c8ec50be517ea 479e2f295059b9b0a470ce6013ebf401555030d7 maimishr <ext-maitrey.mishra at nokia.com> 1291209468 +0200 checkout: moving from master to m-branch
--- .git/logs/refs
+++ .git/logs/refs
+(directory)
--- .git/logs/refs/heads
+++ .git/logs/refs/heads
+(directory)
--- .git/logs/refs/heads/m-branch
+++ .git/logs/refs/heads/m-branch
+0000000000000000000000000000000000000000 479e2f295059b9b0a470ce6013ebf401555030d7 maimishr <ext-maitrey.mishra at nokia.com> 1291209468 +0200 branch: Created from 0.1.35
--- .git/logs/refs/heads/master
+++ .git/logs/refs/heads/master
+0000000000000000000000000000000000000000 d28a7bcfd3d8cbf6094d67b6a38c8ec50be517ea maimishr <ext-maitrey.mishra at nokia.com> 1291209237 +0200 clone: from git at gitorious.org:maemo-af/libcontentaction.git
--- .git/objects
+++ .git/objects
+(directory)
--- .git/objects/info
+++ .git/objects/info
+(directory)
--- .git/objects/pack
+++ .git/objects/pack
+(directory)
--- .git/packed-refs
+++ .git/packed-refs
+# pack-refs with: peeled
+2ab603557b496780fb53ebe3c5f49af613eba38b refs/tags/0.1.9
+b8fbd559e0a3ef693fe1b5e022997a399adf1152 refs/tags/0.1.8
+0660deb5336db0ea84d7f6b4bff4f2d05982e025 refs/tags/0.1.7
+0997bad02dc931206787e0ae19c558a22314f6d5 refs/tags/0.1.6
+686b3cae97935f99bf3d1482e5e4c207c0cd66d2 refs/tags/0.1.5
+40a7f0f7c014b844623a06731977ce5daed58fbc refs/tags/0.1.4
+^b5c8c72803c5bf6bfa4e48e99f42d772955d7464
+479e2f295059b9b0a470ce6013ebf401555030d7 refs/tags/0.1.35
+695c26acfa3565d868bd1bf813f1c3028a9d5633 refs/tags/0.1.34
+c4f5dbf61e4d761a54a02cf4a975ec3be61410ae refs/tags/0.1.33
+b53bcea1e80414a5f79977d5a383cf4f188b417b refs/tags/0.1.32
+848ccfd86690f0a8f0597768ec6e8c06b5cb8ecb refs/tags/0.1.31
+9b79e321c2fb3a9c9d30069daa4219597db85b57 refs/tags/0.1.30
+679712b44dd5981ce343add9d4aa50d7b809fae7 refs/tags/0.1.3
+c988686f6359dd7d7d38ca4a01e1501bb4650842 refs/tags/0.1.29
+dc333aefdb8299d037160c6fb146d483ee920eca refs/tags/0.1.28
+752d37bfa15fe0d6012b063fd9a57f7e5dc2e6cf refs/tags/0.1.27
+4f640f9f57a8f4feafa9c67c264519edade16a1c refs/tags/0.1.26
+c5c6009dc2af778eb2c42ee64803c6c8556d2f65 refs/tags/0.1.25
+db7c3ff3339d5360526643df36d0857b3f09e0fa refs/tags/0.1.24
+dec2f7ba527a11ffc8a74d177b31f4ce455ed8bd refs/tags/0.1.23
+6696e362a5b77124efe059445244b94469f95afc refs/tags/0.1.22
+270d91bb97addc1f1af9848ba9fea7aac9dc979b refs/tags/0.1.21
+1f8e24f9fd6354b06fc14b49d304b7f9e07191b3 refs/tags/0.1.20
+4cf6dc9eddc5ecce9f606b887a8c5c386a29d855 refs/tags/0.1.2
+29f9105b2e8599b33ec2eb8ed1fb4c4422ae727e refs/tags/0.1.19
+59bc44d59f486d71ba77bf9e676dd7058d92531b refs/tags/0.1.18
+8920565ee41a613cf3b4ece9f358543075ee5045 refs/tags/0.1.17
+25e1ba874a2f3f91593aa793863128334753553c refs/tags/0.1.16
+2e0943652ad1251bfa3cba2a0348328271348476 refs/tags/0.1.15
+1bb6aafbc98ff26a1f70edd093e2daf18591d4e2 refs/tags/0.1.14
+508e671adb9774448c4d2c36547fad5f9404e3c0 refs/tags/0.1.13
+ae61655069cad8b06d5f3a49cbf560aefe53fa4a refs/tags/0.1.12
+da1e01931cb28ad4894f1ae86fd7daf878cdb71f refs/tags/0.1.11
+86d704801eea7a62750d30c26fe1366f05308430 refs/tags/0.1.10
+25ce56bf7b7ffbf7667aaa5a73aac3856fca3a94 refs/tags/0.1.1
+^65042c8e68f7b909354bfd3791486bcc62b79e0b
+09fe661ede23b6d7edcd26fa24361e9b89d9bfb8 refs/tags/0.1.0
+dbfb8e3277d39d4a8f325018724de587aed632a8 refs/tags/0.0.8.1
+^61e925b5b0879bf7d104d416a10575b6d6699840
+80b66f2da037f4489a6b5fb7709baf6253820532 refs/tags/0.0.8
+05f8524c613352d10622c087c472d5352a2c7263 refs/tags/0.0.7
+f3e3c5ffea6f412e7875fa28b2185acb87d39ba2 refs/tags/0.0.6
+7795c8d41c087af0309ed6c9be61dd7fc9f92f2f refs/tags/0.0.5
+1863d0f1fcca9d4b388ac4f96a198dc2d67ac176 refs/tags/0.0.4
+79e944cc0ccb34da669f8b85399039c3cda94297 refs/tags/0.0.3
+0f03a794f7eabe70df769ae92e00f91239caa599 refs/tags/0.0.2
+36f748db9cc7c4956b6ef3728747e5fe89971b04 refs/tags/0.0.1
+d28a7bcfd3d8cbf6094d67b6a38c8ec50be517ea refs/remotes/origin/master
+027f591e6104b846513fe9e96dd9c31638cb58f7 refs/remotes/origin/docs
--- .git/refs
+++ .git/refs
+(directory)
--- .git/refs/heads
+++ .git/refs/heads
+(directory)
--- .git/refs/heads/m-branch
+++ .git/refs/heads/m-branch
+479e2f295059b9b0a470ce6013ebf401555030d7
--- .git/refs/heads/master
+++ .git/refs/heads/master
+d28a7bcfd3d8cbf6094d67b6a38c8ec50be517ea
--- .git/refs/remotes
+++ .git/refs/remotes
+(directory)
--- .git/refs/remotes/origin
+++ .git/refs/remotes/origin
+(directory)
--- .git/refs/remotes/origin/HEAD
+++ .git/refs/remotes/origin/HEAD
+ref: refs/remotes/origin/master
--- .git/refs/tags
+++ .git/refs/tags
+(directory)
--- .gitignore
+++ .gitignore
@@ -33,6 +33,7 @@
t/hldemo
t/hl1
t/l10ntest
+t/*.pyo
t/test-l10n-data/test_en.qm
t/test-l10n-data/test_hu.qm
--- configure.ac
+++ configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ([2.61])
-AC_INIT([libcontentaction], [0.1.15], [marius.vollmer at nokia.com], libcontentaction)
+AC_INIT([libcontentaction], [0.1.35], [marius.vollmer at nokia.com], libcontentaction)
AC_CONFIG_SRCDIR([Makefile.am])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
@@ -8,7 +8,7 @@
AC_LANG([C++])
AC_PROG_CXX
-CXXFLAGS="$CXXFLAGS -Wall -Werror"
+CXXFLAGS="$CXXFLAGS -Wall -Werror -DQT_NO_KEYWORDS"
AC_DISABLE_STATIC
AC_PROG_LIBTOOL
AC_PROG_QT_MOC
--- data/Makefile.am
+++ data/Makefile.am
@@ -3,7 +3,9 @@
tracker1.xml \
highlight1.xml
-EXTRA_DIST = \
+testdatadir = $(datadir)/libcontentaction-tests/data
+dist_testdata_DATA = \
+ highlight1.xml \
hl-examples.xml
applicationsdir = $(datadir)/applications
--- data/defaults.list
+++ data/defaults.list
@@ -5,6 +5,7 @@
application/msword=office-tools.desktop
application/pdf=office-tools.desktop
application/rss+xml=feedreader.desktop
+application/smil=musicsuiteplaylistinterface.desktop
application/vnd.ms-powerpoint=office-tools.desktop
application/vnd.oasis.opendocument.presentation=office-tools.desktop
application/vnd.oasis.opendocument.spreadsheet=office-tools.desktop
@@ -17,28 +18,32 @@
application/vnd.openxmlformats-officedocument.wordprocessingml.document=office-tools.desktop
application/vnd.openxmlformats-officedocument.wordprocessingml.template=office-tools.desktop
application/x-mplayer2=musicsuiteinterface.desktop
+application/x-smil=musicsuiteplaylistinterface.desktop
application/x-vnd.oasis.opendocument.presentation=office-tools.desktop
application/x-vnd.oasis.opendocument.spreadsheet=office-tools.desktop
application/x-vnd.oasis.opendocument.text=office-tools.desktop
audio/AMR-WB=musicsuiteinterface.desktop
audio/AMR=musicsuiteinterface.desktop
+audio/aac=musicsuiteinterface.desktop
audio/mp2=musicsuiteinterface.desktop
audio/mp3=musicsuiteinterface.desktop
audio/mp4=musicsuiteinterface.desktop
audio/mpeg=musicsuiteinterface.desktop
-audio/mpegurl=musicsuiteinterface.desktop
+audio/mpegurl=musicsuiteplaylistinterface.desktop
+audio/playlist=musicsuiteplaylistinterface.desktop
audio/wav=musicsuiteinterface.desktop
audio/x-amr=musicsuiteinterface.desktop
audio/x-m4a=musicsuiteinterface.desktop
audio/x-mp2=musicsuiteinterface.desktop
audio/x-mpeg=musicsuiteinterface.desktop
-audio/x-mpegurl=musicsuiteinterface.desktop
+audio/x-mpegurl=musicsuiteplaylistinterface.desktop
audio/x-ms-asx=musicsuiteinterface.desktop
audio/x-ms-wax=musicsuiteinterface.desktop
audio/x-ms-wma=musicsuiteinterface.desktop
-audio/x-scpls=musicsuiteinterface.desktop
+audio/x-scpls=musicsuiteplaylistinterface.desktop
audio/x-wav=musicsuiteinterface.desktop
message/rfc822=mail.desktop
+text/html=fennec.desktop
text/plain=office-tools.desktop
video/3gpp2=videosuiteinterface.desktop
video/3gpp=videosuiteinterface.desktop
@@ -50,6 +55,11 @@
video/x-ms-wmv=videosuiteinterface.desktop
video/x-msvideo=videosuiteinterface.desktop
video/x-xvid=videosuiteinterface.desktop
+x-maemo-highlight/http-url=fennec.desktop
x-maemo-nepomuk/contact=opencontactcard.desktop
x-maemo-nepomuk/email=mail.desktop
+x-maemo-urischeme/file=fennec.desktop
+x-maemo-urischeme/ftp=fennec.desktop
+x-maemo-urischeme/http=fennec.desktop
+x-maemo-urischeme/https=fennec.desktop
x-maemo-urischeme/mailto=mail.desktop
--- data/highlight1.xml
+++ data/highlight1.xml
@@ -1,8 +1,10 @@
<?xml version="1.0"?>
<actions>
-
- <highlight regexp="[^\s@]+@([^\s.]+)(\.[^\s.]+)*" name="email-address"/>
- <highlight regexp="\+?\d+([- ]\d+)*" name="phone-number"/>
- <highlight regexp="http://(\w+((:\w+)?)@)?(\w+\.)+\w+(:\d+)?(/[\w ./?%&=]*)?" name="http-url"/>
-
+ <highlight regexp="(mailto:)?[\w!#$%&'*+/=?^`{|}~-]+(\.[\w!#$%&'*+/=?^`{|}~-]+)*@([\w-]+\.)+[\w-]+" name="email-address"/>
+ <highlight regexp="((\+ ?)|\b|\(\d+\))(\(\d+\) ?|\d[-.pwxPWX# ]?){2,19}\d(?!\d)" name="phone-number"/>
+ <highlight regexp="(https?://)?music\.ovi\.com(/[\w/?%:;@&=+$,\-.!~*'()]*)?" name="ovi-music-url" specialCaseOf="http-url"/>
+ <highlight regexp="(https?://)?store\.ovi\.(com|mobi)(.cn)?(/[\w/?%:;@&=+$,\-.!~*'()]*)?" name="ovi-store-url" specialCaseOf="http-url"/>
+ <highlight regexp="(https?://|www\.)(\w+((:\w+)?)@)?([\w\-]+\.)+[\w\-]+(:\d+)?(/[\w/?%:;@&=+$,\-.!~*'()]*)?" name="http-url"/>
+ <highlight regexp="ftp://(\w+((:\w+)?)@)?([\w\-]+\.)+[\w\-]+(:\d+)?(/[\w/?%:;@&=+$,\-.!~*'()]*)?" name="ftp-url"/>
+ <highlight regexp="feed:(//)?(\w+((:\w+)?)@)?([\w\-]+\.)+[\w\-]+(:\d+)?(/[\w/?%:;@&=+$,\-.!~*'()]*)?" name="feed-url"/>
</actions>
--- data/hl-examples.xml
+++ data/hl-examples.xml
@@ -2,9 +2,21 @@
<actions>
<!-- the following highlight rules are just examples -->
- <highlight regexp="[^\s@]+@([^\s.]+)(\.[^\s.]+)*" name="email"/>
- <highlight regexp="\+?\d+([- ]\d+)*" name="phone"/>
- <highlight regexp="http://(\w+((:\w+)?)@)?(\w+\.)+\w+(:\d+)?(/[\w ./?%&=]*)?" name="url"/>
- <highlight regexp="http://(\w+((:\w+)?)@)?example.com(:\d+)?(/[\w ./?%&=]*)?" name="ovoda"/>
+ <highlight regexp="http://(\w+((:\w+)?)@)?example.com(:\d+)?(/[\w ./?%&=]*)?" name="special-url"/>
+
+ <!-- testing the special case relationships: general case + 2 specializations -->
+ <highlight regexp="foobar\w*" name="special-1a" specialCaseOf="general-1"/>
+ <highlight regexp="foo\w*" name="general-1"/>
+ <highlight regexp="foobaz\w*" name="special-1b" specialCaseOf="general-1"/>
+
+ <!-- testing the special case relationships: general case + specialization + its specialization -->
+ <highlight regexp="cat\w*" name="general-2"/>
+ <highlight regexp="catdogzebra\w*" name="superspecial-2" specialCaseOf="special-2"/>
+ <highlight regexp="catdog\w*" name="special-2" specialCaseOf="general-2"/>
+
+ <!-- testing the special case relationships: even the circular case shouldn't confuse the computation -->
+ <highlight regexp="circ" name="circular-1" specialCaseOf="circular-2"/>
+ <highlight regexp="circ2" name="circular-2" specialCaseOf="circular-1"/>
+
</actions>
--- data/tracker1.xml
+++ data/tracker1.xml
@@ -70,11 +70,6 @@
{ ?uri a nmo:IMMessage . }
</tracker-condition>
- <!-- dont use this, use music-piece instead -->
- <tracker-condition name="musicpiece">
- { ?uri a nmm:MusicPiece . }
- </tracker-condition>
-
<tracker-condition name="music-piece">
{ ?uri a nmm:MusicPiece . }
</tracker-condition>
--- debian/api
+++ debian/api
@@ -1,6 +1,8 @@
interface: libcontentaction
type: library
-scope: Nokia MeeGo
-state: experimental
+scope: Platform
+state: stable
libs-pkg: libcontentaction0
dev-pkg: libcontentaction-dev
+doc-type: doxygen
+doxygen-conf: doc/doxy.cfg
--- debian/changelog
+++ debian/changelog
@@ -1,3 +1,147 @@
+libcontentaction (0.1.35) unstable; urgency=low
+
+ * API addition: Action::actionsForString(const QString&)
+ * API addition: Action::defaultActionForString(const QString&)
+ * Enabling defining regexps specialCaseOf="another-regexp"
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Wed, 01 Dec 2010 14:02:49 +0200
+
+libcontentaction (0.1.34) unstable; urgency=low
+
+ * Configuration update: regexp for phone number
+ * Configuration update: added feed-url, ftp-url, ovi-store-url
+ * Fixes: NB#191300
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Mon, 29 Nov 2010 12:00:30 +0200
+
+libcontentaction (0.1.33) unstable; urgency=low
+
+ * QT_NO_KEYWORDS
+ * Configuration update: regexp for phone number
+ * Fixes: NB#191300
+ * Don't use QDBusInterface when triggering D-Bus actions (workaround, QTBUG-14485)
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Thu, 28 Oct 2010 13:59:32 +0300
+
+libcontentaction (0.1.32) unstable; urgency=low
+
+ * Doc update.
+ * Making regexps case-insensitive.
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Thu, 07 Oct 2010 10:23:24 +0300
+
+libcontentaction (0.1.31) unstable; urgency=low
+
+ * Storing regexps in order; enables prioritizing specific ones over generic ones.
+ * Added missing _aegis file for tests
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Wed, 29 Sep 2010 09:18:23 +0300
+
+libcontentaction (0.1.30) unstable; urgency=low
+
+ * Configuration update: regexp for ovi music urls
+ * Re-reading mimeinfo.cache
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Fri, 24 Sep 2010 14:53:02 +0300
+
+libcontentaction (0.1.29) unstable; urgency=low
+
+ * Fixes: NB#191392
+ * Fixes: NB#191945
+ * Configuration update: e-mail address regexps
+ * Fixes: NB#191957
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Thu, 23 Sep 2010 10:37:25 +0300
+
+libcontentaction (0.1.28) unstable; urgency=low
+
+ * Added 2 Action::launcherAction functions.
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Fri, 17 Sep 2010 13:17:13 +0300
+
+libcontentaction (0.1.27) unstable; urgency=low
+
+ * Fixes: NB#192179
+ * Merging the highlighter tool hl1 into lca-tool (lca-tool --highlight)
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Thu, 16 Sep 2010 11:53:09 +0300
+
+libcontentaction (0.1.26) unstable; urgency=low
+
+ * Fixes: NB#191945
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Wed, 15 Sep 2010 10:14:26 +0300
+
+libcontentaction (0.1.25) unstable; urgency=low
+
+ * Fixes: NB#191791
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Tue, 14 Sep 2010 12:10:12 +0300
+
+libcontentaction (0.1.24) unstable; urgency=low
+
+ * Configuration update: regexps
+ * Fixes: NB#191491
+ * Fixes: NB#191290
+ * Fixes: NB#179385
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Mon, 13 Sep 2010 13:04:21 +0300
+
+libcontentaction (0.1.23) unstable; urgency=low
+
+ * Fixes: NB#190808
+ * lca doesn't get confused if defaults.list contains nonexistent applications
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Mon, 13 Sep 2010 09:36:06 +0300
+
+libcontentaction (0.1.22) unstable; urgency=low
+
+ * Fixing double %-escaping of special characters.
+ * Defaults.list update
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Mon, 06 Sep 2010 10:12:26 +0300
+
+libcontentaction (0.1.21) unstable; urgency=low
+
+ * Configuration update: http-url regexp.
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Fri, 03 Sep 2010 12:19:00 +0300
+
+libcontentaction (0.1.20) unstable; urgency=low
+
+ * Configuration update.
+ * Fixes: NB#189612
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Wed, 01 Sep 2010 12:43:48 +0300
+
+libcontentaction (0.1.19) unstable; urgency=low
+
+ * Small doc fix: .desktop keys were out of date.
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Wed, 01 Sep 2010 11:50:39 +0300
+
+libcontentaction (0.1.18) unstable; urgency=low
+
+ * Remove duplicate actions: now it's ok to declare both x-maemo-nepomuk
+ mime types and the corresponding real mime types in a .desktop file.
+ * Fixes: NB#186435
+
+ -- Marja Hassinen <marja.hassinen at nokia.com> Mon, 30 Aug 2010 10:39:56 +0300
+
+libcontentaction (0.1.17) unstable; urgency=low
+
+ * Assume "file" scheme if none given.
+ * Fixes: NB#180448
+ * Fixes: NB#187474
+
+ -- Akos PASZTORY <ext-akos.pasztory at nokia.com> Thu, 26 Aug 2010 10:38:29 +0300
+
+libcontentaction (0.1.16) unstable; urgency=low
+
+ * Return Icon and Name even for invalid actions.
+
+ -- Akos PASZTORY <ext-akos.pasztory at nokia.com> Wed, 18 Aug 2010 12:49:36 +0300
+
libcontentaction (0.1.15) unstable; urgency=low
* Added an API file, whatever it is.
--- debian/control
+++ debian/control
@@ -7,7 +7,9 @@
libglib2.0-dev (>= 2.12.0),
libmeegotouch-dev,
doxygen (>= 1.5.9),
- pkg-config
+ pkg-config,
+ autoconf, automake, libtool,
+ aegis-builder (>= 1.4)
Standards-Version: 3.8.0
Package: libcontentaction0
--- debian/libcontentaction-tests.aegis
+++ debian/libcontentaction-tests.aegis
+<aegis>
+ <request>
+ <credential name="TrackerReadAccess" />
+ <for path="/usr/lib/libcontentaction-tests/servicetest" />
+ </request>
+</aegis>
--- debian/libcontentaction0.aegis
+++ debian/libcontentaction0.aegis
+<aegis>
+ <request>
+ <credential name="TrackerReadAccess" />
+ <for path="/usr/bin/lca-tool" />
+ </request>
+</aegis>
--- debian/rules
+++ debian/rules
@@ -63,6 +63,8 @@
dh_gencontrol -a
dh_md5sums -a
dh_builddeb -a
+ aegis-deb-add -control debian/libcontentaction0/DEBIAN/control .. debian/libcontentaction0.aegis=_aegis
+ aegis-deb-add -control debian/libcontentaction-tests/DEBIAN/control .. debian/libcontentaction-tests.aegis=_aegis
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install
--- src/config.cpp
+++ src/config.cpp
@@ -36,7 +36,10 @@
using namespace ContentAction::Internal;
// mime type -> regexp
-static QHash<QString, QString> Highlighter_cfg;
+static QList<QPair<QString, QString> > Highlighter_cfg;
+// raw data for Highlighter_cfg
+static QHash<QString, QString> mimeToRegexp;
+static QHash<QString, QString> mimeToParent;
// friendly tracker condition name => sparql snippet
static QHash<QString, QString> Tracker_cfg;
@@ -101,7 +104,10 @@
QString mime = atts.value("name").trimmed();
if (mime.isEmpty())
fail("expected a nonempy mimetype");
- Highlighter_cfg[mime.prepend(HighlighterMimeClass)] = regexp;
+ mimeToRegexp.insert(mime, regexp);
+ QString parentRegexp = atts.value("specialCaseOf");
+ if (!parentRegexp.isEmpty())
+ mimeToParent.insert(mime, parentRegexp);
}
else if (qname == "tracker-condition") {
state = inTrackerCondition;
@@ -155,6 +161,39 @@
#undef fail
+// Constructs Highlighter_cfg from mimeToRegexp and mimeToParent. Sorts the
+// regexps topologically so that the special cases appear before the general
+// cases.
+static void sortRegexps()
+{
+ // Insert the regexps in the wrong order (parent first, parent is the more
+ // general regexp). But always prepend, so the list will be in the right
+ // order (special case before the general case).
+ QString toInsert;
+ QString original;
+ while (!mimeToRegexp.isEmpty()) {
+ // Take any regexp
+ toInsert = mimeToRegexp.begin().key();
+ original = toInsert; // store the starting point (for loop detection)
+ while (mimeToParent.contains(toInsert)
+ && mimeToRegexp.contains(mimeToParent.value(toInsert))) {
+ // There is a parent and parent not yet inserted
+ toInsert = mimeToParent.value(toInsert);
+
+ if (toInsert == original) {
+ LCA_WARNING << "Loop in regexp specialization:" << toInsert;
+ // a loop
+ break;
+ }
+ }
+ // Insert, and also remove from mimeToRegexp to note it has been
+ // inserted.
+ Highlighter_cfg.prepend(
+ qMakePair(QString(HighlighterMimeClass) + toInsert,
+ mimeToRegexp.take(toInsert)));
+ }
+}
+
static void readConfig()
{
static bool read = false;
@@ -170,7 +209,7 @@
}
dir.setNameFilters(QStringList("*.xml"));
QStringList confFiles = dir.entryList(QDir::Files);
- foreach (const QString& confFile, confFiles) {
+ Q_FOREACH (const QString& confFile, confFiles) {
QFile file(dir.filePath(confFile));
ConfigReader handler;
@@ -182,13 +221,19 @@
continue;
}
}
+
+ // Sort the regexps topologially: each regexp (e.g., a specialized url)
+ // before its parent (e.g., a more general url)
+ sortRegexps();
+ mimeToRegexp.clear();
+ mimeToParent.clear();
}
} // end anon namespace
/// Returns the highlighter configuration map of (mimetype, regexp) read from
/// the configuration files.
-const QHash<QString, QString>& ContentAction::Internal::highlighterConfig()
+const QList<QPair<QString, QString> >& ContentAction::Internal::highlighterConfig()
{
readConfig();
return Highlighter_cfg;
--- src/contentaction.cpp
+++ src/contentaction.cpp
@@ -95,19 +95,19 @@
LCA_WARNING << "triggered an invalid action, not doing anything.";
}
-DefaultPrivate::DefaultPrivate(MDesktopEntry* desktopEntry, const QStringList& params)
- : desktopEntry(desktopEntry), params(params)
+DefaultPrivate::DefaultPrivate(QSharedPointer<MDesktopEntry> desktopEntry,
+ const QStringList& params, bool valid)
+ : desktopEntry(desktopEntry), params(params), valid(valid)
{
}
DefaultPrivate::~DefaultPrivate()
{
- delete desktopEntry;
}
bool DefaultPrivate::isValid() const
{
- return true;
+ return valid;
}
QString DefaultPrivate::name() const
@@ -146,9 +146,20 @@
{
}
-Action createAction(const QString& desktopFile, const QStringList& params)
+/// Creates an Action object which will launch the application defined by \a
+/// desktopFilePath with the given \a params when triggered.
+Action createAction(const QString& desktopFilePath, const QStringList& params)
+{
+ QSharedPointer<MDesktopEntry> desktopEntry(new MDesktopEntry(
+ desktopFilePath));
+ return createAction(desktopEntry, params);
+}
+
+/// Creates an Action object which will launch the application defined by \a
+/// desktopEntry with the given \a params when triggered.
+Action createAction(QSharedPointer<MDesktopEntry> desktopEntry,
+ const QStringList& params)
{
- MDesktopEntry* desktopEntry = new MDesktopEntry(desktopFile);
if (desktopEntry->contains(XMaemoMethodKey) &&
!desktopEntry->contains(XMaemoServiceKey)) {
return Action(new ServiceFwPrivate(desktopEntry, params));
@@ -161,9 +172,8 @@
return Action(new ExecPrivate(desktopEntry, params));
}
else {
- delete desktopEntry;
// We don't know how to launch
- return Action(new ActionPrivate());
+ return Action(new DefaultPrivate(desktopEntry, params, false));
}
}
@@ -205,4 +215,25 @@
return d->icon();
}
+/// Creates an action that will launch the given application (specified by
+/// .desktop file name) with the \a params the way the application specifies in
+/// their .desktop file. \a app is the name of the .desktop file (with the
+/// .desktop extension). It is looked for in the standard locations.
+Action Action::launcherAction(const QString& app, const QStringList& params)
+{
+ QString appDesktop = findDesktopFile(app);
+ if (!appDesktop.isEmpty()) {
+ return createAction(appDesktop, params);
+ }
+ return Action();
+}
+
+/// Creates an action that will launch the given application (specified by
+/// MDesktopEntry) with the \a params the way the application specifies in
+/// their .desktop file.
+Action Action::launcherAction(QSharedPointer<MDesktopEntry> mDesktop, const QStringList& params)
+{
+ return createAction(mDesktop, params);
+}
+
} // end namespace
--- src/contentaction.h
+++ src/contentaction.h
@@ -37,6 +37,7 @@
#endif
class MLabel;
+class MDesktopEntry;
namespace ContentAction
{
@@ -57,12 +58,18 @@
static Action defaultActionForFile(const QUrl& fileUri);
static Action defaultActionForFile(const QUrl& fileUri, const QString& mimeType);
static Action defaultActionForScheme(const QString& uri);
+ static Action defaultActionForString(const QString& param);
static QList<Action> actions(const QString& uri);
static QList<Action> actions(const QStringList& uris);
static QList<Action> actionsForFile(const QUrl& fileUri);
static QList<Action> actionsForFile(const QUrl& fileUri, const QString& mimeType);
static QList<Action> actionsForScheme(const QString& uri);
+ static QList<Action> actionsForString(const QString& param);
+
+ static Action launcherAction(const QString& app, const QStringList& params);
+ static Action launcherAction(QSharedPointer<MDesktopEntry>,
+ const QStringList& params);
static QList<Match> highlight(const QString& text);
@@ -78,7 +85,10 @@
QSharedPointer<ActionPrivate> d;
- friend Action createAction(const QString& desktopFileId, const QStringList& params);
+ friend Action createAction(const QString& desktopFilePath,
+ const QStringList& params);
+ friend Action createAction(QSharedPointer<MDesktopEntry> desktopEntry,
+ const QStringList& params);
};
struct LCA_EXPORT Match {
--- src/dbus.cpp
+++ src/dbus.cpp
@@ -24,7 +24,8 @@
#include <MDesktopEntry>
#include <QVariantList>
-#include <QDBusInterface>
+#include <QDBusConnection>
+#include <QDBusMessage>
#include <QDBusPendingCall>
using namespace ContentAction::Internal;
@@ -33,7 +34,8 @@
const QString XMaemoFixedArgsKey("Desktop Entry/X-Maemo-Fixed-Args");
-DBusPrivate::DBusPrivate(MDesktopEntry* desktopEntry, const QStringList& _params)
+DBusPrivate::DBusPrivate(QSharedPointer<MDesktopEntry> desktopEntry,
+ const QStringList& _params)
: DefaultPrivate(desktopEntry, _params), varArgs(false)
{
// mime_open X-Osso-Service
@@ -81,18 +83,26 @@
void DBusPrivate::trigger() const
{
+ // Call a D-Bus function asynchronously. Don't use a QDBusInterface because
+ // it creates a blocking Introspect call, see
+ // http://bugreports.qt.nokia.com/browse/QTBUG-14485
+
if (varArgs) {
// Call a D-Bus function with a variable length argument list
QVariantList vargs;
- foreach (const QString& param, params)
+ Q_FOREACH (const QString& param, params)
vargs << param;
- QDBusInterface launcher(busName, objectPath, iface);
- launcher.callWithArgumentList(QDBus::NoBlock, method, vargs);
+ QDBusMessage message = QDBusMessage::createMethodCall(busName, objectPath, iface, method);
+ message.setArguments(vargs);
+ QDBusConnection::sessionBus().asyncCall(message);
}
else {
// Call a D-Bus function with a string list
- QDBusInterface launcher(busName, objectPath, iface);
- launcher.asyncCall(method, params);
+
+ QDBusMessage message = QDBusMessage::createMethodCall(busName, objectPath, iface, method);
+ message.setArguments(QVariantList() << params);
+ QDBusConnection::sessionBus().asyncCall(message);
+
// FIXME: What if we're launching a non-meegotouch desktop file, and we don't
// have any func taking a string list; only a func taking nothing?
}
--- src/doc.h
+++ src/doc.h
@@ -2,142 +2,195 @@
\mainpage libcontentaction
-\brief a library for associating URIs to the set of applicable
-ContentAction::Action objects and triggering the actions.
+\brief This library associates files, Tracker URIs, and text snippets to a
+set of applicable ContentAction::Action objects and triggers the actions.
-\section Overview
+\section overview Overview
-The libcontentaction library retrieves associated actions
-(ContentAction::Action objects) for files, objects stored in Tracker and
-regular expressions in free text. It may be used to query the default
-action as well. The Action object can be used to trigger() the action.
+The libcontentaction library retrieves associated actions (ContentAction::Action
+objects) for files, objects stored in Tracker, and regular expressions (regexp)
+in free text. It may also be used to query the default action. The Action
+object can be used to trigger() the action.
-Actions correspond to .desktop files and they can be installed independently
+Actions correspond to .desktop files, and they can be installed independently
from libcontentaction.
-In case of file URIs, the library finds out the mime type and uses that as a
-key of the association. For objects stored in Tracker, the ontology classes
-are used for this purpose. Finally, the library provides
-ContentAction::highlightLabel() for adding highlighters to a MLabel
-based on the available actions handling regexps.
-
-\section providing_actions Providing actions
+For file URIs, the library finds out the MIME type and uses it as a key of the
+association. For objects stored in Tracker, the library adds the custom MIME
+types that target them. Finally, the library provides
+ContentAction::highlightLabel(), which adds highlighters to an MLabel based on
+the actions associated with regular expressions (such as phone numbers and
+e-mail addresses).
Actions can target one of the following:
--# mime types (\c image/jpeg)
+-# MIME types (\c image/jpeg)
-# Tracker-query based conditions (\c x-maemo-nepomuk/contact)
-# regular expressions (\c x-maemo-highlight/phonenumber)
-# URI schemes (\c x-maemo-urischeme/mailto)
-The library supports launching actions with one of the following methods:
+\section detaileddescription Detailed description
--# launch a MeeGoTouch based application using the MApplication D-Bus interface
--# call a D-Bus method specified in the .desktop file
--# call a Maemo Service Framework method
--# execute a binary
--# call the legacy mime_open method
+libcontentaction = \ref xdgmimehandling "XDG MIME type handling"
+ + \ref customlaunch
+ + \ref custommime "Custom MIME types"
+ + \ref highlighter
-All D-Bus based invocation methods (except mime_open) require the receiver
-to accept an array of strings.
+The following sections describe how libcontentaction extends the XDG MIME
+type handling system.
-To define a new action, drop a .desktop file in /usr/share/applications (or
-in one of the directories in $XDG_DATA_DIRS).
+\section xdgmimehandling XDG MIME type handling
-When you install a debian package which puts a file in /usr/share/applications, debian triggers take
-care of calling update-desktop-database which gathers information about handled mime types to
-/usr/share/mimeinfo.cache. When experimenting, you might want to call update-desktop-database
-manually.
+XDG MIME type handling associates files with applications which can open them.
+Each file has an associated MIME type, and applications define which MIME types
+they can handle.
-\subsection writing_desktopfile Writing .desktop files for actions
+Applications define which MIME types they handle in the .desktop file
+installed to /usr/share/applications. (See also \c $XDG_DATA_DIRS and \c
+$XDG_DATA_HOME in the XDG Base Directory specification.)
-Let's take an image viewer for example.
+Example of a .desktop file called /usr/share/applications/myimageviewer.desktop:
\verbatim
[Desktop Entry]
Type=Application
-Icon=gallery.png
-;; This is needed to prevent this action appearing in the launcher.
-NotShowIn=X-MeeGo;
+Name=MyImageViewer
+Name[en]=My Image Viewer
+Name[fi]=Kuvankatselu
+Exec=/usr/bin/myimgview --view %U
+Icon=myimgview.png
+MimeType=image/jpeg;image/png;
+\endverbatim
-;; Defining a localization method:
-;; 1. MeeGoTouch-based
-X-MeeGo-translation-catalog=gallery_catalog
-X-MeeGo-logical-id=view_logical_id
-;; 2. XDG style
-Name=View in gallery
-Name[fi]=Näytä galleriassa
+The \c MimeType line contains the list of MIME types that the application
+handles. Wildcards (such as \c image/*) are allowed.
-;; Defining when this action applies:
-;; 1. ordinary mimetypes
-MimeType=image/*;text/plain;
-;; 2. Tracker-query based conditions
-MimeType=x-maemo-nepomuk/contact;
-;; 3. pre-defined regexps for the highlighter
-MimeType=x-maemo-highlight/phonenumber;
-;; 4. URI schemes
-MimeType=x-maemo-urischeme/mailto;
+The \c Exec line defines how to execute the application. When the action is
+launched, \%U is replaced with a list of image URIs to open (such as
+file:///home/me/myimage.jpg).
+
+The update-desktop-database tool gathers information on which application
+handles which MIME type into /usr/share/applications/mimeinfo.cache. When a
+.desktop file is installed by a debian package, it is automatically called by a
+dpkg trigger.
-;; Defining how to trigger the action:
-;; 1. invoke a MApplication based program, by calling
-;; the com.nokia.MApplicationIf.launch method
-X-Maemo-Service=org.maemo.gallery_service
-;; 2. general D-Bus invocation
-X-Maemo-Service=org.maemo.gallery_service
-X-Maemo-Method=org.maemo.galleryinterface.viewimage
-;; It is possible to specify an optional object path, defaults to '/'.
-X-Maemo-Object-Path=/the/object/path
-;; Also an action may have optional, fixed string arguments, which get
-;; prepended to normal arguments.
-X-Maemo-Fixed-Args=foo;bar;baz;
-;; 3. Maemo Service Framework based action
-;; NOTE in this case you must not define X-Maemo-Service!
-X-Maemo-Method=com.nokia.imageviewerinterface.showImage
-;; 4. Plain old exec
-Exec=/usr/bin/gallery %U
-;; 5. the legacy mime_open method, provided only to wrap old programs into
-;; actions, don't use it in new applications
-X-Osso-Service=org.maemo.gallery_service
+Example of mimeinfo.cache:
+\verbatim
+[MIME Cache]
+image/jpeg=myimageviewer.desktop;someotherviewer.desktop;
+image/png=myimageviewer.desktop
\endverbatim
-Additionally:
+Default applications for each MIME type are declared in
+/usr/share/applications/defaults.list. Each user might also have their own
+defaults.list, overriding the global one.
-- All D-Bus methods must accept a list of strings and no other parameters
- (in D-Bus terms, signature="as"). When your function is called, the
- strings will be the URIs (or the free-text snippet) used to construct the
- Action. (You may have a return value; we'll ignore it.)
-
-- If you use a the Maemo Service Framework based invocation, then you must
- declare your application to be an implementor of that interface. For
- this, it's enough to add a "Interface: " line to your D-Bus .service file.
- You might also want to publish your interface in the maemo-services
- package, but it's not needed for libcontentaction.
+Example of defaults.list:
+\verbatim
+[Default Applications]
+image/jpeg=someotherviewer.desktop
+image/png=myimageviewer.desktop
+\endverbatim
-\section tracker_conditions Defining new Tracker-based conditions
+The defaults.list is installed by the package libcontentaction-data.
-\attention
-The following section may be subject to changes!
+The libcontentaction library is compatible with XDG MIME type handling. If you
+install the example file myimageviewer.desktop into /usr/share/applications,
+MyImageViewer appears as an action for jpeg and png images. For most cases,
+this is all you need. However, libcontentaction also provides you with custom
+launch methods. For more information, see \ref customlaunch.
-\attention
-The configuration file directory has changed from /etc/contentaction to /usr/share/contentaction.
+More information:
-Conditions are defined with XML files in \c /usr/share/contentaction/ (this
-location is overridden by $CONTENTACTION_ACTIONS). A condition is described
-by a \a <tracker-condition> element, whose \c name attribute is appended to
-\c "x-maemo-nepomuk/" to get the corresponding mime type. The element's
-text contains the SparQL snippet used to evaluate the condition by
-substituting it into the following query:
+<a href="http://en.wikipedia.org/wiki/Internet_media_type">MIME types</a>
-\code
-SELECT 1 {
- SNIPPET
- FILTER(?uri = <the-uri-to-verify-against>)
-}
-\endcode
+<a href="http://standards.freedesktop.org/desktop-entry-spec/latest/">Desktop entry specification</a>
-The condition applies if the query returns non-zero rows.
+<a href="http://freedesktop.org/wiki/Software/desktop-file-utils">Desktop file utils (including update-desktop-database)</a>
+
+<a href="http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html"> XDG Base Directory specification</a>
+
+\section customlaunch Custom launch methods
+
+In addition to the Exec line, .desktop files can specify custom ways to launch
+the application. The launch methods supported by libcontentaction are:
+
+-# launching a MeeGoTouch based application using the MApplication D-Bus interface
+ - Define: \c X-Maemo-Service=my.bus.name
+ - Optionally: \c X-Maemo-Fixed-Args=my;fixed;args
+-# calling a D-Bus method specified in the .desktop file
+ - Define: \c X-Maemo-Service=my.bus.name
+ - Define: \c X-Maemo-Method=com.my.interface.Method
+ - Optionally: \c X-Maemo-Object-Path=/the/object/path (default: /)
+ - Optionally: \c X-Maemo-Fixed-Args=my;fixed;args
+-# calling a MeeGo Service Framework method
+ - Define: \c X-Maemo-Method=com.my.interface.Method
+ - Optionally: \c X-Maemo-Fixed-Args=my;fixed;args
+ - Note: Do not define \c X-Maemo-Service
+-# executing a binary
+ - Define: \c Exec=command-to-execute fixedarg1 \%U fixedarg2
+ - No need for \c X-Maemo-Fixed-Args
+-# calling the legacy mime_open method
+ - Define: \c X-Osso-Service=my.bus.name
-Example:
+All D-Bus based invocation methods (except for mime_open) require the receiver
+to accept an array of strings (in D-Bus terms, signature="as"). When your
+function is called, the strings are the URIs (or the free-text snippet)
+used to construct the Action, as well as the fixed parameters you may have
+specified. If there is a return value, it is ignored.
+
+If you use a MeeGo Service Framework based invocation,
+declare your application to be an implementor of the interface. You just need to
+add an "Interface: " line to your D-Bus .service file. You can also publish
+your interface in the meego-services package, but it is not needed for
+libcontentaction.
+
+If your application is running, D-Bus based launching delivers the
+function call to the running instance. If your application is not running,
+D-Bus can autolaunch it as defined in your .service file. This makes
+it possible to have only one instance of your application running without any
+extra code.
+
+For more information, see \ref exampledesktop.
+
+More information:
+
+<a href="http://www.freedesktop.org/wiki/Software/dbus">D-Bus</a>
+
+<a href="http://dbus.freedesktop.org/doc/dbus-specification.html">Message Bus Starting Services</a>
+
+<a href="http://apidocs.meego.com/mtf/index.html">MeeGoTouch</a>
+
+\section custommime Custom MIME types for Tracker URIs
+
+\attention
+The following section may be subject to changes!
+
+The XDG MIME type handling associates files with applications that can open
+them. However, some objects are not represented as files. For example, contacts
+are represented as objects in a semantic data store, Tracker. It is often
+necessary to define actions to a subset of certain objects. For example, the
+"call" action is only applicable to contacts which have an associated phone
+number.
+
+To this end, libcontentaction can find actions for Tracker URIs which are ids
+for objects in the Tracker data store.
+
+If a URI represents a normal file (for instance, an image), the actions found
+through XDG MIME type handling are added to the list of applicable actions. This
+makes libcontentaction compatible with XDG MIME type handling. The applications
+that declare actions for normal files do not need to know about Tracker URIs.
+
+The libcontentaction library defines the "tracker conditions" which determine
+whether an URI is of interest. The conditions are mapped into custom MIME types
+(\c "x-maemo-nepomuk/...").
+
+The conditions are defined in .xml files installed in /usr/share/contentaction
+(or a location specified by $CONTENTACTION_ACTIONS). Each condition defines a
+SparQL snippet for querying whether a given URI satisfies the condition.
+
+For instance, the following .xml adds new MIME types \c x-maemo-nepomuk/image, \c
+x-maemo-nepomuk/contact and \c x-maemo-nepomuk/contact-with-phone-number.
\code
<actions>
@@ -156,38 +209,169 @@
</actions>
\endcode
-\section highlighter Free-text highlighter
+A condition is evaluated by executing the following SparQL query:
-Passing a string to highlight() can be used to discover interesting parts of
-the text. It returns Match objects identifying the position of the match
-and the possible actions.
+\code
+SELECT 1 {
+ SNIPPET
+ FILTER(?uri = <the-uri-to-verify-against>)
+}
+\endcode
-\note
-These actions have different semantics than ordinary Actions. When
-triggered, they call the method with a single element list containing the
-matched text (as UTF-8). These are very likely _not_ valid URIs!
+The condition applies if the query returns non-zero rows.
+
+An application can now define in its .desktop file that it handles a custom
+MIME type. When launched, the application receives a parameter which is the
+Tracker URI of the object to be opened. The application needs to query all
+the needed information (for example, the name and phone number for a contact)
+from Tracker.
+
+If your application wants to receive Tracker URIs instead of file URIs as
+parameters, a Tracker condition can overlap normal MIME types. For example,
+applications handling the \c x-maemo-nepomuk/image MIME type get Tracker
+URIs and applications handling \c image/jpeg get file URIs as parameters.
+Both applications appear as applicable actions for images.
+
+More information:
+
+<a href="http://live.gnome.org/Tracker/Documentation">Tracker</a>
+
+<a href="http://www.semanticdesktop.org/ontologies/">Nepomuk ontologies</a>
+
+<a href="http://www.w3.org/TR/rdf-sparql-query/">SparQL, the query language</a>
+
+\section custommimescheme Custom MIME types for URI schemes
+
+The libcontentaction library is also able to dispatch URIs based on the scheme
+(ContentAction::Action::actionsForScheme). To this end, applications can
+define that they handle a custom MIME type, for example,
+\c x-maemo-urischeme/http. When actionsForScheme("http://www.example.com") is
+called, applications declaring \c x-maemo-urischeme/http appear in the list of
+applicable actions. When launched, an action gets the string
+"http://www.example.com" as a parameter.
-\subsection defining_regexps Defining new regexps for the highlighter
+\section highlighter Free-text highlighter
\attention
The following section may be subject to changes!
-Similarly to Tracker-query based conditions, regexps are also defined in XML
-files residing in \c /etc/contentaction:
+Passing an MLabel* to ContentAction::Action::highlightLabel() adds a
+MLabelHighlighter which highlights interesting elements inside the label. When
+the user clicks a highlighted element, the default action for it is launched.
+When the user long-clicks a highlighted element, a pop-up menu containing the
+applicable actions is shown. When the user clicks an item in the menu, the
+corresponding action is launched.
+
+These actions have different semantics than ordinary Actions. When
+triggered, they call the method with a single element list containing the
+matched text (as UTF-8). Note that these are very likely invalid URIs.
+
+Similarly to Tracker conditions, regexps are also defined in .xml files
+located in \c /usr/share/contentaction (unless overridden with
+$CONTENTACTION_ACTIONS).
+
+For example, the following .xml adds new MIME types \c
+x-maemo-highlight/email-address and \c x-maemo-nepomuk/phone-number.
\code
<actions>
- <highlight regexp="[^\s@]+@([^\s.]+)(\.[^\s.]+)*" name="email"/>
- <highlight regexp="\+?\d+([- ]\d+)*" name="phone"/>
+ <highlight regexp="[^\s@]+@([^\s.]+)(\.[^\s.]+)*" name="email-address"/>
+ <highlight regexp="\+?\d+([- ]\d+)*" name="phone-number"/>
</actions>
\endcode
-To form the mimetype used in the action .desktop files, \c
-x-maemo-highlight/ is prepended to the \a name attribute.
+Applications can now define in their .desktop files that they handle these
+custom MIME types. When launched, they get a string which matches the regular
+expression as a parameter. For example, an application handling
+\c x-maemo-highlight/phone-number might get "+ 123 456-789" as a parameter.
+
+More information:
+
+<a href="http://apidocs.meego.com/mtf/class_m_label.html">MLabel documentation</a>
-\section default_actions Default actions
+\section exampledesktop An example .desktop file
-If you want your application to be the default application for some mime
-types, contact the libcontentaction implementors.
+The following example illustrates the interesting .desktop file fields from the
+libcontentaction point of view:
+
+\verbatim
+[Desktop Entry]
+Type=Application
+Icon=gallery.png
+;; This is needed to prevent this action from appearing in the launcher.
+NotShowIn=X-MeeGo;
+
+;; Defining a localisation method:
+;; 1. MeeGoTouch-based
+X-MeeGo-Translation-Catalog=gallery_catalog
+X-MeeGo-Logical-Id=view_logical_id
+;; 2. XDG style
+Name=View in gallery
+Name[fi]=Avaa galleriassa
+
+;; Defining when this action applies:
+;; 1. ordinary mimetypes
+MimeType=image/*;text/plain;
+;; 2. Tracker-query based conditions
+MimeType=x-maemo-nepomuk/contact;
+;; 3. pre-defined regexps for the highlighter
+MimeType=x-maemo-highlight/phonenumber;
+;; 4. URI schemes
+MimeType=x-maemo-urischeme/mailto;
+
+;; Defining how to trigger the action:
+;; 1. invoke a MApplication based program by calling
+;; the com.nokia.MApplicationIf.launch method
+X-Maemo-Service=org.maemo.gallery_service
+;; 2. general D-Bus invocation; define a bus name and a function
+X-Maemo-Service=org.maemo.gallery_service
+X-Maemo-Method=org.maemo.galleryinterface.viewimage
+;; It is possible to specify an optional object path, defaults to '/'.
+X-Maemo-Object-Path=/the/object/path
+;; Also an action may have optional, fixed string arguments, which get
+;; prepended to normal arguments. (This applies to all launch methods.)
+X-Maemo-Fixed-Args=foo;bar;baz;
+;; 3. MeeGo Service Framework based action
+;; NOTE in this case you must not define X-Maemo-Service!
+X-Maemo-Method=com.nokia.imageviewerinterface.showImage
+;; 4. Plain old exec
+Exec=/usr/bin/gallery %U
+;; 5. the legacy mime_open method, provided only to wrap old programs into
+;; actions, do not use it in new applications
+X-Osso-Service=org.maemo.gallery_service
+\endverbatim
+
+More information:
+
+<a href="http://apidocs.meego.com/mtf/i18n.html#translationsystem">MeeGoTouch translation system</a>
+
+\section lcatool lca-tool
+
+The lca-tool is a command-line utility which can be used as a development and
+testing tool by action implementors.
+
+Use the lca-tool to:
+- list the applicable actions for a file, Tracker URI or a string with a scheme.
+- trigger an applicable action for a file, Tracker URI or a string with a scheme.
+- launch an application (given its .desktop file) with parameters.
+- search for interesting items to highlight in free text.
+
+The lca-tool is installed by the libcontentaction0 package. To display the help
+message, run lca-tool without parameters.
+
+Example workflow for testing that an image viewer has successfully
+declared the \c image/jpeg MIME type:
+
+\verbatim
+$ cp myimageviewer.desktop /usr/share/applications
+$ update-desktop-database /usr/share/applications
+$ lca-tool --file --printmimes file:///home/me/myimage.jpg
+image/jpeg
+$ lca-tool --file --print file:///home/me/myimage.jpg
+someotherviewer
+myimageviewer
+$ lca-tool --file --trigger myimageviewer file:///home/me/myimage.jpg
+(MyImageViewer should launch)
+\endverbatim
*/
--- src/exec.cpp
+++ src/exec.cpp
@@ -31,11 +31,17 @@
namespace ContentAction {
-ExecPrivate::ExecPrivate(MDesktopEntry* desktopEntry, const QStringList& params)
+ExecPrivate::ExecPrivate(QSharedPointer<MDesktopEntry> desktopEntry,
+ const QStringList& params)
: DefaultPrivate(desktopEntry, params)
{
g_type_init();
- appInfo = G_APP_INFO(g_desktop_app_info_new_from_filename(desktopEntry->fileName().toLocal8Bit().constData()));
+ appInfo = G_APP_INFO(
+ g_desktop_app_info_new_from_filename(
+ desktopEntry->fileName().toLocal8Bit().constData()));
+ if (appInfo == 0) {
+ LCA_WARNING << "invalid desktop file" << desktopEntry->fileName();
+ }
}
ExecPrivate::~ExecPrivate()
@@ -48,7 +54,7 @@
GError *error = 0;
GList *uris = NULL;
- foreach (const QString& param, params)
+ Q_FOREACH (const QString& param, params)
uris = g_list_append(uris, g_strdup(param.toAscii().constData()));
g_app_info_launch_uris(appInfo, uris, NULL, &error);
--- src/highlight.cpp
+++ src/highlight.cpp
@@ -45,7 +45,7 @@
public:
LCALabelHighlighter(const MimesAndRegexps &mars_,
QObject *parent = 0);
-private slots:
+private Q_SLOTS:
void doDefaultAction(const QString& match);
void doPopupActions(const QString& match);
void doAction(const QModelIndex& ix);
@@ -58,14 +58,14 @@
{
QString re("(?:");
bool first = true;
- foreach (const MimeAndRegexp &mr, mars) {
+ Q_FOREACH (const MimeAndRegexp &mr, mars) {
if (!first)
re += '|';
re += mr.second.pattern();
first = false;
}
re += ")";
- return QRegExp(re);
+ return QRegExp(re, Qt::CaseInsensitive);
}
LCALabelHighlighter::LCALabelHighlighter(const MimesAndRegexps &mars_,
@@ -84,7 +84,7 @@
QStringList LCALabelHighlighter::matchingMimes(const QString &str) const
{
QStringList ret;
- foreach (const MimeAndRegexp &mr, mars)
+ Q_FOREACH (const MimeAndRegexp &mr, mars)
if (mr.second.exactMatch(str))
ret.append(mr.first);
return ret;
@@ -94,18 +94,21 @@
{
QStringList mimes = matchingMimes(match);
QString app;
- foreach (const QString &mime, mimes) {
- app = defaultAppForContentType(mime);
+ Q_FOREACH (const QString &mime, mimes) {
+ app = findDesktopFile(defaultAppForContentType(mime));
if (!app.isEmpty()) {
- createAction(findDesktopFile(app), QStringList() << match).trigger();
+ createAction(app, QStringList() << match).trigger();
return;
}
}
- foreach (const QString &mime, mimes) {
+ Q_FOREACH (const QString &mime, mimes) {
QStringList apps = appsForContentType(mime);
- if (!apps.isEmpty()) {
- createAction(findDesktopFile(apps[0]), QStringList() << match).trigger();
- return;
+ Q_FOREACH (const QString& appid, apps) {
+ app = findDesktopFile(appid);
+ if (!app.isEmpty()) {
+ createAction(app, QStringList() << match).trigger();
+ return;
+ }
}
}
}
@@ -152,9 +155,13 @@
qRegisterMetaType<Action>();
QList<Action> alist;
QStringList mimes = matchingMimes(match);
- foreach (const QString &mime, mimes) {
- foreach (const QString &app, appsForContentType(mime))
- alist << createAction(findDesktopFile(app), QStringList() << match);
+ QString app;
+ Q_FOREACH (const QString &mime, mimes) {
+ Q_FOREACH (const QString &appid, appsForContentType(mime)) {
+ app = findDesktopFile(appid);
+ if (!app.isEmpty())
+ alist << createAction(app, QStringList() << match);
+ }
}
MPopupList *popuplist = new MPopupList();
@@ -200,25 +207,29 @@
void ContentAction::highlightLabel(MLabel *label)
{
MimesAndRegexps mars;
- QHashIterator<QString, QString> iter(highlighterConfig());
+ QListIterator<QPair<QString, QString> > iter(highlighterConfig());
while (iter.hasNext()) {
- iter.next();
- // iter.key == mime type, iter.value == regexp
- if (!appsForContentType(iter.key()).isEmpty())
- mars += qMakePair(iter.key(), QRegExp(iter.value()));
+ QPair<QString, QString> mar = iter.next();
+ if (!appsForContentType(mar.first).isEmpty())
+ mars += qMakePair(mar.first, QRegExp(mar.second));
}
hiLabel(label, mars);
}
/// Similar to highlightLabel() but allows specifying which regexp-types to
-/// highlight (e.g. only \c "x-maemo-highlight/mailto").
+/// highlight (e.g. only \c "x-maemo-highlight/mailto"). The order of the \a
+/// typesOfHighlight is honoured; the regexps appearing first get the priority
+/// when deciding the default action and the order of the actions.
void ContentAction::highlightLabel(MLabel *label,
QStringList typesToHighlight)
{
MimesAndRegexps mars;
- const QHash<QString, QString>& cfg = highlighterConfig();
- foreach (const QString& k, typesToHighlight) {
- QString re(cfg.value(k, QString()));
+ const QList<QPair<QString, QString> >& cfgList = highlighterConfig();
+ QMap<QString, QString> cfgMap;
+ for (int i = 0; i < cfgList.size(); ++i)
+ cfgMap[cfgList[i].first] = cfgList[i].second;
+ Q_FOREACH (const QString& k, typesToHighlight) {
+ QString re(cfgMap.value(k, QString()));
if (re.isEmpty())
continue;
if (!appsForContentType(k).isEmpty())
--- src/highlighter.cpp
+++ src/highlighter.cpp
@@ -34,12 +34,12 @@
/// list of Match objects.
QList<Match> Action::highlight(const QString& text)
{
- const QHash<QString, QString>& cfg = highlighterConfig();
+ const QList<QPair<QString, QString> >& cfg = highlighterConfig();
QList<Match> result;
- foreach (const QString& mime, cfg.keys()) {
- QRegExp re(cfg[mime]);
- QStringList apps = appsForContentType(mime);
+ for (int i = 0; i < cfg.size(); ++i) {
+ QRegExp re(cfg[i].second, Qt::CaseInsensitive);
+ QStringList apps = appsForContentType(cfg[i].first);
int pos = 0;
while ((pos = re.indexIn(text, pos)) != -1) {
int l = re.matchedLength();
@@ -47,11 +47,13 @@
m.start = pos;
m.end = pos + l;
- foreach (const QString& app, apps) {
+ Q_FOREACH (const QString& app, apps) {
m.actions << createAction(findDesktopFile(app), QStringList() << re.cap());
}
result << m;
pos += l;
+ if (l == 0)
+ ++pos;
}
}
return result;
--- src/internal.h
+++ src/internal.h
@@ -30,25 +30,30 @@
struct DefaultPrivate : public ActionPrivate
{
- DefaultPrivate(MDesktopEntry* desktopEntry, const QStringList& params);
+ DefaultPrivate(QSharedPointer<MDesktopEntry> desktopEntry,
+ const QStringList& params,
+ bool valid = true);
virtual ~DefaultPrivate();
virtual bool isValid() const;
virtual QString name() const;
virtual QString localizedName() const;
virtual QString icon() const;
- MDesktopEntry* desktopEntry;
+ QSharedPointer<MDesktopEntry> desktopEntry;
QStringList params;
+ bool valid;
};
struct ServiceFwPrivate : public DefaultPrivate {
- ServiceFwPrivate(MDesktopEntry* desktopEntry, const QStringList& params);
+ ServiceFwPrivate(QSharedPointer<MDesktopEntry> desktopEntry,
+ const QStringList& params);
virtual void trigger() const;
QString serviceFwMethod;
};
struct DBusPrivate : public DefaultPrivate {
- DBusPrivate(MDesktopEntry* desktopEntry, const QStringList& params);
+ DBusPrivate(QSharedPointer<MDesktopEntry> desktopEntry,
+ const QStringList& params);
virtual void trigger() const;
QString busName;
@@ -59,14 +64,18 @@
};
struct ExecPrivate : public DefaultPrivate {
- ExecPrivate(MDesktopEntry* desktopEntry, const QStringList& params);
+ ExecPrivate(QSharedPointer<MDesktopEntry> desktopEntry,
+ const QStringList& params);
virtual ~ExecPrivate();
virtual void trigger() const;
GAppInfo *appInfo;
};
-Action createAction(const QString& desktopFileId, const QStringList& params);
+Action createAction(const QString& desktopFilePath,
+ const QStringList& params);
+Action createAction(QSharedPointer<MDesktopEntry> desktopEntry,
+ const QStringList& params);
// our pseudo mimetype classes
extern const QString OntologyMimeClass;
@@ -91,9 +100,10 @@
LCA_EXPORT QString mimeForScheme(const QString& uri);
LCA_EXPORT QString mimeForFile(const QUrl& fileUri);
LCA_EXPORT QStringList mimeForTrackerObject(const QString& uri);
+LCA_EXPORT QStringList mimeForString(const QString& param);
const QHash<QString, QStringList>& mimeApps();
-const QHash<QString, QString>& highlighterConfig();
+const QList<QPair<QString, QString> >& highlighterConfig();
const QHash<QString, QString>& trackerConditions();
} // end namespace Internal
--- src/lca-tool.cpp
+++ src/lca-tool.cpp
@@ -33,24 +33,25 @@
using namespace ContentAction::Internal;
static const char help[] = \
-"Usage: lca-tool [OPTIONS] MODE MODALCOMMAND URIS\n"
+"Usage: lca-tool [OPTIONS] MODE MODALCOMMAND PARAMS\n"
" lca-tool [OPTIONS] OTHERCOMMAND ARGS\n"
"OPTION can be:\n"
" --l10n use localized names when printing actions\n"
"\n"
"MODE is one of:\n"
-" --tracker URIS are representing objects stored in Tracker,\n"
+" --tracker PARAMS are representing objects stored in Tracker,\n"
" dispatched using Tracker-query based conditions\n"
-" --file URI is a file (or other resource), dispatched based on\n"
+" --file PARAMS is a file (or other resource), dispatched based on\n"
" its content type\n"
-" --scheme URIS are dispatched based on their scheme only\n"
+" --scheme PARAMS are dispatched based on their scheme only\n"
+" --string PARAMS are dispatched based on regexp matches\n"
"\n"
"In modal use, the following commands are available:\n"
-" --print prints actions applicable to URIS\n"
-" --trigger ACTION trigger ACTION with the given URIS\n"
-" --printdefault print the default action for URIS\n"
-" --triggerdefault trigger the default action for the given URIS\n"
-" --printmimes print the (pseudo) mimetypes of URIS\n"
+" --print prints actions applicable to PARAMS\n"
+" --trigger ACTION trigger ACTION with the given PARAMS\n"
+" --printdefault print the default action for PARAMS\n"
+" --triggerdefault trigger the default action for the given PARAMS\n"
+" --printmimes print the (pseudo) mimetypes of PARAMS\n"
"\n"
"ACTION is the basename of the action's .desktop file (both when printing and\n"
"when invoking).\n"
@@ -62,6 +63,9 @@
" mimetype\n"
" --setmimedefault MIME ACTION set ACTION as default for the given mimetype\n"
" --resetmimedefault MIME remove the user-defined default from the given mimetype\n"
+" --highlight will read text from stdin and find actions for items in it\n"
+" --triggerdesktop DESKTOPFILE PARAMS will launch the application defined by DESKTOPFILE with the given PARAMS\n"
+
"\n"
"Return values:\n"
" 0 success\n"
@@ -69,18 +73,23 @@
" 2 problems with the arguments\n"
" 3 triggered an action not applicable to the given URIS\n"
" 4 no default action exists for the given URIS\n"
+" 5 desktop file not found\n"
"\n"
"Examples:\n"
" $ lca-tool --tracker --triggerdefault urn:1246934-4213\n"
" $ lca-tool --file --print file://$HOME/plaintext\n"
" $ lca-tool --scheme --triggerdefault mailto:someone at example.com\n"
-" $ lca-tool --setmimedefault image/jpeg imageviewer\n";
+" $ lca-tool --string print \"myaddress at email.com\""
+" $ lca-tool --setmimedefault image/jpeg imageviewer\n"
+" $ lca-tool --highlight < myinput.txt\n"
+" $ lca-tool --triggerdesktop myapp.desktop param1 param2\n";
enum UriMode {
NoMode = 0,
TrackerMode,
FileMode,
SchemeMode,
+ StringMode,
};
enum ActionToDo {
@@ -98,6 +107,8 @@
PrintMimeDefault,
SetMimeDefault,
ResetMimeDefault,
+ Highlight,
+ TriggerDesktop
};
#define NEEDARG(errmsg) \
@@ -108,6 +119,72 @@
} \
} while (0)
+// The highlighter part:
+
+QDebug operator<<(QDebug dbg, const Match& m) {
+ dbg.nospace() << "match at ("
+ << m.start << ", " << m.end << "): ";
+ Q_FOREACH (const Action& a, m.actions) {
+ dbg.space() << a.name();
+ }
+ dbg.nospace() << "\n";
+ return dbg;
+}
+
+QDebug operator<<(QDebug dbg, const QList<Match>& ms) {
+ Q_FOREACH (const Match& m, ms) {
+ dbg.space() << m;
+ }
+ return dbg;
+}
+
+/*
+ * Reads text from the standard input, highlight rules from the usual place
+ * (ie. xml files in $CONTENTACTION_ACTIONS) and then prints match results on
+ * the standard output. If the terminal is a tty, the results are printed on
+ * stderr, and on stdout a beautifully colored version of the text is shown.
+ */
+void doHighlight()
+{
+ QTextStream out(isatty(1) ? stderr : stdout);
+ QTextStream textout(isatty(1) > 0 ? stdout : fopen("/dev/null", "w"));
+ QTextStream in(stdin);
+ QString text = in.readAll();
+
+ QList<Match> ms = Action::highlight(text);
+ Q_FOREACH (const Match& m, ms) {
+ QStringList actions;
+ Q_FOREACH (const Action& a, m.actions)
+ actions << a.name();
+ out << QString("%1 %2 '%3' %4\n").arg(QString::number(m.start),
+ QString::number(m.end),
+ text.mid(m.start, m.end - m.start),
+ actions.join(" "));
+ }
+ QString hltext(text);
+ if (isatty(1)) {
+ qSort(ms.begin(), ms.end());
+ QString color[] = {
+ "\e[1;37;41m",
+ "\e[1;37;42m",
+ "\e[1;37;43m",
+ "\e[1;37;44m",
+ "\e[1;37;45m",
+ "\e[1;37;46m",
+ };
+ int i = 0;
+ int d = 0;
+ Q_FOREACH (const Match& m, ms) {
+ hltext.insert(d + m.start, color[i]);
+ d += color[i].length();
+ i = (i + 1) % (sizeof(color) / sizeof(color[0]));
+ hltext.insert(d + m.end, "\e[0m");
+ d += 4;
+ }
+ textout << hltext;
+ }
+}
+
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
@@ -120,7 +197,7 @@
char *l10npaths = getenv("CONTENTACTION_L10N_PATH");
if (l10npaths) {
- foreach (const QString& p, QString::fromLocal8Bit(l10npaths).split(':')) {
+ Q_FOREACH (const QString& p, QString::fromLocal8Bit(l10npaths).split(':')) {
qDebug() << "adding path:" << p;
MLocale::addTranslationPath(p);
}
@@ -155,6 +232,8 @@
newmode = FileMode;
else if (arg == "--scheme")
newmode = SchemeMode;
+ else if (arg == "--string")
+ newmode = StringMode;
if (newmode != NoMode) {
if (mode != NoMode) {
err << "only a single MODE may be specified" << endl;
@@ -192,6 +271,14 @@
NEEDARG("a MIME must be given when using --setmimedefault");
mime = args.takeFirst();
}
+ else if (arg == "--highlight") {
+ todo = Highlight;
+ }
+ else if (arg == "--triggerdesktop") {
+ todo = TriggerDesktop;
+ NEEDARG("a DESKTOPFILE must be given when using --triggerdesktop");
+ actionName = args.takeFirst();
+ }
// modal actions
else if (arg == "--print") {
todo = PrintActions;
@@ -222,7 +309,7 @@
// handle modeless actions first
switch (todo) {
case PrintActionsForMime:
- foreach (const Action& a, actionsForMime(mime)) {
+ Q_FOREACH (const Action& a, actionsForMime(mime)) {
out << a.name() << endl;
}
return 0;
@@ -239,6 +326,18 @@
resetMimeDefault(mime);
return 0;
break;
+ case Highlight:
+ doHighlight();
+ return 0;
+ break;
+ case TriggerDesktop:
+ {
+ Action a = Action::launcherAction(actionName, args);
+ if (!a.isValid())
+ return 5;
+ a.trigger();
+ return 0;
+ }
default:
break;
}
@@ -265,34 +364,51 @@
case FileMode:
{
QFileInfo fileInfo(args[0]);
- if (fileInfo.exists())
- args[0] = fileInfo.absoluteFilePath().prepend("file://");
- actions = Action::actionsForFile(QUrl(args[0]));
- defAction = Action::defaultActionForFile(QUrl(args[0]));
+ QUrl fileUrl;
+ if (fileInfo.exists()) {
+ // the user gave: /home/me/somefile#canhavespecialchars.txt
+ fileUrl = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
+ }
+ else {
+ // the user gave: file:///home/me/mustbe%23escapedproperly.txt
+ // (hopefully)
+ fileUrl = QUrl::fromEncoded(args[0].toLatin1());
+ QFileInfo fileInfo2(fileUrl.toLocalFile());
+ if (!fileInfo2.exists()) {
+ err << "possibly incorrect file uri: " << args[0] << endl;
+ err << "input a file uri (file:///abs/path/...) %-escaped" << endl;
+ }
+ }
+ actions = Action::actionsForFile(fileUrl);
+ defAction = Action::defaultActionForFile(fileUrl);
}
break;
case SchemeMode:
actions = Action::actionsForScheme(args[0]);
defAction = Action::defaultActionForScheme(args[0]);
break;
+ case StringMode:
+ actions = Action::actionsForString(args[0]);
+ defAction = Action::defaultActionForString(args[0]);
+ break;
default:
break;
}
switch (todo) {
case PrintActions:
- foreach (const Action& a, actions) {
+ Q_FOREACH (const Action& a, actions) {
out << (use_l10n ? a.localizedName() : a.name()) << endl;
}
break;
case TriggerAction:
- foreach (const Action& a, actions) {
+ Q_FOREACH (const Action& a, actions) {
if (a.name() == actionName) {
a.trigger();
return 0;
}
}
- err << actionName << "is not applicable" << endl;
+ err << actionName << " is not applicable" << endl;
return 3;
break;
case PrintDefaultAction:
@@ -300,7 +416,7 @@
break;
case TriggerDefaultAction:
if (!defAction.isValid()) {
- err << "no default action for the given URIs" << endl;
+ err << "no default action for the given PARAMS" << endl;
return 4;
}
defAction.trigger();
@@ -309,7 +425,7 @@
case PrintMimes: {
switch (mode) {
case TrackerMode:
- foreach (const QString& mime, mimeForTrackerObject(args[0])) {
+ Q_FOREACH (const QString& mime, mimeForTrackerObject(args[0])) {
out << mime << endl;
}
break;
@@ -319,6 +435,11 @@
case SchemeMode:
out << mimeForScheme(args[0]) << endl;
break;
+ case StringMode:
+ Q_FOREACH (const QString& mime, mimeForString(args[0])) {
+ out << mime << endl;
+ }
+ break;
default:
break;
}
--- src/mime.cpp
+++ src/mime.cpp
@@ -32,6 +32,7 @@
#include <QDir>
#include <QFile>
#include <QFileInfo>
+#include <QDateTime>
#include <QTextStream>
#include <QDebug>
#include <QFile>
@@ -64,9 +65,13 @@
/// Returns the content type of the given file, or an empty string if it cannot
/// be retrieved.
-QString Internal::mimeForFile(const QUrl& fileUri)
+QString Internal::mimeForFile(const QUrl& uri)
{
g_type_init();
+ // assume "file" scheme if the uri had nothing
+ QUrl fileUri(uri);
+ if (fileUri.scheme().isEmpty())
+ fileUri.setScheme("file");
QByteArray filename = fileUri.toEncoded();
GFile *file = g_file_new_for_uri(filename.constData());
@@ -205,6 +210,8 @@
// ("something.desktop"), and returns the first hit.
QString Internal::findDesktopFile(const QString& id)
{
+ if (id.isEmpty())
+ return QString();
QStringList dirs = xdgDataDirs();
for (int i = 0; i < dirs.size(); ++i) {
QFile f(dirs[i] + "/applications/" + id);
@@ -241,14 +248,28 @@
}
// Reads the mimeinfo.cache files and returns the mapping from mime types to
-// desktop entries.
+// desktop entries. Tries to decide cleverly whether to re-read the files if
+// they might have changed.
const QHash<QString, QStringList>& Internal::mimeApps()
{
- static bool read = false;
static QHash<QString, QStringList> mimecache;
+ // When have we last consider reading various mimeinfo.cache files
+ static uint lastTime = 0;
+ // What were the "last modified" times of them when they were read
+ static QHash<QString, uint> lastModified;
+
+ // Read each mimeinfo.cache if 1) it has never been read or 2) 1 min has
+ // passed since our previous timestamp check && timestamp shows it has
+ // changed.
+
+ // This is a hack but so is trying to use QFileSystemWatcher from a library
+ // without a LifeTimeManager object. Deleting the QFileSystemWatcher at the
+ // right moment is tricky and cannot be enforced by the library.
- if (read)
+ uint currentTime = QDateTime::currentDateTime().toTime_t();
+ if (currentTime - lastTime < 60)
return mimecache;
+ lastTime = currentTime;
QStringList dirs = xdgDataDirs();
QHash<QString, QString> temp;
@@ -256,14 +277,20 @@
QFile f(dirs[i] + "/applications/mimeinfo.cache");
if (!f.exists())
continue;
+ // Check the "last modified" time of the file
+ uint lm = QFileInfo(f.fileName()).lastModified().toTime_t();
+ if (lastModified.contains(dirs[i]) &&
+ lm == lastModified[dirs[i]])
+ continue;
+
readKeyValues(f, temp);
+ lastModified[dirs[i]] = lm;
}
QHashIterator<QString, QString> it(temp);
while (it.hasNext()) {
it.next();
mimecache.insert(it.key(), it.value().split(";", QString::SkipEmptyParts));
}
- read = true;
return mimecache;
}
@@ -314,10 +341,11 @@
// actually) is to launch the application it describes.
if (mimeType == DesktopFileMimeType)
return createAction(fileUri.toLocalFile(), QStringList());
- QString appid = defaultAppForContentType(mimeType);
- if (!appid.isEmpty())
- return createAction(findDesktopFile(appid),
- QStringList() << fileUri.toEncoded());
+ QString app = findDesktopFile(defaultAppForContentType(mimeType));
+ if (!app.isEmpty()) {
+ return createAction(app,
+ QStringList() << fileUri.toEncoded());
+ }
// Fall back to one of the existing actions (if there are some)
QList<Action> acts = actionsForUri(fileUri.toEncoded(), mimeType);
if (acts.size() >= 1)
@@ -333,9 +361,11 @@
return result << createAction(uri, QStringList());
QStringList appIds = appsForContentType(mimeType);
- foreach (const QString& id, appIds) {
- result << createAction(findDesktopFile(id),
- QStringList() << uri);
+ Q_FOREACH (const QString& id, appIds) {
+ QString app = findDesktopFile(id);
+ if (!app.isEmpty())
+ result << createAction(app,
+ QStringList() << uri);
}
return result;
}
@@ -371,14 +401,28 @@
return mime;
}
+/// Returns the pseudo-mimetypes of the \a param string. Mime types are found
+/// based on exact matching against regexps in the highlighter configuration.
+QStringList Internal::mimeForString(const QString& param)
+{
+ QStringList mimes;
+ const QList<QPair<QString, QString> >& cfgList = highlighterConfig();
+ for (int i = 0; i < cfgList.size(); ++i) {
+ if (QRegExp(cfgList[i].second, Qt::CaseInsensitive).exactMatch(param)) {
+ mimes << cfgList[i].first;
+ }
+ }
+ return mimes;
+}
+
/// Returns the default action for handling the scheme of the passed \a uri.
/// \sa actionsForScheme().
Action Action::defaultActionForScheme(const QString& uri)
{
QString mimeType = mimeForScheme(uri);
- QString defApp = defaultAppForContentType(mimeType);
+ QString defApp = findDesktopFile(defaultAppForContentType(mimeType));
if (!defApp.isEmpty())
- return createAction(findDesktopFile(defApp), QStringList() << uri);
+ return createAction(defApp, QStringList() << uri);
// Fall back to one of the existing actions (if there are some)
QList<Action> acts = actionsForUri(uri, mimeType);
@@ -395,17 +439,54 @@
QList<Action> Action::actionsForScheme(const QString& uri)
{
QList<Action> result;
- foreach (const QString& app, appsForContentType(mimeForScheme(uri))) {
+ Q_FOREACH (const QString& app, appsForContentType(mimeForScheme(uri))) {
result << createAction(findDesktopFile(app), QStringList() << uri);
}
return result;
}
+/// Returns the default action for handling the passed \a param.
+/// \sa actionsForString().
+Action Action::defaultActionForString(const QString& param)
+{
+ QStringList mimeTypes = mimeForString(param);
+ Q_FOREACH (const QString& mimeType, mimeTypes) {
+ QString def = findDesktopFile(defaultAppForContentType(mimeType));
+ if (!def.isEmpty())
+ return createAction(def,
+ QStringList() << param);
+ }
+ // Fall back to one of the existing actions (if there are some)
+ QList<Action> acts = actionsForString(param);
+ if (acts.size() >= 1)
+ return acts[0];
+ return Action();
+}
+
+/// Returns all actions handling the given string \a param. Dispatching is done
+/// based on exact matching against the regexpx of highlighter configuration.
+QList<Action> Action::actionsForString(const QString& param)
+{
+ QStringList mimeTypes = mimeForString(param);
+ QList<Action> result;
+ Q_FOREACH (const QString& mimeType, mimeTypes) {
+ QStringList apps = appsForContentType(mimeType);
+ Q_FOREACH (const QString& appid, apps) {
+ QString app = findDesktopFile(appid);
+ if (!app.isEmpty()) {
+ result << createAction(app,
+ QStringList() << param);
+ }
+ }
+ }
+ return result;
+}
+
QList<Action> actionsForMime(const QString& mimeType)
{
QList<Action> result;
QStringList appIds = appsForContentType(mimeType);
- foreach (const QString& id, appIds) {
+ Q_FOREACH (const QString& id, appIds) {
result << createAction(findDesktopFile(id),
QStringList());
}
@@ -414,9 +495,9 @@
Action defaultActionForMime(const QString& mimeType)
{
- QString appid = defaultAppForContentType(mimeType);
- if (!appid.isEmpty())
- return createAction(findDesktopFile(appid),
+ QString app = findDesktopFile(defaultAppForContentType(mimeType));
+ if (!app.isEmpty())
+ return createAction(app,
QStringList());
return Action();
}
--- src/service.cpp
+++ src/service.cpp
@@ -33,7 +33,8 @@
namespace ContentAction
{
-ServiceFwPrivate::ServiceFwPrivate(MDesktopEntry* desktopEntry, const QStringList& params)
+ServiceFwPrivate::ServiceFwPrivate(QSharedPointer<MDesktopEntry> desktopEntry,
+ const QStringList& params)
: DefaultPrivate(desktopEntry, params),
serviceFwMethod(desktopEntry->value(XMaemoMethodKey))
{
@@ -72,7 +73,7 @@
ServiceResolver::~ServiceResolver()
{
- foreach (QDBusInterface* proxy, proxies)
+ Q_FOREACH (QDBusInterface* proxy, proxies)
delete proxy;
proxies.clear();
delete mapperProxy;
@@ -102,7 +103,7 @@
{
// Check which interfaces now become unusable
QStringList interfaces = resolved.keys(implementor);
- foreach (const QString& interface, interfaces)
+ Q_FOREACH (const QString& interface, interfaces)
resolved.remove(interface);
if (proxies.contains(implementor))
delete proxies.take(implementor);
--- src/service.h
+++ src/service.h
@@ -39,7 +39,7 @@
QDBusInterface* implementor(const QString& interface);
QDBusInterface* implementorForAction(const QString& action, QString& method);
-private slots:
+private Q_SLOTS:
void onServiceAvailable(QString, QString);
void onServiceUnavailable(QString);
--- src/tracker.cpp
+++ src/tracker.cpp
@@ -76,14 +76,14 @@
static bool mimeAndUriFromTracker(const QStringList& uris, QStringList &urlsAndMimes)
{
QString query("SELECT ");
- foreach (const QString& uri, uris)
+ Q_FOREACH (const QString& uri, uris)
query += QString("nie:url(<%1>) nie:mimeType(<%1>) ").arg(uri);
query += " {}";
QDBusReply<QVector<QStringList> > reply = tracker()->call(SparqlQuery, query);
if (!reply.isValid())
return false;
urlsAndMimes = reply.value()[0];
- foreach (const QString& x, urlsAndMimes)
+ Q_FOREACH (const QString& x, urlsAndMimes)
if (x.isEmpty()) return false;
return true;
}
@@ -94,14 +94,14 @@
static bool hactionFromTracker(const QStringList& uris, QStringList &urls)
{
QString query("SELECT ");
- foreach (const QString& uri, uris)
+ Q_FOREACH (const QString& uri, uris)
query += QString("tracker:coalesce(nfo:bookmarks(<%1>), nfo:uri(<%1>)) ").arg(uri);
query += " {}";
QDBusReply<QVector<QStringList> > reply = tracker()->call(SparqlQuery, query);
if (!reply.isValid())
return false;
urls = reply.value()[0];
- foreach (const QString& x, urls)
+ Q_FOREACH (const QString& x, urls)
if (x.isEmpty()) return false;
return true;
}
@@ -126,7 +126,7 @@
QStringList mimeTypes;
QHash<QString, QString> conditions = trackerConditions();
// TODO: evaluate them at once.
- foreach (const QString& mimeType, conditions.keys()) {
+ Q_FOREACH (const QString& mimeType, conditions.keys()) {
// Don't consider mime types for which nobody defines an action,
// except if it is `software-application' which is special case.
QString pseudoMimeType(OntologyMimeClass + mimeType);
@@ -145,7 +145,7 @@
static QList<QStringList> mimeTypesForUris(const QStringList& uris)
{
QList<QStringList> allMimeTypes;
- foreach (const QString& uri, uris) {
+ Q_FOREACH (const QString& uri, uris) {
if (!isValidIRI(uri)) return QList<QStringList>();
allMimeTypes << mimeForTrackerObject(uri);
}
@@ -182,12 +182,12 @@
if (!isValidIRI(uri)) return Action();
QStringList mimeTypes = mimeForTrackerObject(uri);
LCA_DEBUG << "pseudo-mimes" << mimeTypes;
- foreach (const QString& mimeType, mimeTypes) {
+ Q_FOREACH (const QString& mimeType, mimeTypes) {
if (mimeType == SoftwareApplicationMimeType)
return createSoftwareAction(uri);
- QString def = defaultAppForContentType(mimeType);
+ QString def = findDesktopFile(defaultAppForContentType(mimeType));
if (!def.isEmpty())
- return createAction(findDesktopFile(def),
+ return createAction(def,
QStringList() << uri);
}
// If the resource is a file-based one, query its url and mimetype, and
@@ -195,7 +195,9 @@
QStringList urlAndMime;
if (mimeAndUriFromTracker(QStringList() << uri, urlAndMime)) {
LCA_DEBUG << "real url and mimetype" << urlAndMime;
- return defaultActionForFile(urlAndMime[0], urlAndMime[1]);
+ // Tracker has the filename %-encoded, don't encode it again
+ QUrl fileUrl = QUrl::fromEncoded(urlAndMime[0].toUtf8());
+ return defaultActionForFile(fileUrl, urlAndMime[1]);
}
// FIXME: this is a hack for converting nfo:Bookmark and nfo:WebHistory into
@@ -236,7 +238,7 @@
QSet<QString> defApps;
for (int i = 0; i < mimeTypes.size(); ++i) {
QSet<QString> defs;
- foreach (const QString& mimeType, mimeTypes[i]) {
+ Q_FOREACH (const QString& mimeType, mimeTypes[i]) {
QString def = defaultAppForContentType(mimeType);
if (!def.isEmpty())
defs << def;
@@ -249,8 +251,11 @@
LCA_DEBUG << "defApps" << defApps;
// If there are multiple possible default applications, the choice is
// arbitrary.
- if (!defApps.empty())
- return createAction(findDesktopFile(*defApps.begin()), uris);
+ Q_FOREACH (const QString& appid, defApps) {
+ QString app = findDesktopFile(appid);
+ if (!app.isEmpty())
+ return createAction(app, uris);
+ }
// Try mimetype based handlers for real things.
QStringList urlsAndMimes;
@@ -269,8 +274,9 @@
}
}
LCA_DEBUG << "defApp" << defApp;
- if (!defApp.isEmpty())
- return createAction(findDesktopFile(defApp), fileUris);
+ QString app = findDesktopFile(defApp);
+ if (app.isEmpty())
+ return createAction(app, fileUris);
}
// Fall back to one of the existing actions (if there are some)
LCA_DEBUG << "fallback to actions()";
@@ -296,21 +302,35 @@
QStringList mimeTypes = mimeForTrackerObject(uri);
LCA_DEBUG << "pseudo mimes" << mimeTypes;
- foreach (const QString& mimeType, mimeTypes) {
+ QSet<QString> blackList; // for adding each action only once
+ Q_FOREACH (const QString& mimeType, mimeTypes) {
QStringList apps = appsForContentType(mimeType);
if (mimeType == SoftwareApplicationMimeType)
result << createSoftwareAction(uri);
- foreach (const QString& app, apps) {
- result << createAction(findDesktopFile(app),
- QStringList() << uri);
+ Q_FOREACH (const QString& appid, apps) {
+ QString app = findDesktopFile(appid);
+ if (!app.isEmpty()) {
+ result << createAction(app,
+ QStringList() << uri);
+ blackList.insert(result.last().name());
+ }
}
}
// Construct additional actions based on nie:mimeType(uri), passing
- // nie:url(uri) as argument.
+ // nie:url(uri) as argument. However, don't add actions for those
+ // applications which already are in the list (because they declare handling
+ // the x-maemo-nepomuk mime type).
QStringList urlAndMime;
if (mimeAndUriFromTracker(QStringList() << uri, urlAndMime)) {
LCA_DEBUG << "real url and mimetype" << urlAndMime;
- result << actionsForFile(urlAndMime[0], urlAndMime[1]);
+ // Tracker has the filename %-encoded, don't encode it again
+ QUrl fileUrl = QUrl::fromEncoded(urlAndMime[0].toUtf8());
+ QList<Action> actions = actionsForFile(fileUrl, urlAndMime[1]);
+ Q_FOREACH (const Action& a, actions) {
+ if (!blackList.contains(a.name())) {
+ result << a;
+ }
+ }
}
// And still others, if it happens to be a nfo:Bookmark or nfo:WebHistory.
// FIXME: this is a hack for converting nfo:Bookmark and nfo:WebHistory into
@@ -348,13 +368,13 @@
QStringList commonApps;
for (int i = 0; i < mimeTypes.size(); ++i) {
QStringList apps;
- foreach (const QString& mime, mimeTypes[i])
+ Q_FOREACH (const QString& mime, mimeTypes[i])
apps += appsForContentType(mime);
if (i == 0) {
commonApps = apps;
} else {
QStringList intersection;
- foreach (const QString& commonApp, commonApps) {
+ Q_FOREACH (const QString& commonApp, commonApps) {
if (apps.contains(commonApp))
intersection << commonApp;
}
@@ -362,8 +382,14 @@
}
}
LCA_DEBUG << "commonApps" << commonApps;
- foreach (const QString& app, commonApps)
- result << createAction(findDesktopFile(app), uris);
+ QSet<QString> blackList; // for adding each action only once
+ Q_FOREACH (const QString& appid, commonApps) {
+ QString app = findDesktopFile(appid);
+ if (!app.isEmpty()) {
+ result << createAction(app, uris);
+ blackList.insert(result.last().name());
+ }
+ }
QStringList urlsAndMimes;
if (mimeAndUriFromTracker(uris, urlsAndMimes)) {
@@ -377,7 +403,7 @@
commonApps = apps;
} else {
QStringList intersection;
- foreach (const QString& commonApp, commonApps) {
+ Q_FOREACH (const QString& commonApp, commonApps) {
if (apps.contains(commonApp))
intersection << commonApp;
}
@@ -385,8 +411,15 @@
}
}
LCA_DEBUG << "real-mime commonApps" << commonApps;
- foreach (const QString& app, commonApps)
- result << createAction(findDesktopFile(app), fileUris);
+ Q_FOREACH (const QString& appid, commonApps) {
+ QString app = findDesktopFile(appid);
+ if (app.isEmpty())
+ continue;
+ Action a = createAction(app, fileUris);
+ if (!blackList.contains(a.name())) {
+ result << a;
+ }
+ }
}
// TODO: sort the result
return result;
--- t/Makefile.am
+++ t/Makefile.am
@@ -31,7 +31,10 @@
test-desktop-launching.py \
test-l10n.sh \
test-fixed-params.py \
- test-schemes.sh
+ test-schemes.sh \
+ test-special-chars.py \
+ test-invalid-defaults.py \
+ test-regexps.py
noinst_SCRIPTS = \
start-sandbox.sh \
@@ -43,11 +46,11 @@
service.map \
testdata.ttl \
plaintext \
+ empty.pdf \
launchme.desktop
check_PROGRAMS = \
- linktest \
- hl1
+ linktest
noinst_PROGRAMS = hldemo
hldemo_SOURCES = hldemo.cpp
@@ -64,11 +67,13 @@
testhelper_PROGRAMS = \
servicetest
-hl1_SOURCES = hl1.cpp
linktest_SOURCES = linktest.cpp
linktest_CPPFLAGS = \
$(AM_CPPFLAGS) \
- $(GIO_CFLAGS)
+ $(GIO_CFLAGS) \
+ $(MT_CFLAGS)
+linktest_LDADD = \
+ $(MT_LIBS)
servicetest_SOURCES = servicelistener.cpp
@@ -85,6 +90,7 @@
$(noinst_SCRIPTS) \
hlinput.txt \
plaintext \
+ empty.pdf \
launchme.desktop
# NOTE: we depend on automake executing $(TESTS) in order. Should this
@@ -103,6 +109,9 @@
test-l10n.sh \
test-fixed-params.py \
test-schemes.sh \
+ test-special-chars.py \
+ test-invalid-defaults.py \
+ test-regexps.py \
stop-sandbox.sh
clean-local:
--- t/applications/Makefile.am
+++ t/applications/Makefile.am
@@ -16,4 +16,9 @@
fixedparams.desktop \
plainimageviewer.desktop \
trackerimageviewer.desktop \
- plainmusicplayer.desktop
+ plainmusicplayer.desktop \
+ complexmusic.desktop \
+ uriprinter.desktop \
+ gallerywithfilename.desktop \
+ browser.desktop \
+ special-browser.desktop
--- t/applications/addcontact.desktop
+++ t/applications/addcontact.desktop
@@ -5,4 +5,4 @@
Terminal=false
Type=Application
NotShowIn=X-MeeGo;
-MimeType=x-maemo-highlight/phone;
+MimeType=x-maemo-highlight/phone-number;
\ No newline at end of file
--- t/applications/browser.desktop
+++ t/applications/browser.desktop
+[Desktop Entry]
+Encoding=UTF-8
+Name=browser
+Exec=echo "browser with params:" %U
+Terminal=false
+Type=Application
+NotShowIn=X-MeeGo;
+MimeType=x-maemo-highlight/http-url;x-maemo-highlight/ftp-url;x-maemo-highlight/feed-url;x-maemo-highlight/ftp-url;
--- t/applications/caller.desktop
+++ t/applications/caller.desktop
@@ -5,4 +5,4 @@
Terminal=false
Type=Application
NotShowIn=X-MeeGo;
-MimeType=x-maemo-highlight/phone;x-maemo-highlight/url;
+MimeType=x-maemo-highlight/phone-number;
--- t/applications/complexmusic.desktop
+++ t/applications/complexmusic.desktop
+[Desktop Entry]
+Encoding=UTF-8
+Name=complex_musicplayer
+GenericName=A complex music player
+Icon=execicon
+Comment=Views audio
+Exec=echo complex_musicplayer %U
+Terminal=false
+Type=Application
+MimeType=x-maemo-nepomuk/music-piece;audio/mpeg;
+NotShowIn=X-MeeGo;
--- t/applications/defaults.list
+++ t/applications/defaults.list
@@ -4,5 +4,7 @@
x-maemo-highlight/url=caller.desktop
x-maemo-highlight/ovoda=ovoda.desktop
x-maemo-nepomuk/image=galleryserviceinterface.desktop
+x-maemo-nepomuk/calendar-event=nonexistent.desktop
+application/pdf=nonexistent.desktop
image/*=plainimageviewer.desktop
audio/*=plainmusicplayer.desktop
--- t/applications/gallerywithfilename.desktop
+++ t/applications/gallerywithfilename.desktop
+[Desktop Entry]
+Encoding=UTF-8
+Name=fake gallery
+Terminal=false
+Type=Application
+MimeType=image/png;
+NotShowIn=X-MeeGo;
+X-Maemo-Service=just.a.gallery
+X-Maemo-Method=com.nokia.galleryserviceinterface.showImage
--- t/applications/mimeinfo.cache
+++ t/applications/mimeinfo.cache
@@ -1,12 +1,17 @@
[MIME Cache]
x-maemo-nepomuk/person-contact=contacthandler.desktop
-x-maemo-highlight/url=caller.desktop
text/*=fixedparams.desktop
-x-maemo-highlight/ovoda=ovoda.desktop
+image/png=gallerywithfilename.desktop;uriprinter.desktop;
image/*=plainimageviewer.desktop
x-maemo-nepomuk/image=galleryserviceinterface.desktop;trackerimageviewer.desktop;other.desktop;upload.desktop;show.desktop;
-x-maemo-highlight/phone=addcontact.desktop;caller.desktop;
text/plain=uberexec.desktop;ubermeego.desktop;ubermimeopen.desktop;
+audio/mpeg=complexmusic.desktop
audio/*=plainmusicplayer.desktop
-x-maemo-highlight/email=emailer.desktop
+x-maemo-nepomuk/music-piece=complexmusic.desktop
x-maemo-urischeme/mailto=emailer.desktop
+x-maemo-highlight/email-address=emailer.desktop;
+x-maemo-highlight/http-url=browser.desktop;
+x-maemo-highlight/ftp-url=browser.desktop;
+x-maemo-highlight/feed-url=browser.desktop;
+x-maemo-highlight/phone-number=caller.desktop;
+x-maemo-highlight/special-url=special-browser.desktop;
--- t/applications/special-browser.desktop
+++ t/applications/special-browser.desktop
+[Desktop Entry]
+Encoding=UTF-8
+Name=browser
+Exec=echo "special browser with params:" %U
+Terminal=false
+Type=Application
+NotShowIn=X-MeeGo;
+MimeType=x-maemo-highlight/special-url;
--- t/applications/uriprinter.desktop
+++ t/applications/uriprinter.desktop
+[Desktop Entry]
+Encoding=UTF-8
+Name=UriPrinter
+Comment=Just prints the params into a file
+Exec=python -c "f2 = open('./executedAction', 'w'); f2.write(\"%U\\n\");"
+Terminal=false
+Type=Application
+MimeType=image/png;
+NotShowIn=X-MeeGo;
--- t/hl1.cpp
+++ t/hl1.cpp
-/*
- * Reads text from the standard input, highlight rules from the usual place
- * (ie. xml files in $CONTENTACTION_ACTIONS) and then prints match results on
- * the standard output. If the terminal is a tty, the results are printed on
- * stderr, and on stdout a beautifully colored version of the text is shown.
- */
-#include <stdio.h>
-#include <unistd.h>
-#include <contentaction.h>
-#include <QDebug>
-
-using namespace ContentAction;
-
-QDebug operator<<(QDebug dbg, const Match& m) {
- dbg.nospace() << "match at ("
- << m.start << ", " << m.end << "): ";
- foreach (const Action& a, m.actions) {
- dbg.space() << a.name();
- }
- dbg.nospace() << "\n";
- return dbg;
-}
-
-QDebug operator<<(QDebug dbg, const QList<Match>& ms) {
- foreach (const Match& m, ms) {
- dbg.space() << m;
- }
- return dbg;
-}
-
-int main(void)
-{
- QTextStream out(isatty(1) ? stderr : stdout);
- QTextStream textout(isatty(1) > 0 ? stdout : fopen("/dev/null", "w"));
- QTextStream in(stdin);
- QString text = in.readAll();
-
- QList<Match> ms = Action::highlight(text);
- foreach (const Match& m, ms) {
- QStringList actions;
- foreach (const Action& a, m.actions)
- actions << a.name();
- out << QString("%1 %2 '%3' %4\n").arg(QString::number(m.start),
- QString::number(m.end),
- text.mid(m.start, m.end - m.start),
- actions.join(" "));
- }
- QString hltext(text);
- if (isatty(1)) {
- qSort(ms.begin(), ms.end());
- QString color[] = {
- "\e[1;37;41m",
- "\e[1;37;42m",
- "\e[1;37;43m",
- "\e[1;37;44m",
- "\e[1;37;45m",
- "\e[1;37;46m",
- };
- int i = 0;
- int d = 0;
- foreach (const Match& m, ms) {
- hltext.insert(d + m.start, color[i]);
- d += color[i].length();
- i = (i + 1) % (sizeof(color) / sizeof(color[0]));
- hltext.insert(d + m.end, "\e[0m");
- d += 4;
- }
- textout << hltext;
- }
- return 0;
-}
--- t/hldemo.cpp
+++ t/hldemo.cpp
@@ -23,7 +23,7 @@
Us();
~Us();
-private slots:
+private Q_SLOTS:
void doHilite();
void doUnHilite();
--- t/hlinput.txt
+++ t/hlinput.txt
@@ -3,4 +3,58 @@
or 911
ooaoa+foo at motherland.ru
normal uri http://foo.bar.ru
-ovoda http://example.com/quux/323
+special url http://example.com/quux/323
+
+These should be valid phone numbers:
+number 1234567 is here
+number (303)499-7111 is here
+number +13034997111 is here
+number 303-499-7111 is here
+number +1(303)499-7111 is here
+number 303.499.7111, is here
+number (3034997111) is here
+number +48 123.12-3 123 is here
+number +481234p12345 is here
+number +481234#12345 is here
+number +358 (9) 123 456 is here
+
+These should be valid web addresses:
+http://us.m.yahoo.com
+http://www.google.com/m
+www.google.com/m
+<http://us.m.yahoo.com>
+http://maps.google.com/maps?f=d&source=s_d&saddr=Nieznana+droga&daddr=krak%C3%B3w&hl&geocode=Fa5h9wIdlq87Aq%3BFQrt-wIdFFYwASnRGE41wEQWRzG_ikd2tbZrtA&mra=ls&sll=49.915862,20.323334&sspn=0.505808,1.234589&ie=UTF8&t=h&z=10
+http://host-with-dash.com/path?%:@&=+$,-!~*'with(special)chars
+
+And other browsable urls:
+feed://browsefeed.com
+feed:browsefeed.com
+ftp://browseftp.com
+
+These should be valid e-mail addresses:
+Address with an extra dot: john.doe at att.com.
+<mailto:john_doe2 at att.com>
+
+These are suspicious phone numbers:
+sometextbefore333222111444sometextafter
++(((((
++358+7777
+i bought 13 bananas
+too short phone number: 14
+too long phone number: 151515151515151515151
+but these are ok: 141 and 14141414141414141414
+
+These are suspicious e-mail addresses:
+double at atsign@bar.com
+onlyuser at andhostname
+onlyuser2 at andhostname2.
+USERNAME at ALLUPPERCASE.COM
+
+These are suspicious web addresses:
+http://http://double.http.com
+
+These are some previous error cases:
+this is an url www.myurl.com/foo/bar and e-mail first at home.com
+1112223338;email at domain.org;4445556668;email2 at domain.org
+Http://www.capital.com
+hTTp://www.capital.com
--- t/linktest.cpp
+++ t/linktest.cpp
@@ -3,6 +3,8 @@
#include "contentaction.h"
#include "internal.h"
+#include <MDesktopEntry>
+
using namespace ContentAction;
using namespace ContentAction::Internal;
@@ -29,6 +31,11 @@
setMimeDefault("foo", "bar");
QList<Action> list = actionsForMime("foo");
setMimeDefault("foo", list[0]);
+
+ QSharedPointer<MDesktopEntry> m(new MDesktopEntry("some.desktop"));
+ Action d = Action::launcherAction(m, QStringList() << "param1" << "param2");
+
+ Action e = Action::launcherAction("some.desktop", QStringList() << "param1" << "param2");
}
int main(int argc, char **argv)
--- t/servicelistener.cpp
+++ t/servicelistener.cpp
@@ -7,7 +7,7 @@
class Dummy : public QObject
{
Q_OBJECT
-public slots:
+public Q_SLOTS:
void timeout()
{
static int n = 0;
--- t/test-desktop-launching.py
+++ t/test-desktop-launching.py
@@ -55,6 +55,15 @@
os.remove("./launchedAction")
self.assert_(content.find("I was launched") != -1)
+ def testLaunchWithParams(self):
+ (status, output) = getstatusoutput("lca-tool --triggerdesktop uriprinter.desktop param1 param2 param3")
+ f = open("./executedAction")
+ content = f.read()
+ f.close()
+ os.remove("./executedAction")
+ self.assert_(status == 0)
+ self.assert_(content.find("'param1' 'param2' 'param3'") != -1)
+
def runTests():
suite = unittest.TestLoader().loadTestsFromTestCase(Launching)
result = unittest.TextTestRunner(verbosity=2).run(suite)
--- t/test-highlight.sh
+++ t/test-highlight.sh
@@ -8,9 +8,77 @@
expr "$1" : "$2" >/dev/null;
}
-res=$(./hl1 < $srcdir/hlinput.txt)
+res=$(lca-tool --highlight < $srcdir/hlinput.txt)
strstr "$res" ".*61 73 '+44 433 2236' caller" || exit 1
-strstr "$res" ".*77 80 '911' caller" || exit 1
+strstr "$res" ".*77 80 '911' caller" || exit 1
strstr "$res" ".*15 33 'email at address.here' emailer" || exit 1
strstr "$res" ".*81 104 'ooaoa+foo at motherland.ru' emailer" || exit 1
+
+# phone numbers
+
+strstr "$res" ".*'1234567' caller" || exit 2
+strstr "$res" ".*'(303)499-7111' caller" || exit 2
+strstr "$res" ".*'+13034997111' caller" || exit 2
+strstr "$res" ".*'303-499-7111' caller" || exit 2
+strstr "$res" ".*'+1(303)499-7111' caller" || exit 2
+strstr "$res" ".*'303.499.7111' caller" || exit 2
+strstr "$res" ".*'3034997111' caller" || exit 2
+strstr "$res" ".*'+48 123.12-3 123' caller" || exit 2
+strstr "$res" ".*'+481234p12345' caller" || exit 2
+strstr "$res" ".*'+481234#12345' caller" || exit 2
+strstr "$res" ".*'+358 (9) 123 456' caller" || exit 2
+
+# web addresses
+
+strstr "$res" ".*'http://us.m.yahoo.com' browser" || exit 3
+strstr "$res" ".*'http://www.google.com/m' browser" || exit 3
+strstr "$res" ".*'www.google.com/m' browser" || exit 3
+strstr "$res" ".*'http://us.m.yahoo.com' browser" || exit 3
+strstr "$res" ".*'http://maps.google.com/maps?f=d&source=s_d&saddr=Nieznana+droga&daddr=krak%C3%B3w&hl&geocode=Fa5h9wIdlq87Aq%3BFQrt-wIdFFYwASnRGE41wEQWRzG_ikd2tbZrtA&mra=ls&sll=49.915862,20.323334&sspn=0.505808,1.234589&ie=UTF8&t=h&z=10' browser" || exit 3
+strstr "$res" ".*'http://host-with-dash.com/path?%:@&=+\\$,-!~\\*'with(special)chars' browser" || exit 3
+
+strstr "$res" ".*feed://browsefeed.com' browser" || exit 3
+strstr "$res" ".*feed:browsefeed.com' browser" || exit 3
+strstr "$res" ".*ftp://browseftp.com' browser" || exit 3
+
+# email addresses
+strstr "$res" ".*'john.doe at att.com' emailer" || exit 4
+strstr "$res" ".*'mailto:john_doe2 at att.com' emailer" || exit 4
+
+# invalid and almost-invalid cases
+strstr "$res" ".*'333222111444' caller" && exit 5
+strstr "$res" ".*'+((((' caller" && exit 5
+#+358 and +7777 will be recognized separately, though
+strstr "$res" ".*'+358+7777' caller" && exit 5
+#strstr "$res" ".*'+358' caller" && exit 5
+#strstr "$res" ".*'+7777' caller" && exit 5
+strstr "$res" ".*'13' caller" && exit 5
+strstr "$res" ".*'14' caller" && exit 5
+# a long phone number
+strstr "$res" ".*'151515151515151515151' caller" && exit 5
+# also: it's prefix shouldn't be recognized
+strstr "$res" ".*'15151515151515151515' caller" && exit 5
+strstr "$res" ".*'141' caller" || exit 5
+strstr "$res" ".*'14141414141414141414' caller" || exit 5
+
+strstr "$res" ".*'double at atsign@bar.com' emailer" && exit 5
+strstr "$res" ".*'onlyuser at andhostname' emailer" && exit 5
+strstr "$res" ".*'onlyuser2 at andhostname2.' emailer" && exit 5
+strstr "$res" ".*'USERNAME at ALLUPPERCASE.COM' emailer" || exit 5
+
+strstr "$res" ".*'http://http://double.http.com' browser" && exit 6
+strstr "$res" ".*'http://double.http.com' browser" || exit 6
+
+# previous bugs
+strstr "$res" ".*'www.myurl.com/foo/bar' browser" || exit 7
+strstr "$res" ".*'first at home.com' emailer" || exit 7
+strstr "$res" ".*'1112223338' caller" || exit 7
+strstr "$res" ".*'email at domain.org' emailer" || exit 7
+strstr "$res" ".*'4445556668' caller" || exit 7
+strstr "$res" ".*'email2 at domain.org' emailer" || exit 7
+
+strstr "$res" ".*'Http://www.capital.com' browser" || exit 8
+strstr "$res" ".*'hTTp://www.capital.com' browser" || exit 8
+
+exit 0
--- t/test-invalid-defaults.py
+++ t/test-invalid-defaults.py
+#!/usr/bin/python2.5
+##
+## Copyright (C) 2008, 2009 Nokia. All rights reserved.
+##
+## Contact: Marius Vollmer <marius.vollmer at nokia.com>
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public License
+## version 2.1 as published by the Free Software Foundation.
+##
+## This library 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
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+## 02110-1301 USA
+
+import sys
+import os
+# Otherwise env.py won't be found when running tests inside a VPATH build dir
+sys.path.insert(0, os.getcwd())
+
+try: import env
+except: pass
+
+import unittest
+from commands import getstatusoutput
+from cltool import CLTool
+
+# this controls where the test files are
+testfiles_dir = os.path.abspath('.')
+if 'MIME_TEST_DIR' in os.environ:
+ testfiles_dir = os.path.abspath(os.environ['MIME_TEST_DIR'])
+
+class InvalidDefaults(unittest.TestCase):
+ def testInvalidDefaultForUri(self):
+ # this uri is a ncal:Event, and x-maemo-nepomuk/calendar-event has a
+ # defaults.list entry pointing to a nonexistent application.
+ (status, output) = getstatusoutput("lca-tool --tracker --printdefault urn:test:calendarevent")
+ self.assert_(status == 0)
+ self.assert_(output.find("Invalid action") != -1)
+
+ def testInvalidDefaultForFile(self):
+ filename = "file://" + testfiles_dir + "/empty.pdf"
+ (status, output) = getstatusoutput("lca-tool --file --printdefault " + filename)
+ self.assert_(status == 0)
+ self.assert_(output.find("Invalid action") != -1)
+
+def runTests():
+ suite = unittest.TestLoader().loadTestsFromTestCase(InvalidDefaults)
+ result = unittest.TextTestRunner(verbosity=2).run(suite)
+ return len(result.errors + result.failures)
+
+if __name__ == "__main__":
+ sys.exit(runTests())
--- t/test-regexps.py
+++ t/test-regexps.py
+#!/usr/bin/python2.5
+##
+## Copyright (C) 2008-2010 Nokia. All rights reserved.
+##
+## Contact: Marius Vollmer <marius.vollmer at nokia.com>
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public License
+## version 2.1 as published by the Free Software Foundation.
+##
+## This library 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
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+## 02110-1301 USA
+
+import sys
+import os
+# Otherwise env.py won't be found when running tests inside a VPATH build dir
+sys.path.insert(0, os.getcwd())
+
+try: import env
+except: pass
+
+import unittest
+from commands import getstatusoutput
+from cltool import CLTool
+from tempfile import mkdtemp
+
+class Regexps(unittest.TestCase):
+ def setUp(self):
+ pass
+ def tearDown(self):
+ pass
+
+ def testStringMimes1(self):
+ # only the general
+ (status, output) = getstatusoutput("lca-tool --string --printmimes foo")
+ self.assert_(status == 0)
+ self.assert_(output.find("general-1") != -1)
+ self.assert_(output.find("special-1a") == -1)
+ self.assert_(output.find("special-1b") == -1)
+
+ # general and one special case
+ (status, output) = getstatusoutput("lca-tool --string --printmimes foobar")
+ self.assert_(status == 0)
+ self.assert_(output.find("special-1a") != -1)
+ self.assert_(output.find("general-1") != -1)
+ self.assert_(output.find("special-1b") == -1)
+ # verify the order
+ self.assert_(output.find("special-1a") < output.find("general-1"))
+
+ # general and another special case
+ (status, output) = getstatusoutput("lca-tool --string --printmimes foobazxx")
+ self.assert_(status == 0)
+ self.assert_(output.find("special-1b") != -1)
+ self.assert_(output.find("general-1") != -1)
+ self.assert_(output.find("special-1a") == -1)
+ # verify the order
+ self.assert_(output.find("special-1b") < output.find("general-1"))
+
+ def testStringMimes2(self):
+ # only the general
+ (status, output) = getstatusoutput("lca-tool --string --printmimes cat")
+ self.assert_(status == 0)
+ self.assert_(output.find("general-2") != -1)
+ self.assert_(output.find("special-2") == -1)
+ self.assert_(output.find("superspecial-2") == -1)
+
+ # general and one special case
+ (status, output) = getstatusoutput("lca-tool --string --printmimes catdog")
+ self.assert_(status == 0)
+ self.assert_(output.find("general-2") != -1)
+ self.assert_(output.find("special-2") != -1)
+ self.assert_(output.find("superspecial-2") == -1)
+ # verify the order
+ self.assert_(output.find("special-2") < output.find("general-2"))
+
+ # general and both special cases
+ (status, output) = getstatusoutput("lca-tool --string --printmimes catdogzebra")
+ self.assert_(status == 0)
+ self.assert_(output.find("general-2") != -1)
+ self.assert_(output.find("special-2") != -1)
+ self.assert_(output.find("superspecial-2") != -1)
+ # verify the order
+ self.assert_(output.find("special-2") < output.find("general-2"))
+ self.assert_(output.find("superspecial-2") < output.find("special-2"))
+
+ def testActionsForString(self):
+ (status, output) = getstatusoutput("lca-tool --string --print www.foo.com")
+ self.assert_(status == 0)
+ self.assert_(output.find("browser") != -1)
+ self.assert_(output.find("special-browser") == -1)
+
+ (status, output) = getstatusoutput("lca-tool --string --print http://example.com")
+ self.assert_(status == 0)
+ self.assert_(output.find("special-browser") != -1)
+ self.assert_(output.find("browser") != -1)
+ self.assert_(output.find("special-browser") < output.find("browser"))
+
+ def testDefaultActionForString(self):
+ (status, output) = getstatusoutput("lca-tool --string --printdefault www.foo.com")
+ self.assert_(status == 0)
+ self.assert_(output.find("browser") != -1)
+
+ (status, output) = getstatusoutput("lca-tool --string --printdefault http://example.com")
+ self.assert_(status == 0)
+ self.assert_(output.find("special-browser") != -1)
+
+def runTests():
+ suite = unittest.TestLoader().loadTestsFromTestCase(Regexps)
+ result = unittest.TextTestRunner(verbosity=2).run(suite)
+ return len(result.errors + result.failures)
+
+if __name__ == "__main__":
+ sys.exit(runTests())
--- t/test-special-chars.py
+++ t/test-special-chars.py
+#!/usr/bin/python2.5
+##
+## Copyright (C) 2008, 2009 Nokia. All rights reserved.
+##
+## Contact: Marius Vollmer <marius.vollmer at nokia.com>
+##
+## This library is free software; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser General Public License
+## version 2.1 as published by the Free Software Foundation.
+##
+## This library 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
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+## 02110-1301 USA
+
+import sys
+import os
+# Otherwise env.py won't be found when running tests inside a VPATH build dir
+sys.path.insert(0, os.getcwd())
+
+try: import env
+except: pass
+
+import unittest
+from commands import getstatusoutput
+from cltool import CLTool
+
+class SpecialChars(unittest.TestCase):
+ def setUp(self):
+ # start a fake gallery service
+ self.gallery = CLTool("gallery.py")
+ self.assert_(self.gallery.expect("started"))
+ (status, output) = getstatusoutput("touch /tmp/some#file.mp3")
+ (status, output) = getstatusoutput("ls /tmp/some#file.mp3")
+
+ def tearDown(self):
+ self.gallery.kill()
+ (status, output) = getstatusoutput("rm /tmp/some#file.mp3")
+
+ def testDBusWithSpecialChars(self):
+ (status, output) = getstatusoutput("lca-tool --tracker --trigger gallerywithfilename specialchars.image")
+ self.assert_(status == 0)
+ # assert that the gallery was invoked
+ self.assert_(self.gallery.expect("showImage ; file:///tmp/%5Bspecial%5B.png"))
+
+ def testExecWithSpecialChars(self):
+ (status, output) = getstatusoutput("lca-tool --tracker --trigger uriprinter specialchars.image")
+ self.assert_(status == 0)
+ f = open("./executedAction")
+ content = f.read()
+ f.close()
+ os.remove("./executedAction")
+ self.assert_(content.find("'/tmp/[special[.png'") != -1)
+
+ def testActionsForFileWithSpecialChars(self):
+ filename = "file:///tmp/some%23file.mp3"
+ (status, output) = getstatusoutput("lca-tool --file --print " + filename)
+ self.assert_(status == 0)
+ self.assert_(output.find("plainmusicplayer") != -1)
+
+ def testActionsForFileWithSpecialChars2(self):
+ filename = "/tmp/some#file.mp3"
+ (status, output) = getstatusoutput("lca-tool --file --print " + filename)
+ self.assert_(status == 0)
+ self.assert_(output.find("plainmusicplayer") != -1)
+
+def runTests():
+ suite = unittest.TestLoader().loadTestsFromTestCase(SpecialChars)
+ result = unittest.TextTestRunner(verbosity=2).run(suite)
+ return len(result.errors + result.failures)
+
+if __name__ == "__main__":
+ sys.exit(runTests())
--- t/testdata.ttl
+++ t/testdata.ttl
@@ -24,6 +24,9 @@
<a.music> a nmm:MusicPiece, nie:DataObject ;
nie:url "file:///tmp/aaa.mp3" ;
nie:mimeType "audio/mpeg" .
+<a2.music> a nmm:MusicPiece, nie:DataObject ;
+ nie:url "file:///tmp/aaa2.mp3" ;
+ nie:mimeType "audio/mpeg" .
<b.music> a nmm:MusicPiece, nie:DataObject ;
nie:url "file:///tmp/bbb.wav" ;
nie:mimeType "audio/wav" .
@@ -43,6 +46,10 @@
nie:url "file:///tmp/bbb.png" ;
nie:mimeType "image/png" .
+<specialchars.image> a nfo:Image, nie:DataObject ;
+ nie:url "file:///tmp/%5Bspecial%5B.png" ;
+ nie:mimeType "image/png" .
+
<urn:uuid:1930642225> a nfo:WebHistory;
nie:title "www.piratebay.org 0";
nie:contentCreated "2009-04-23T17:02:08";
@@ -109,3 +116,4 @@
<urn:test:webhistory> a nfo:WebHistory ;
nfo:uri "mailto:foo at bar.com" .
+<urn:test:calendarevent> a ncal:Event .
--- t/tests.xml
+++ t/tests.xml
@@ -83,6 +83,20 @@
PATH=.:/usr/lib/libcontentaction-tests:$PATH XDG_DATA_HOME=/usr/share/libcontentaction-tests ./test-schemes.sh
</step>
</case>
+ <case name="test-special-chars" description="A test of questionable value.">
+ <step expected_result="0">
+ . /tmp/session_bus_address.user; \
+ cd /usr/share/libcontentaction-tests; \
+ PATH=.:/usr/lib/libcontentaction-tests:$PATH XDG_DATA_HOME=/usr/share/libcontentaction-tests ./test-special-chars.py
+ </step>
+ </case>
+ <case name="test-regexps" description="A test of questionable value.">
+ <step expected_result="0">
+ . /tmp/session_bus_address.user; \
+ cd /usr/share/libcontentaction-tests; \
+ PATH=.:/usr/lib/libcontentaction-tests:$PATH XDG_DATA_HOME=/usr/share/libcontentaction-tests CONTENTACTION_ACTIONS=/usr/share/libcontentaction-tests/data ./test-regexps.py
+ </step>
+ </case>
<environments>
<scratchbox>true</scratchbox>
++++++ libcontentaction.yaml
--- libcontentaction.yaml
+++ libcontentaction.yaml
@@ -1,14 +1,14 @@
Name: libcontentaction
Summary: Library for associating content with actions
-Version: 0.1.15
+Version: 0.1.35
Release: 1
Group: System/Desktop
License: LGPLv2.1
URL: http://maemo.gitorious.org/maemo-af/libcontentaction
Sources:
- "%{name}-%{version}.tar.gz"
-Patches:
- - fix_glib_ftbfs.patch
+Patches:
+ - 0001-Fix-python-version-for-tests.patch
Description: |
libcontentaction is a library for associating content with actions.
PkgConfigBR:
++++++ deleted files:
--- fix_glib_ftbfs.patch
More information about the MeeGo-commits
mailing list