summaryrefslogtreecommitdiffstats
path: root/kmrml
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit47d455dd55be855e4cc691c32f687f723d9247ee (patch)
tree52e236aaa2576bdb3840ebede26619692fed6d7d /kmrml
downloadtdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.tar.gz
tdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegraphics@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kmrml')
-rw-r--r--kmrml/AUTHORS1
-rw-r--r--kmrml/ChangeLog28
-rw-r--r--kmrml/Makefile.am1
-rw-r--r--kmrml/README95
-rw-r--r--kmrml/README.DEVELOPMENT41
-rw-r--r--kmrml/TODO15
-rw-r--r--kmrml/example-session.mrml142
-rw-r--r--kmrml/kmrml.lsm27
-rw-r--r--kmrml/kmrml.spec62
-rw-r--r--kmrml/kmrml/Makefile.am41
-rw-r--r--kmrml/kmrml/algorithmcombo.cpp66
-rw-r--r--kmrml/kmrml/algorithmcombo.h54
-rw-r--r--kmrml/kmrml/algorithmdialog.cpp132
-rw-r--r--kmrml/kmrml/algorithmdialog.h60
-rw-r--r--kmrml/kmrml/browser.cpp63
-rw-r--r--kmrml/kmrml/browser.h48
-rw-r--r--kmrml/kmrml/collectioncombo.cpp95
-rw-r--r--kmrml/kmrml/collectioncombo.h57
-rw-r--r--kmrml/kmrml/kcontrol/Makefile.am25
-rw-r--r--kmrml/kmrml/kcontrol/indexcleaner.cpp96
-rw-r--r--kmrml/kmrml/kcontrol/indexcleaner.h53
-rw-r--r--kmrml/kmrml/kcontrol/indexer.cpp190
-rw-r--r--kmrml/kmrml/kcontrol/indexer.h68
-rw-r--r--kmrml/kmrml/kcontrol/indextest.cpp43
-rw-r--r--kmrml/kmrml/kcontrol/indextest.h26
-rw-r--r--kmrml/kmrml/kcontrol/kcmkmrml.cpp146
-rw-r--r--kmrml/kmrml/kcontrol/kcmkmrml.desktop176
-rw-r--r--kmrml/kmrml/kcontrol/kcmkmrml.h52
-rw-r--r--kmrml/kmrml/kcontrol/mainpage.cpp501
-rw-r--r--kmrml/kmrml/kcontrol/mainpage.h109
-rw-r--r--kmrml/kmrml/kcontrol/serverconfigwidget.ui272
-rw-r--r--kmrml/kmrml/lib/Makefile.am11
-rw-r--r--kmrml/kmrml/lib/kmrml_config.cpp339
-rw-r--r--kmrml/kmrml/lib/kmrml_config.h123
-rw-r--r--kmrml/kmrml/lib/mrml_shared.cpp235
-rw-r--r--kmrml/kmrml/lib/mrml_shared.h166
-rw-r--r--kmrml/kmrml/lib/mrml_utils.cpp89
-rw-r--r--kmrml/kmrml/lib/mrml_utils.h50
-rw-r--r--kmrml/kmrml/lib/version.h6
-rw-r--r--kmrml/kmrml/lib/watcher_stub.cpp95
-rw-r--r--kmrml/kmrml/lib/watcher_stub.h36
-rw-r--r--kmrml/kmrml/loader.cpp121
-rw-r--r--kmrml/kmrml/loader.h72
-rw-r--r--kmrml/kmrml/mrml-servicemenu.desktop67
-rw-r--r--kmrml/kmrml/mrml.cpp267
-rw-r--r--kmrml/kmrml/mrml.desktop60
-rw-r--r--kmrml/kmrml/mrml.h84
-rw-r--r--kmrml/kmrml/mrml.protocol10
-rw-r--r--kmrml/kmrml/mrml_creator.cpp76
-rw-r--r--kmrml/kmrml/mrml_creator.h49
-rw-r--r--kmrml/kmrml/mrml_elements.cpp358
-rw-r--r--kmrml/kmrml/mrml_elements.h255
-rw-r--r--kmrml/kmrml/mrml_part.cpp857
-rw-r--r--kmrml/kmrml/mrml_part.desktop67
-rw-r--r--kmrml/kmrml/mrml_part.h175
-rw-r--r--kmrml/kmrml/mrml_view.cpp480
-rw-r--r--kmrml/kmrml/mrml_view.h180
-rw-r--r--kmrml/kmrml/mrmlsearch.cpp74
-rw-r--r--kmrml/kmrml/propertysheet.cpp206
-rw-r--r--kmrml/kmrml/propertysheet.h113
-rw-r--r--kmrml/kmrml/propertywidgets.cpp121
-rw-r--r--kmrml/kmrml/propertywidgets.h108
-rw-r--r--kmrml/kmrml/server/Makefile.am12
-rw-r--r--kmrml/kmrml/server/daemonwatcher.desktop103
-rw-r--r--kmrml/kmrml/server/watcher.cpp280
-rw-r--r--kmrml/kmrml/server/watcher.h107
66 files changed, 8237 insertions, 0 deletions
diff --git a/kmrml/AUTHORS b/kmrml/AUTHORS
new file mode 100644
index 00000000..9e0745fb
--- /dev/null
+++ b/kmrml/AUTHORS
@@ -0,0 +1 @@
+Carsten Pfeiffer <pfeiffer@kde.org>
diff --git a/kmrml/ChangeLog b/kmrml/ChangeLog
new file mode 100644
index 00000000..9dbd3ea3
--- /dev/null
+++ b/kmrml/ChangeLog
@@ -0,0 +1,28 @@
+Uh er, looks like I didn't add all the other changes lately :} Sorry...
+
+Sun May 6 04:40:52 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * UI is a bit nicer now (arrangement of thumbnail items)
+
+ * it's possible to search by example, i.e. by right-clicking
+ on one or more images and selecting "search for similar images"
+
+ * tiny bit of code cleanup
+
+Sat May 5 02:30:21 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * argh, fixed the bug that files couldn't get downloaded by
+ clicking on them and that the statusbar isn't updated.
+ casts suck :} That took me a lot of time to find out :(
+
+ * added middle-button -> create new window
+
+ * scroll to top when loading a new page
+
+ * show standard popupmenu on right-click on image
+
+ * schedule the slaves instead of creating all at once
+
+Sam Apr 28 00:09:17 CEST 2001 - Carsten Pfeiffer <pfeiffer@kde.org>
+ o Initial Creation
+ didn't do any entries until something is actually working :)
diff --git a/kmrml/Makefile.am b/kmrml/Makefile.am
new file mode 100644
index 00000000..c48d9eb6
--- /dev/null
+++ b/kmrml/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = kmrml
diff --git a/kmrml/README b/kmrml/README
new file mode 100644
index 00000000..59f2dd9b
--- /dev/null
+++ b/kmrml/README
@@ -0,0 +1,95 @@
+kio_mrml and mrml_part
+
+Carsten Pfeiffer <pfeiffer@kde.org> 2001/05/03
+----------------------------------------------------------------------
+These are the sources for an mrml kioslave and an accompanying KPart.
+
+
+How does it work in Konqueror?
+==============================
+For now, the MrmlPart is rather a proof of concept, than a full blown
+MRML client.
+
+You can start the MrmlPart by entering an appropriate URL into Konqueror,
+e.g. mrml://user:pass@host.domain:port
+user, pass and domain are optional, so if you're running a server locally
+yourself, you can enter mrml://localhost to make Konqueror show the
+MrmlPart. If you don't have a running GIFT-server, you can try out
+mrml://viper.unige.ch:12790 as an example. Then, Konqueror will try to
+connect the server at the given URL and show you a list of
+image-collections the server has available. You can specify the number
+of images a query should return and you can hit the Search-button
+to actually start the query. If you don't give an image as example for
+the query, it will return random images from the collection.
+
+Shortly after hitting the Search-button, you will see a list of images
+as thumbnails. Below every image is a small rectangle showing the
+similarity of the image with the example image(s). The longer the
+rectangle, the better the match.
+
+Even easier than entering the mrml URL is right-clicking on an image
+in Konqueror and selecting "Search for similar images..." in the context
+menu. This will open up a new Konqueror window where the query will start
+automatically. By default, this will try to contact a local server, i.e
+mrml://localhost. You can configure different servers in the KControl
+Module (System -> Advanced Search). The last chosen server will be used
+for those queries.
+
+Note that a remote server surely can't access an image from your home
+direcory though. I have to think a little bit about the usability of
+this :) The greatest use of this is when you've indexed your files
+and running an own GIFT server anyway. Ideally, the server could be
+started on demand, when a query comes up.
+
+
+MrmlPart:
+=========
+ This KPart makes use of the mrml ioslave to provide a full MRML
+client. MRML, Multimedia Retrieval Markup Language (see
+http://www.mrml.net) is a means to query CBIR (Content Based Image
+Retrieval) servers. An OpenSource server is the GIFT (GNU Image
+Finding Tool), see www.mrml.net for downloading the GIFT.
+
+You can query for images by choosing one or more "example" images.
+The server will search for images that have similarities to the
+example(s) you gave. Queries can be refined by specifying relevance,
+i.e. by including and excluding parts of the previous search result.
+
+
+mrml ioslave:
+=============
+ Basically this is not much more than a slave for asynchronous
+transport of "data". With the URL, you can specify the user, password
+and port, as well as the url of the server to connect to.
+
+The data exchange of client <-> slave is done via metaData, with an
+"mrml_data" key. The data that the slave sends to the client is sent
+in one big chunk, after all the data has arrived at the slave. This
+could be made configurable later.
+
+With a little tuning, one could turn this into a generic slave
+which can transport any kind of data.
+
+[mrmlsearch]
+This little baby is called from Konqueror's popupmenu, when you hit
+"Search for similar images...". This program simply gets the URLs
+from Konqueror and creates a query of the form
+mrml://host.com/?relevant=url1;url2;url3;url4....
+It will use the currently selected host in the KControl module
+System -> Advanced Search to perform the query.
+
+mrmlsearch will then invoke "kfmclient openURL query" to start open
+a new Konqueror window and perform the query.
+
+
+Thanks go to Wolfgang Mller <Wolfgang.Mueller@cui.unige.ch> for his
+work on the GIFT and for making me write this frontend :) I really
+had a WOW-effect about the GIFT, when MrmlPart returned the first
+query results.
+
+New versions of this package can be found at
+http://devel-home.kde.org/~pfeiffer/kmrml/
+See http://www.mrml.net for downloading the GIFT and more information.
+
+Have fun,
+ Carsten Pfeiffer
diff --git a/kmrml/README.DEVELOPMENT b/kmrml/README.DEVELOPMENT
new file mode 100644
index 00000000..6fbe600d
--- /dev/null
+++ b/kmrml/README.DEVELOPMENT
@@ -0,0 +1,41 @@
+This file gives an overview of the structure of the kmrml package.
+
+kmrml consists of the following:
+
+- kio_mrml: an ioslave that is able to contact an mrml daemon (i.e. the GIFT)
+ and transports the data from the daemon to its master (i.e. the
+ MrmlPart) as XML (MRML, Multimedia Retrieval Markup Language)
+
+- MrmlPart: the konqueror-embeddable controller and view
+
+- mrmlsearch: a small tool that is e.g. called from Konqueror's ContextMenu
+ "Search for similar images" to start an image query.
+
+- kcontrol/: a KDE Control Center module for configuring parts of the GIFT,
+ i.e. indexing directories, specifying GIFT hosts, etc.
+
+- server/: a kded module, i.e. a tiny little daemon, that can be told via
+ DCOP to start, restart upon failure and automatically/manually
+ stop services. It is completely independent of GIFT/kmrml.
+ It is used to have one centralized place where the gift server
+ is started (ensuring this happens only once, restarting it upon
+ failure and stopping the gift after all kio_mrml instances
+ have been killed.
+
+lib/: common stuff used by more than one module
+
+
+Useful URLs:
+
+The MRML DTD:
+http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/gift/gift/dtd/mrml.dtd?rev=HEAD&content-type=text/plain
+
+The GIFT Homepage:
+http://www.gnu.org/software/gift
+
+The fer-de-lance project homepage, under which the GIFT and kmrml are living
+http://www.fer-de-lance.org
+
+
+2002/08/08
+Carsten Pfeiffer <pfeiffer@kde.org>
diff --git a/kmrml/TODO b/kmrml/TODO
new file mode 100644
index 00000000..85a9aa7f
--- /dev/null
+++ b/kmrml/TODO
@@ -0,0 +1,15 @@
+- Konqueror Properties dialog for indexing directory? Or just a context menu entry?
+- make use of BrowserExtension, provide the actions
+- contextmenu
+- better layouting?
+- better keyboard support
+- progress report from slave
+- transfer mrml in chunks as data arrives?
+- finish algorithm configuration
+- integrate with KPaint so you can paint an example image
+- integrate with kamera, so that images from your digicam will be indexed automatically
+- create Konq ContextMenu plugin instead of the ServiceMenu thing (mrmlsearch binary)
+- proper browserextension (restorestate/savestate, history, implement actions)
+- a panel applet or tray app KDirWatching indexable dirs and re-indexing on demand
+
+lots more probably
diff --git a/kmrml/example-session.mrml b/kmrml/example-session.mrml
new file mode 100644
index 00000000..27b5c009
--- /dev/null
+++ b/kmrml/example-session.mrml
@@ -0,0 +1,142 @@
+ <algorithm-list>
+ <algorithm
+ algorithm-name="Classical IDF"
+ algorithm-id="a-cidf"
+ algorithm-type="a-cidf" >
+ cui-block-texture-histogram="no"
+ collection-id="c-0-40-20-27-3-101-5-116-0"
+ cui-pr-percentage-of-features="70"
+ cui-block-texture-blocks="no"
+ cui-weighting-function="ClassicalIDF"
+ cui-base-type="inverted_file"
+ cui-block-color-histogram="no"
+ cui-block-color-blocks="no"
+ <query-paradigm-list>
+ <query-paradigm/>
+ </query-paradigm-list>
+
+
+ <property-sheet
+ send-type="none"
+ maxsubsetsize="1"
+ property-sheet-id="cui-p-1"
+ minsubsetsize="0"
+ property-sheet-type="subset" >
+ <property-sheet
+ caption="Modify default configuration"
+ send-type="none"
+ property-sheet-id="cui-p0"
+ property-sheet-type="set-element" >
+
+ <property-sheet
+ send-name="cui-pr-percentage-of-features"
+ send-value="70"
+ caption="Prune at % of features"
+ send-type="attribute"
+ from="20"
+ to="100"
+ step="5"
+ property-sheet-id="cui-p15"
+ property-sheet-type="numeric" />
+
+ <property-sheet
+ send-type="none"
+ maxsubsetsize="4"
+ property-sheet-id="cui-p1"
+ minsubsetsize="1"
+ property-sheet-type="subset" >
+ <property-sheet
+ send-name="cui-block-color-blocks"
+ send-value="yes"
+ caption="Colour blocks"
+ send-type="attribute"
+ property-sheet-id="cui-p12"
+ send-boolean-inverted="yes"
+ property-sheet-type="set-element" />
+ <property-sheet
+ send-name="cui-block-texture-blocks"
+ send-value="yes"
+ caption="Gabor blocks"
+ send-type="attribute"
+ property-sheet-id="cui-p14"
+ send-boolean-inverted="yes"
+ property-sheet-type="set-element" />
+ <property-sheet
+ send-name="cui-block-texture-histogram"
+ send-value="yes"
+ caption="Gabor histogram"
+ send-type="attribute"
+ property-sheet-id="cui-p13"
+ send-boolean-inverted="yes"
+ property-sheet-type="set-element" />
+ <property-sheet
+ send-name="cui-block-color-histogram"
+ send-value="yes"
+ caption="Colour histogram"
+ send-type="attribute"
+ property-sheet-id="cui-p11"
+ send-boolean-inverted="yes"
+ property-sheet-type="set-element" />
+ </property-sheet>
+ </property-sheet>
+ </property-sheet>
+
+
+ </algorithm>
+
+
+ <!-- -->
+
+
+ <algorithm cui-perl-query-function="processGIFTQueryCall" algorithm-id="a-perl" cui-perl-script-file="/home/gis/gift-embed-perl-modules.pl" cui-perl-package="CGIFTLink" collection-id="c-0-40-20-27-3-101-5-116-0" cui-perl-random-function="processGIFTRandomQueryCall" cui-weighting-function="ClassicalIDF" algorithm-name="Perl link" cui-base-type="perl" algorithm-type="a-perl" >
+ <query-paradigm-list>
+ <query-paradigm type="inverted-file" />
+ <query-paradigm type="perl-demo" />
+ </query-paradigm-list>
+
+
+ <property-sheet send-type="none" maxsubsetsize="1" property-sheet-id="cui-p-1" minsubsetsize="0" property-sheet-type="subset" >
+ <property-sheet caption="Modify default configuration" send-type="none" property-sheet-id="cui-p0" property-sheet-type="set-element" />
+ </property-sheet>
+ </algorithm>
+ <algorithm cui-block-texture-histogram="no" algorithm-id="adefault" collection-id="c-0-40-20-27-3-101-5-116-0" cui-pr-percentage-of-features="70" cui-block-texture-blocks="no" cui-weighting-function="ClassicalIDF" algorithm-name="Separate Normalisation" cui-base-type="multiple" cui-block-color-histogram="no" cui-block-color-blocks="no" algorithm-type="adefault" >
+ <algorithm cui-block-texture-histogram="yes" algorithm-id="sub1" cui-pr-percentage-of-features="100" cui-block-texture-blocks="yes" algorithm-name="sub1" cui-base-type="inverted_file" cui-block-color-blocks="yes" algorithm-type="sub1" />
+ <algorithm cui-block-texture-histogram="yes" algorithm-id="sub2" cui-block-texture-blocks="yes" algorithm-name="sub2" cui-base-type="inverted_file" cui-block-color-histogram="yes" algorithm-type="sub2" />
+ <algorithm algorithm-id="sub3" cui-pr-percentage-of-features="100" cui-block-texture-blocks="yes" algorithm-name="sub3" cui-base-type="inverted_file" cui-block-color-histogram="yes" cui-block-color-blocks="yes" algorithm-type="sub3" />
+ <algorithm cui-block-texture-histogram="yes" algorithm-id="sub4" algorithm-name="sub4" cui-base-type="inverted_file" cui-block-color-histogram="yes" cui-block-color-blocks="yes" algorithm-type="sub4" />
+ <query-paradigm-list>
+ <query-paradigm/>
+ </query-paradigm-list>
+ <property-sheet send-type="none" maxsubsetsize="1" property-sheet-id="cui-p-1" minsubsetsize="0" property-sheet-type="subset" >
+ <property-sheet caption="Modify default configuration" send-type="none" property-sheet-id="cui-p0" property-sheet-type="set-element" >
+ <property-sheet send-name="cui-pr-percentage-of-features" send-value="70" caption="Prune at % of features" send-type="attribute" from="20" to="100" step="5" property-sheet-id="cui-p15" property-sheet-type="numeric" />
+ <property-sheet send-type="none" maxsubsetsize="4" property-sheet-id="cui-p1" minsubsetsize="1" property-sheet-type="subset" >
+ <property-sheet send-name="cui-block-color-blocks" send-value="yes" caption="Colour blocks" send-type="attribute" property-sheet-id="cui-p12" send-boolean-inverted="yes" property-sheet-type="set-element" />
+ <property-sheet send-name="cui-block-texture-blocks" send-value="yes" caption="Gabor blocks" send-type="attribute" property-sheet-id="cui-p14" send-boolean-inverted="yes" property-sheet-type="set-element" />
+ <property-sheet send-name="cui-block-texture-histogram" send-value="yes" caption="Gabor histogram" send-type="attribute" property-sheet-id="cui-p13" send-boolean-inverted="yes" property-sheet-type="set-element" />
+ <property-sheet send-name="cui-block-color-histogram" send-value="yes" caption="Colour histogram" send-type="attribute" property-sheet-id="cui-p11" send-boolean-inverted="yes" property-sheet-type="set-element" />
+ </property-sheet>
+ </property-sheet>
+ </property-sheet>
+ </algorithm>
+ </algorithm-list>
+
+
+
+ <collection-list>
+ <collection
+ collection-name="images"
+ collection-id="c-0-40-20-27-3-101-5-116-0"
+ cui-inverted-file-location="InvertedFile.db"
+ cui-offset-file-location="InvertedFileOffset.db"
+ cui-algorithm-id-list-id="ail-inverted-file"
+ cui-feature-file-location="url2fts.xml"
+ cui-feature-description-location="InvertedFileFeatureDescription.db"
+ cui-base-dir="/home/gis/gift-indexing-data/images//"
+ cui-number-of-images="372" >
+ <query-paradigm-list>
+ <query-paradigm type="inverted-file" />
+ <query-paradigm type="perl-demo" />
+ </query-paradigm-list>
+ </collection>
+ </collection-list>
diff --git a/kmrml/kmrml.lsm b/kmrml/kmrml.lsm
new file mode 100644
index 00000000..4b2dfeb6
--- /dev/null
+++ b/kmrml/kmrml.lsm
@@ -0,0 +1,27 @@
+Begin3
+Title: MRML for KDE -- Content based image retrieval
+Version: 0.3.2
+Entered-date: 2001/06/05
+Description: MRML is short for Multimedia Retrieval Markup Language,
+ which defines a protocol for querying a server for images
+ based on their content. See http://www.mrml.net about MRML
+ and the GNU Image Finding Tool (GIFT), an MRML server.
+
+ This package consists of an mrml kio-slave that handles
+ the communication with the MRML server and a KPart to
+ be embedded e.g. into Konqueror.
+
+ With those, you can search for images by giving an example
+ image and let the server look up similar images. The query
+ result can be refined by giving positive/negative feedback.
+Keywords: Image retrieval, GIFT, MRML, Konqueror, KDE, Qt
+Author: Carsten Pfeiffer <pfeiffer@kde.org>
+Maintained-by: Carsten Pfeiffer <pfeiffer@kde.org>
+Home-page: http://devel-home.kde.org/~pfeiffer/kmrml/
+Alternate-site: ftp://ftp.kde.org/pub/kde/unstable/apps/utils
+Primary-site: http://devel-home.kde.org/~pfeiffer/kmrml/
+ xxxxxx kmrml-0.3.2.tgz
+ xxx kmrml-0.3.2.lsm
+Platform: Unix. Needs KDE 3.x
+Copying-policy: GPL
+End
diff --git a/kmrml/kmrml.spec b/kmrml/kmrml.spec
new file mode 100644
index 00000000..79dbab29
--- /dev/null
+++ b/kmrml/kmrml.spec
@@ -0,0 +1,62 @@
+%define version 0.3
+%define release 1
+%define serial 1
+%define prefix /opt/kde3
+
+Name: kmrml
+Summary: MRML for KDE -- Content based image retrieval
+Version: %{version}
+Release: %{release}
+Serial: %{serial}
+Source: http://devel-home.kde.org/~pfeiffer/kmrml/kmrml-%{version}.tgz
+URL: http://devel-home.kde.org/~pfeiffer/kmrml/
+Copyright: GPL
+Packager: Carsten Pfeiffer <pfeiffer@kde.org>
+Group: X11/KDE/Utilities
+BuildRoot: /tmp/kmrml-%{version}-root
+Prefix: %{prefix}
+
+%description
+MRML is short for Multimedia Retrieval Markup Language,
+which defines a protocol for querying a server for images
+based on their content. See http://www.mrml.net about MRML
+and the GNU Image Finding Tool (GIFT), an MRML server.
+
+This package consists of an mrml kio-slave that handles
+the communication with the MRML server and a KPart to
+be embedded e.g. into Konqueror.
+
+With those, you can search for images by giving an example
+image and let the server look up similar images. The query
+result can be refined by giving positive/negative feedback.
+
+Install with '--prefix $KDEDIR' unless you have KDE in /opt/kde3
+
+%prep
+rm -rf $RPM_BUILD_ROOT
+
+%setup -n kmrml-%{version}
+
+%build
+export KDEDIR=%{prefix}
+CXXFLAGS="$RPM_OPT_FLAGS -fno-exceptions -malign-functions=2 -malign-jumps=2 -malign-loops=2 -pipe" LDFLAGS=-s ./configure --prefix=%{prefix} --enable-final --disable-debug
+mkdir -p $RPM_BUILD_ROOT
+make
+
+%install
+make install DESTDIR=$RPM_BUILD_ROOT
+
+cd $RPM_BUILD_ROOT
+
+find . -type d | sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' > $RPM_BUILD_DIR/file.list.%{name}
+
+find . -type f | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.%{name}
+
+find . -type l | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.%{name}
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+rm -f $RPM_BUILD_DIR/file.list.%{name}
+
+%files -f ../file.list.%{name}
+
diff --git a/kmrml/kmrml/Makefile.am b/kmrml/kmrml/Makefile.am
new file mode 100644
index 00000000..440e1123
--- /dev/null
+++ b/kmrml/kmrml/Makefile.am
@@ -0,0 +1,41 @@
+SUBDIRS = server lib kcontrol
+INCLUDES= -I$(top_srcdir)/kmrml/kmrml/lib $(all_includes)
+METASOURCES = AUTO
+
+LIB_KMRMLSTUFF = $(top_builddir)/kmrml/kmrml/lib/libkmrmlstuff.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kio_mrml.la libkmrmlpart.la
+
+kio_mrml_la_SOURCES = mrml.cpp
+kio_mrml_la_LIBADD = $(LIB_KMRMLSTUFF) $(LIB_KIO)
+kio_mrml_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+
+libkmrmlpart_la_SOURCES = mrml_part.cpp mrml_view.cpp loader.cpp \
+ mrml_elements.cpp mrml_creator.cpp browser.cpp algorithmdialog.cpp \
+ collectioncombo.cpp algorithmcombo.cpp propertysheet.cpp
+libkmrmlpart_la_LIBADD = $(LIB_KMRMLSTUFF) $(LIB_KPARTS)
+libkmrmlpart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN)
+
+services_DATA = mrml.protocol mrml_part.desktop
+servicesdir = $(kde_servicesdir)
+
+mimetypes_DATA = mrml.desktop
+mimetypesdir = $(kde_mimedir)/text
+
+servicemenu_DATA = mrml-servicemenu.desktop
+servicemenudir = $(kde_datadir)/konqueror/servicemenus
+
+#############################################
+bin_PROGRAMS =
+lib_LTLIBRARIES =
+kdeinit_LTLIBRARIES = mrmlsearch.la
+
+mrmlsearch_la_LIBADD = $(LIB_KMRMLSTUFF) $(LIB_KDECORE)
+mrmlsearch_la_LDFLAGS = $(all_libraries) -module -avoid-version
+mrmlsearch_la_SOURCES = mrmlsearch.cpp
+
+messages:
+ $(EXTRACTRC) */*.ui > rc.cpp
+ $(XGETTEXT) *.h *.cpp */*.cpp */*.h -o $(podir)/kmrml.pot
diff --git a/kmrml/kmrml/algorithmcombo.cpp b/kmrml/kmrml/algorithmcombo.cpp
new file mode 100644
index 00000000..b22556df
--- /dev/null
+++ b/kmrml/kmrml/algorithmcombo.cpp
@@ -0,0 +1,66 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "algorithmcombo.h"
+
+#include <kdatastream.h>
+
+using namespace KMrml;
+
+// ### copycat of CollectionCombo... moc can't handle templates unfortunately..
+// could use base-class MrmlElement....
+
+AlgorithmCombo::AlgorithmCombo( QWidget *parent, const char *name )
+ : KComboBox( false, parent, name ),
+ m_algorithms( 0L )
+{
+ connect( this, SIGNAL( activated( const QString& ) ),
+ SLOT( slotActivated( const QString& ) ));
+}
+
+AlgorithmCombo::~AlgorithmCombo()
+{
+}
+
+void AlgorithmCombo::setAlgorithms( const AlgorithmList *algorithms )
+{
+ assert( algorithms != 0L );
+
+ clear();
+ m_algorithms = algorithms;
+ insertStringList( algorithms->itemNames() );
+ // #### block signals here?
+}
+
+void AlgorithmCombo::setCurrent( const Algorithm& coll )
+{
+ setCurrentItem( coll.name() );
+}
+
+Algorithm AlgorithmCombo::current() const
+{
+ return m_algorithms->findByName( currentText() );
+}
+
+void AlgorithmCombo::slotActivated( const QString& name )
+{
+ Algorithm coll = m_algorithms->findByName( name );
+ emit selected( coll );
+}
+
+#include "algorithmcombo.moc"
diff --git a/kmrml/kmrml/algorithmcombo.h b/kmrml/kmrml/algorithmcombo.h
new file mode 100644
index 00000000..3e151933
--- /dev/null
+++ b/kmrml/kmrml/algorithmcombo.h
@@ -0,0 +1,54 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef ALGORITHMCOMBO_H
+#define ALGORITHMCOMBO_H
+
+#include <kcombobox.h>
+
+#include "mrml_elements.h"
+
+namespace KMrml
+{
+
+ class AlgorithmCombo : public KComboBox
+ {
+ Q_OBJECT
+
+ public:
+ AlgorithmCombo( QWidget *parent, const char *name = 0 );
+ ~AlgorithmCombo();
+
+ void setAlgorithms( const AlgorithmList * algorithms );
+ void setCurrent( const Algorithm& coll );
+
+ Algorithm current() const;
+
+ signals:
+ void selected( const Algorithm& );
+
+ private slots:
+ void slotActivated( const QString& );
+
+ private:
+ const AlgorithmList *m_algorithms;
+ };
+
+}
+
+#endif // ALGORITHMCOMBO_H
diff --git a/kmrml/kmrml/algorithmdialog.cpp b/kmrml/kmrml/algorithmdialog.cpp
new file mode 100644
index 00000000..cb62fd84
--- /dev/null
+++ b/kmrml/kmrml/algorithmdialog.cpp
@@ -0,0 +1,132 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "algorithmdialog.h"
+#include "algorithmcombo.h"
+#include "collectioncombo.h"
+
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qscrollview.h>
+#include <qvbox.h>
+#include <qvgroupbox.h>
+
+#include <klocale.h>
+
+using namespace KMrml;
+
+class ScrollView : public QScrollView
+{
+public:
+ ScrollView(QWidget* parent = 0, const char* name = 0)
+ : QScrollView(parent, name)
+ {
+ setFrameStyle(QFrame::NoFrame);
+ m_frame = new QFrame(viewport(), "ScrollView::m_frame");
+ m_frame->setFrameStyle(QFrame::NoFrame);
+ addChild(m_frame, 0, 0);
+ };
+
+ QFrame* frame() {return m_frame;};
+
+protected:
+ virtual void viewportResizeEvent(QResizeEvent* ev)
+ {
+ QScrollView::viewportResizeEvent(ev);
+ m_frame->resize( kMax(m_frame->sizeHint().width(), ev->size().width()),
+ kMax(m_frame->sizeHint().height(), ev->size().height()));
+ };
+
+private:
+ QFrame* m_frame;
+};
+
+AlgorithmDialog::AlgorithmDialog( const AlgorithmList& algorithms,
+ const CollectionList& collections,
+ const Collection& currentColl,
+ QWidget *parent, const char *name )
+ : KDialogBase( parent, name, false, i18n("Configure Query Algorithms"),
+ Ok | Cancel, Ok, false ),
+ m_allAlgorithms( algorithms ),
+ m_collections( collections )
+{
+ QWidget *box = makeMainWidget();
+
+ QVBoxLayout *mainLayout = new QVBoxLayout( box, 0, KDialog::spacingHint(),
+ "mainLayout");
+
+ QHBoxLayout *collectionLayout = new QHBoxLayout( 0L, 0, 0, "coll layout");
+ collectionLayout->addWidget( new QLabel( i18n("Collection: "), box ));
+
+ m_collectionCombo = new CollectionCombo( box, "collection combo" );
+ m_collectionCombo->setCollections( &m_collections );
+ collectionLayout->addWidget( m_collectionCombo );
+
+ mainLayout->addLayout( collectionLayout );
+ mainLayout->addSpacing( 14 );
+
+ QHBox *algoHLayout = new QHBox( box );
+ (void) new QLabel( i18n("Algorithm: "), algoHLayout);
+ m_algoCombo = new AlgorithmCombo( algoHLayout, "algo combo" );
+
+ QVGroupBox *groupBox = new QVGroupBox( box, "groupBox" );
+ mainLayout->addWidget( groupBox );
+ algoHLayout->raise();
+
+ ScrollView *scrollView = new ScrollView( groupBox, "scroll view" );
+ m_view = scrollView->frame();
+ QVBoxLayout *viewLayout = new QVBoxLayout( scrollView );
+ viewLayout->setSpacing( KDialog::spacingHint() );
+
+
+ collectionChanged( currentColl );
+
+ connect( m_algoCombo, SIGNAL( selected( const Algorithm& ) ),
+ SLOT( initGUI( const Algorithm& ) ));
+ connect( m_collectionCombo, SIGNAL( selected( const Collection& ) ),
+ SLOT( collectionChanged( const Collection& ) ));
+
+ algoHLayout->adjustSize();
+ mainLayout->activate();
+ algoHLayout->move( groupBox->x() + 10, groupBox->y() - 12 );
+
+ box->setMinimumWidth( algoHLayout->sizeHint().width() +
+ 4 * KDialog::spacingHint() );
+}
+
+AlgorithmDialog::~AlgorithmDialog()
+{
+}
+
+void AlgorithmDialog::collectionChanged( const Collection& coll )
+{
+ m_algosForCollection = m_allAlgorithms.algorithmsForCollection( coll );
+ m_algoCombo->setAlgorithms( &m_algosForCollection );
+
+ initGUI( m_algoCombo->current() );
+}
+
+void AlgorithmDialog::initGUI( const Algorithm& algo )
+{
+ m_algo = algo;
+
+
+}
+
+#include "algorithmdialog.moc"
diff --git a/kmrml/kmrml/algorithmdialog.h b/kmrml/kmrml/algorithmdialog.h
new file mode 100644
index 00000000..740a95bf
--- /dev/null
+++ b/kmrml/kmrml/algorithmdialog.h
@@ -0,0 +1,60 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef ALGORITHMDIALOG_H
+#define ALGORITHMDIALOG_H
+
+#include <kdialogbase.h>
+
+#include "mrml_elements.h"
+
+namespace KMrml
+{
+ class AlgorithmCombo;
+ class CollectionCombo;
+
+ class AlgorithmDialog : public KDialogBase
+ {
+ Q_OBJECT
+
+ public:
+ AlgorithmDialog( const AlgorithmList&, const CollectionList&,
+ const Collection& currentColl,
+ QWidget *parent = 0, const char *name = 0 );
+ ~AlgorithmDialog();
+
+ private slots:
+ void collectionChanged( const Collection& );
+ void initGUI( const Algorithm& algo );
+
+ private:
+ Algorithm m_algo;
+ AlgorithmList m_allAlgorithms;
+ AlgorithmList m_algosForCollection;
+ CollectionList m_collections;
+
+ CollectionCombo *m_collectionCombo;
+ AlgorithmCombo *m_algoCombo;
+
+ QFrame *m_view;
+ };
+
+}
+
+#endif // ALGORITHMDIALOG_H
diff --git a/kmrml/kmrml/browser.cpp b/kmrml/kmrml/browser.cpp
new file mode 100644
index 00000000..f2453243
--- /dev/null
+++ b/kmrml/kmrml/browser.cpp
@@ -0,0 +1,63 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "browser.h"
+#include "mrml_part.h"
+
+#include <qscrollview.h>
+
+using namespace KMrml;
+
+Browser::Browser( MrmlPart *parent, const char *name )
+ : KParts::BrowserExtension( parent, name ),
+ m_part( parent )
+{
+
+}
+
+Browser::~Browser()
+{
+
+}
+
+void Browser::saveState( QDataStream& stream )
+{
+// BrowserExtension::saveState( stream );
+
+ m_part->saveState( stream );
+}
+
+void Browser::restoreState( QDataStream& stream )
+{
+// BrowserExtension::restoreState( stream );
+ // ### BrowserExtension::restoreState() calls openURL() at the end (arghh).
+
+ m_part->restoreState( stream );
+}
+
+int Browser::xOffset()
+{
+ return static_cast<QScrollView*>( m_part->widget())->contentsX();
+}
+
+int Browser::yOffset()
+{
+ return static_cast<QScrollView*>( m_part->widget())->contentsY();
+}
+
+#include "browser.moc"
diff --git a/kmrml/kmrml/browser.h b/kmrml/kmrml/browser.h
new file mode 100644
index 00000000..11661ed5
--- /dev/null
+++ b/kmrml/kmrml/browser.h
@@ -0,0 +1,48 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef BROWSER_H
+#define BROWSER_H
+
+#include <kparts/browserextension.h>
+
+namespace KMrml
+{
+ class MrmlPart;
+
+ class Browser : public KParts::BrowserExtension
+ {
+ Q_OBJECT
+
+ public:
+ Browser( MrmlPart *parent, const char *name );
+ ~Browser();
+
+ virtual void saveState( QDataStream& stream );
+ virtual void restoreState( QDataStream& stream );
+
+ virtual int xOffset();
+ virtual int yOffset();
+
+ private:
+ MrmlPart *m_part;
+ };
+
+}
+
+#endif // BROWSER_H
diff --git a/kmrml/kmrml/collectioncombo.cpp b/kmrml/kmrml/collectioncombo.cpp
new file mode 100644
index 00000000..b45d7ebf
--- /dev/null
+++ b/kmrml/kmrml/collectioncombo.cpp
@@ -0,0 +1,95 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "collectioncombo.h"
+
+#include <kdatastream.h>
+
+using namespace KMrml;
+
+CollectionCombo::CollectionCombo( QWidget *parent, const char *name )
+ : KComboBox( false, parent, name ),
+ m_collections( 0L )
+{
+ connect( this, SIGNAL( activated( const QString& ) ),
+ SLOT( slotActivated( const QString& ) ));
+}
+
+CollectionCombo::~CollectionCombo()
+{
+}
+
+void CollectionCombo::setCollections( const CollectionList *collections )
+{
+ assert( collections != 0L );
+
+ clear();
+ m_collections = collections;
+ insertStringList( collections->itemNames() );
+ // #### block signals here?
+}
+
+void CollectionCombo::setCurrent( const Collection& coll )
+{
+ setCurrentItem( coll.name() );
+}
+
+Collection CollectionCombo::current() const
+{
+ return m_collections->findByName( currentText() );
+}
+
+void CollectionCombo::slotActivated( const QString& name )
+{
+ Collection coll = m_collections->findByName( name );
+ emit selected( coll );
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream,
+ const CollectionCombo& combo )
+{
+ int count = combo.count();
+ stream << count;
+ for ( int i = 0; i < count; i++ )
+ stream << combo.text( i );
+
+ stream << combo.currentItem();
+ return stream;
+}
+
+QDataStream& KMrml::operator>>( QDataStream& stream, CollectionCombo& combo )
+{
+ combo.clear();
+
+ int count;
+ stream >> count;
+ QString text;
+ for ( int i = 0; i < count; i++ )
+ {
+ stream >> text;
+ combo.insertItem( text );
+ }
+
+ int current;
+ stream >> current;
+ combo.setCurrentItem( current );
+
+ return stream;
+}
+
+#include "collectioncombo.moc"
diff --git a/kmrml/kmrml/collectioncombo.h b/kmrml/kmrml/collectioncombo.h
new file mode 100644
index 00000000..3ca67a64
--- /dev/null
+++ b/kmrml/kmrml/collectioncombo.h
@@ -0,0 +1,57 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef COLLECTIONCOMBO_H
+#define COLLECTIONCOMBO_H
+
+#include <kcombobox.h>
+
+#include "mrml_elements.h"
+
+namespace KMrml
+{
+
+ class CollectionCombo : public KComboBox
+ {
+ Q_OBJECT
+
+ public:
+ CollectionCombo( QWidget *parent, const char *name = 0 );
+ ~CollectionCombo();
+
+ void setCollections( const CollectionList * collections );
+ void setCurrent( const Collection& coll );
+
+ Collection current() const;
+
+ signals:
+ void selected( const Collection& );
+
+ private slots:
+ void slotActivated( const QString& );
+
+ private:
+ const CollectionList *m_collections;
+ };
+
+ QDataStream& operator<<( QDataStream& stream, const CollectionCombo& );
+ QDataStream& operator>>( QDataStream& stream, CollectionCombo& );
+
+}
+
+#endif // COLLECTIONCOMBO_H
diff --git a/kmrml/kmrml/kcontrol/Makefile.am b/kmrml/kmrml/kcontrol/Makefile.am
new file mode 100644
index 00000000..c1330cfd
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/Makefile.am
@@ -0,0 +1,25 @@
+LIB_KMRMLSTUFF = $(top_builddir)/kmrml/kmrml/lib/libkmrmlstuff.la
+
+kde_module_LTLIBRARIES = kcm_kmrml.la
+
+kcm_kmrml_la_SOURCES = kcmkmrml.cpp mainpage.cpp indexer.cpp serverconfigwidget.ui indexcleaner.cpp
+kcm_kmrml_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+kcm_kmrml_la_LIBADD = $(LIB_KMRMLSTUFF) $(LIB_KIO)
+INCLUDES= -I$(top_srcdir)/kmrml/kmrml/lib $(all_includes)
+
+kcm_kmrml_la_METASOURCES = AUTO
+
+noinst_HEADERS = kcmkmrml.h mainpage.h serverconfigwidget.h indexer.h indexcleaner.h
+
+xdg_apps_DATA = kcmkmrml.desktop
+
+#check_PROGRAMS = indextest
+#indextest_SOURCES = indextest.cpp indexer.cpp
+#indextest_LDADD = $(LIB_KMRMLSTUFF) $(LIB_KDECORE)
+#indextest_LDFLAGS = $(all_libraries)
+
+
+
+#pics_DATA = play.png
+#picsdir = $(kde_datadir)/kcontrol/pics
+
diff --git a/kmrml/kmrml/kcontrol/indexcleaner.cpp b/kmrml/kmrml/kcontrol/indexcleaner.cpp
new file mode 100644
index 00000000..5f5eea93
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/indexcleaner.cpp
@@ -0,0 +1,96 @@
+#include <kdebug.h>
+#include <kprocess.h>
+
+#include <kmrml_config.h>
+#include "indexcleaner.h"
+
+#include <kdeversion.h>
+#if KDE_VERSION < 306
+ #define QUOTE( x ) x
+#else
+ #define QUOTE( x ) KProcess::quote( x )
+#endif
+
+using namespace KMrmlConfig;
+
+IndexCleaner::IndexCleaner( const QStringList& dirs,
+ const KMrml::Config *config,
+ QObject *parent, const char *name )
+ : QObject( parent, name ),
+ m_dirs( dirs ),
+ m_config( config ),
+ m_process( 0L )
+{
+ m_stepSize = 100 / dirs.count();
+}
+
+IndexCleaner::~IndexCleaner()
+{
+ if ( m_process )
+ {
+ m_process->kill();
+ delete m_process;
+ m_process = 0L;
+ }
+}
+
+void IndexCleaner::start()
+{
+ startNext();
+}
+
+void IndexCleaner::slotExited( KProcess *proc )
+{
+ emit advance( m_stepSize );
+
+ if ( !proc->normalExit() )
+ kdWarning() << "Error removing old indexed directory" << endl;
+
+ m_process = 0L;
+
+ startNext();
+}
+
+void IndexCleaner::startNext()
+{
+ if ( m_dirs.isEmpty() )
+ {
+ emit advance( 100 );
+ emit finished();
+ return;
+ }
+
+#if KDE_VERSION < 306
+ m_process = new KShellProcess();
+#else
+ m_process = new KProcess();
+ m_process->setUseShell( true );
+#endif
+ connect( m_process, SIGNAL( processExited( KProcess * )),
+ SLOT( slotExited( KProcess * ) ));
+
+ QString cmd = m_config->removeCollectionCommandLine();
+
+ QString dir = m_dirs.first();
+ m_dirs.pop_front();
+
+ int index = cmd.find( "%d" );
+ if ( index != -1 )
+ cmd.replace( index, 2, QUOTE( dir ) );
+ else // no %d? What else can we do?
+ cmd.append( QString::fromLatin1(" ") + QUOTE( dir ) );
+
+ *m_process << cmd;
+
+ if ( !m_process->start() )
+ {
+ kdWarning() << "Error starting: " << cmd << endl;
+
+ delete m_process;
+ m_process = 0L;
+
+ startNext();
+ }
+}
+
+#include "indexcleaner.moc"
diff --git a/kmrml/kmrml/kcontrol/indexcleaner.h b/kmrml/kmrml/kcontrol/indexcleaner.h
new file mode 100644
index 00000000..0ddcaac4
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/indexcleaner.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+** $Id$
+**
+** Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+**
+****************************************************************************/
+
+#ifndef INDEXCLEANER_H
+#define INDEXCLEANER_H
+
+#include <qobject.h>
+#include <qstringlist.h>
+
+class KProcess;
+
+namespace KMrml
+{
+ class Config;
+}
+
+namespace KMrmlConfig
+{
+ class IndexCleaner : public QObject
+ {
+ Q_OBJECT
+
+ public:
+ IndexCleaner( const QStringList& dirs, const KMrml::Config *config,
+ QObject *parent = 0, const char *name = 0 );
+ ~IndexCleaner();
+
+ void start();
+
+ signals:
+ void advance( int value );
+ void finished();
+
+ private slots:
+ void slotExited( KProcess * );
+
+ private:
+ int m_stepSize;
+ void startNext();
+
+ QStringList m_dirs;
+ const KMrml::Config *m_config;
+ KProcess *m_process;
+ };
+
+}
+
+
+#endif // INDEXCLEANER_H
diff --git a/kmrml/kmrml/kcontrol/indexer.cpp b/kmrml/kmrml/kcontrol/indexer.cpp
new file mode 100644
index 00000000..a3bb6b7d
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/indexer.cpp
@@ -0,0 +1,190 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qfile.h>
+#include <qregexp.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kprocio.h>
+
+#include "indexer.h"
+
+#include <kdeversion.h>
+#if KDE_VERSION < 306
+ #define QUOTE( x ) x
+#else
+ #define QUOTE( x ) KProcess::quote( x )
+#endif
+
+using namespace KMrmlConfig;
+
+Indexer::Indexer( const KMrml::Config* config,
+ QObject *parent, const char *name )
+ : QObject( parent, name ),
+ m_config( config ),
+ m_dirCount( 0 )
+{
+ m_process = new KProcIO();
+#if KDE_VERSION >= 306
+ m_process->setUseShell( true );
+#endif
+ m_process->setEnvironment( "LC_ALL", "C" );
+ connect( m_process, SIGNAL( processExited( KProcess * )),
+ SLOT( processFinished( KProcess * )));
+ connect( m_process, SIGNAL( readReady( KProcIO * )),
+ SLOT( slotCanRead( KProcIO * )) );
+}
+
+Indexer::~Indexer()
+{
+ delete m_process;
+}
+
+void Indexer::startIndexing( const QStringList& dirs )
+{
+ if ( m_process->isRunning() )
+ return;
+
+ m_dirs = dirs;
+ m_dirCount = dirs.count();
+ processNext();
+}
+
+void Indexer::processFinished( KProcess *proc )
+{
+ // still more directories to index?
+ if ( !m_dirs.isEmpty() )
+ processNext();
+ else
+ {
+ if ( proc->normalExit() )
+ emit finished( proc->exitStatus() );
+ else
+ emit finished( -1000 );
+ }
+}
+
+
+void Indexer::processNext()
+{
+ m_currentDir = m_dirs.first();
+ m_dirs.pop_front();
+ while ( m_currentDir.endsWith( "/" ) )
+ m_currentDir.remove( m_currentDir.length() -1, 1 );
+
+ m_process->resetAll();
+
+ QString cmd = m_config->addCollectionCommandLine().simplifyWhiteSpace().stripWhiteSpace();
+
+ // in the commandline, replace %d with the directory to process and
+ // %t with the thumbnail dir
+ int index = cmd.find( "%d" ); // ### QFile::encodeName()?
+ if ( index != -1 )
+ cmd.replace( index, 2, QUOTE( m_currentDir ) );
+ index = cmd.find( "%t" );
+ if ( index != -1 )
+ cmd.replace( index, 2, QUOTE(m_currentDir + "_thumbnails") );
+
+// qDebug("****** command: %s", cmd.latin1());
+#if KDE_VERSION >= 306
+ *m_process << cmd;
+#else
+ QStringList params = QStringList::split( ' ', cmd );
+ QStringList::Iterator it = params.begin();
+ for ( ; it != params.end(); ++it )
+ *m_process << *it;
+#endif
+
+ emit progress( 0, i18n("<qt>Next Folder: <br><b>%1</b>").arg( m_currentDir ));
+ m_process->start();
+}
+
+void Indexer::slotCanRead( KProcIO *proc )
+{
+ static const QString& sprogress = KGlobal::staticQString("PROGRESS: ");
+ static const QString& r1 = /* PROGRESS: 1 of 6 done (15%) */
+ KGlobal::staticQString( "(\\d+) of (\\d+) done \\((\\d+)%\\)" );
+
+ QString line;
+ int bytes = -1;
+ while ( (bytes = proc->readln( line )) != -1 )
+ {
+ // examine the output.
+ // We're looking for lines like:
+ // PROGRESS: 1 of 6 done (15%)
+ // PROGRESS: 99%
+ // PROGRESS: 100%
+
+ if ( !line.startsWith( sprogress ) ) // uninteresting debug output
+ continue;
+ else // parse output
+ {
+ // cut off "PROGRESS: "
+ line = line.mid( sprogress.length() );
+ line = line.simplifyWhiteSpace().stripWhiteSpace();
+// qDebug("*** START LINE ***");
+// qDebug("%s", line.latin1());
+// qDebug("*** END LINE ***");
+
+ // case 1: image processing, below 99%
+ if ( line.at( line.length() -1 ) == ')' )
+ {
+ QRegExp regxp( r1 );
+ int pos = regxp.search( line );
+ if ( pos > -1 )
+ {
+ QString currentFile = regxp.cap( 1 );
+ QString numFiles = regxp.cap( 2 );
+ QString percent = regxp.cap( 3 );
+
+// qDebug( "current: %s, number: %s, percent: %s", currentFile.latin1(), numFiles.latin1(), percent.latin1());
+ bool ok = false;
+ int perc = percent.toInt( &ok );
+ if ( ok )
+ {
+ uint dirsLeft = m_dirs.count();
+ QString message = i18n( "<qt>Processing folder %1 of %2: <br><b>%3</b><br>File %4 of %5.</qt>").arg( m_dirCount - dirsLeft ).arg( m_dirCount).arg( m_currentDir ).arg( currentFile ).arg( numFiles );
+ emit progress( perc, message );
+ }
+ }
+ }
+
+
+ // case 2: file writing, 99% or done, 100%
+ else
+ {
+ QString percent = line.left( line.length() - 1 );
+
+ bool ok = false;
+ int number = percent.toInt( &ok );
+ if ( ok )
+ {
+ QString message = (number == 100) ?
+ i18n("Finished.") : i18n("Writing data...");
+ emit progress( number, message );
+ }
+ else
+ kdDebug() << "Error while parsing gift-add-collection.pl output" << endl;
+ }
+ }
+ }
+}
+
+#include "indexer.moc"
diff --git a/kmrml/kmrml/kcontrol/indexer.h b/kmrml/kmrml/kcontrol/indexer.h
new file mode 100644
index 00000000..97335a70
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/indexer.h
@@ -0,0 +1,68 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef INDEXER_H
+#define INDEXER_H
+
+#include <qobject.h>
+
+#include <kmrml_config.h>
+
+class KProcess;
+class KProcIO;
+
+namespace KMrmlConfig
+{
+ class Indexer : public QObject
+ {
+ Q_OBJECT
+
+ public:
+ Indexer( const KMrml::Config *config,
+ QObject *parent = 0L, const char *name = 0 );
+ ~Indexer();
+
+ void startIndexing( const QStringList& dirs );
+ void stop();
+
+ signals:
+ void progress( int percent, const QString& text );
+ void finished( int returnCode );
+
+
+ private slots:
+ void slotCanRead( KProcIO * );
+ void processFinished( KProcess * );
+
+ private:
+ void processNext();
+
+ KProcIO *m_process;
+ const KMrml::Config *m_config;
+
+ uint m_dirCount;
+ QStringList m_dirs;
+ QString m_currentDir;
+
+ };
+
+
+}
+
+
+#endif // INDEXER_H
diff --git a/kmrml/kmrml/kcontrol/indextest.cpp b/kmrml/kmrml/kcontrol/indextest.cpp
new file mode 100644
index 00000000..161ca798
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/indextest.cpp
@@ -0,0 +1,43 @@
+#include "indexer.h"
+#include <kmrml_config.h>
+#include "indextest.moc"
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+
+using namespace KMrmlConfig;
+
+IndexTest::IndexTest()
+{
+ KMrml::Config *config = new KMrml::Config( KGlobal::config() );
+ Indexer *indexer = new Indexer( *config, this );
+ connect( indexer, SIGNAL( finished( bool )), SLOT( slotFinished( bool )));
+ connect( indexer, SIGNAL( progress( int, const QString& )),
+ SLOT( slotProgress( int, const QString& )));
+
+ indexer->startIndexing( "/home/gis/testcoll" );
+}
+
+IndexTest::~IndexTest()
+{
+
+}
+
+void IndexTest::slotFinished( bool success )
+{
+ qDebug("##### FINISHED: %i", success );
+}
+
+void IndexTest::slotProgress( int percent, const QString& message )
+{
+ qDebug("--- progress: %i: %s", percent, message.latin1());
+}
+
+int main( int argc, char **argv )
+{
+ KApplication app( argc, argv, "indextest" );
+ IndexTest *test = new IndexTest();
+
+ return app.exec();
+}
diff --git a/kmrml/kmrml/kcontrol/indextest.h b/kmrml/kmrml/kcontrol/indextest.h
new file mode 100644
index 00000000..5f85f5f1
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/indextest.h
@@ -0,0 +1,26 @@
+/****************************************************************************
+** $Id$
+**
+** Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+**
+****************************************************************************/
+
+#ifndef INDEXTEST_H
+#define INDEXTEST_H
+
+class IndexTest : public QObject
+{
+ Q_OBJECT
+
+public:
+ IndexTest();
+ ~IndexTest();
+
+private slots:
+ void slotFinished( bool success );
+ void slotProgress( int percent, const QString& message );
+
+};
+
+
+#endif // INDEXTEST_H
diff --git a/kmrml/kmrml/kcontrol/kcmkmrml.cpp b/kmrml/kmrml/kcontrol/kcmkmrml.cpp
new file mode 100644
index 00000000..43e46b03
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/kcmkmrml.cpp
@@ -0,0 +1,146 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kgenericfactory.h>
+#include <kstandarddirs.h>
+#include <kurllabel.h>
+
+#include "kcmkmrml.h"
+#include <dcopclient.h>
+
+#include "mainpage.h"
+#include <version.h>
+
+using namespace KMrmlConfig;
+
+static const int COL_FILENAME = 1;
+
+typedef KGenericFactory<KCMKMrml, QWidget> MrmlFactory;
+K_EXPORT_COMPONENT_FACTORY( kcm_kmrml, MrmlFactory("kmrml") )
+
+KCMKMrml::KCMKMrml(QWidget *parent, const char *name, const QStringList & ):
+ KCModule(MrmlFactory::instance(), parent, name)
+{
+ KAboutData* ab = new KAboutData(
+ "kcmkmrml",
+ I18N_NOOP("KCMKMrml"),
+ KMRML_VERSION,
+ I18N_NOOP("Advanced Search Control Module"),
+ KAboutData::License_GPL,
+ I18N_NOOP( "Copyright 2002, Carsten Pfeiffer" ),
+ 0,
+ "http://devel-home.kde.org/~pfeiffer/kmrml/" );
+ ab->addAuthor( "Carsten Pfeiffer", 0, "pfeiffer@kde.org" );
+ setAboutData( ab );
+
+ QVBoxLayout *layout = new QVBoxLayout( this );
+ layout->setSpacing( KDialog::spacingHint() );
+ m_mainPage = new MainPage( this, "main page" );
+
+ layout->addWidget( m_mainPage );
+
+ connect( m_mainPage, SIGNAL( changed( bool ) ), SIGNAL( changed( bool )));
+
+ checkGiftInstallation();
+}
+
+KCMKMrml::~KCMKMrml()
+{
+}
+
+void KCMKMrml::checkGiftInstallation()
+{
+ QString giftExe = KGlobal::dirs()->findExe( "gift" );
+ QString giftAddCollectionExe = KGlobal::dirs()->findExe( "gift-add-collection.pl" );
+
+ if ( giftExe.isEmpty() || giftAddCollectionExe.isEmpty() )
+ {
+ QString errorMessage =
+ i18n("Cannot find executables \"gift\" and/or \"gift-add-collection.pl\" in the PATH.\n"
+ "Please install the \"GNU Image Finding Tool\".");
+ KMessageBox::error( this, errorMessage );
+ m_mainPage->hide();
+ QLabel *errorLabel = new QLabel( errorMessage, this );
+ errorLabel->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
+ KURLLabel *urlLabel = new KURLLabel( "http://www.gnu.org/software/gift", QString::null, this );
+ urlLabel->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+ connect( urlLabel, SIGNAL( leftClickedURL( const QString& )), kapp, SLOT( invokeBrowser( const QString& )) );
+ QLayout *l = layout();
+ l->addItem( new QSpacerItem( 0, 10, QSizePolicy::Minimum, QSizePolicy::Expanding ) );
+ l->add( errorLabel );
+ l->add( urlLabel );
+ l->addItem( new QSpacerItem( 0, 10, QSizePolicy::Minimum, QSizePolicy::Expanding ) );
+ errorLabel->show();
+ }
+ else
+ load();
+}
+
+void KCMKMrml::defaults()
+{
+ if (KMessageBox::warningContinueCancel(this,
+ i18n("Do you really want the configuration to be reset "
+ "to the defaults?"), i18n("Reset Configuration"), KStdGuiItem::cont())
+ != KMessageBox::Continue)
+ return;
+
+ m_mainPage->resetDefaults();
+
+ emit changed( true );
+}
+
+void KCMKMrml::load()
+{
+ m_mainPage->load();
+
+ emit changed( true );
+}
+
+void KCMKMrml::save()
+{
+ m_mainPage->save();
+
+ emit changed( false );
+}
+
+QString KCMKMrml::quickHelp() const
+{
+ return i18n("<h1>Image Index</h1>"
+ "KDE can make use of the GNU Image Finding Tool (GIFT) to "
+ "perform queries based not just on filenames, but on "
+ "file content."
+ "<p>For example, you can search for an image by giving an example "
+ "image that looks similar to the one you are looking for.</p>"
+ "<p>For this to work, your image directories need to be "
+ "indexed by, for example, the GIFT server.</p>"
+ "<p>Here you can configure the servers (you can also query "
+ "remote servers) and the directories to index.</p>"
+ );
+}
+
+#include "kcmkmrml.moc"
diff --git a/kmrml/kmrml/kcontrol/kcmkmrml.desktop b/kmrml/kmrml/kcontrol/kcmkmrml.desktop
new file mode 100644
index 00000000..d9dd1f02
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/kcmkmrml.desktop
@@ -0,0 +1,176 @@
+[Desktop Entry]
+Exec=kcmshell kcmkmrml
+Icon=folder_image
+Type=Application
+
+X-KDE-ModuleType=Library
+X-KDE-Library=kmrml
+
+Name=Image Index
+Name[ar]=فهرس الصور
+Name[bg]=Графичен индекс
+Name[br]=Meneger ar skeudenn
+Name[bs]=Indeks slika
+Name[ca]=Índex d'imatge
+Name[cs]=Rejstřík obrázků
+Name[cy]=Mynegai Delweddau
+Name[da]=Billedindeks
+Name[de]=Bildindex
+Name[el]=Ευρετήριο εικόνων
+Name[eo]=Bildindekso
+Name[es]=Índice de imágenes
+Name[et]=Pildiindeks
+Name[eu]=Irudiaren indizea
+Name[fa]=نمایۀ تصویر
+Name[fi]=Kuvahakemisto
+Name[fr]=Indexation des images
+Name[gl]=Índice imaxe
+Name[he]=אינדקס תמונות
+Name[hi]=छवि सूची
+Name[hu]=Képkereső
+Name[is]=Myndayfirlit
+Name[it]=Indice di immagini
+Name[ja]=画像インデックス
+Name[kk]=Кескіндер индексі
+Name[km]=លិបិក្រម​រូបភាព
+Name[lt]=Paveikslėlių rodyklė
+Name[ms]=Indeks Imej
+Name[nb]=Bildeindeks
+Name[nds]=Bildindex
+Name[ne]=छवि अनुक्रमणिका
+Name[nl]=Afbeeldingenindex
+Name[nn]=Biletindeks
+Name[nso]=Palo ya Ponagalo
+Name[pl]=Spis obrazków
+Name[pt]=Índice de Imagens
+Name[pt_BR]=Índice de Imagens
+Name[ro]=Index imagini
+Name[ru]=Индексирование изображений
+Name[se]=Govvaindeaksa
+Name[sk]=Katalóg obrázkov
+Name[sl]=Seznam slik
+Name[sr]=Индекс слика
+Name[sr@Latn]=Indeks slika
+Name[sv]=Bildindex
+Name[ta]=பிம்ப அட்டவணை
+Name[tg]=Индексатсия кардани тасвирот
+Name[th]=ดัชนีรูปภาพ
+Name[tr]=Resim İndeksi
+Name[uk]=Індекс зображень
+Name[uz]=Rasm indeksi
+Name[uz@cyrillic]=Расм индекси
+Name[ven]=Index ya tshifanyiso
+Name[wa]=Indecse des imådjes
+Name[xh]=Isalathisi Somfanekiso
+Name[zh_CN]=图像索引
+Name[zh_HK]=圖像索引
+Name[zh_TW]=影像索引
+Name[zu]=Isiqalo Sesithombe
+
+Comment=Configuration for using the GNU Image Finding Tool
+Comment[ar]=اعدادات لاستخدام أداة GNU للبحث عن الصور
+Comment[bg]=Настройване на програмата за индексиране и търсене на изображения
+Comment[bs]=Podešavanje za upotrebu GNU Alata za pronalaženje slika
+Comment[ca]=Configuració per a l'ús de l'eina de cerca d'imatges GNU
+Comment[cs]=Konfigurace používání nástroje GNU Image Finding Tool
+Comment[cy]=Ffurfweddiad am ddefnyddio'r Erfyn Canfod Delweddau GNU
+Comment[da]=Indstilling for brug af GNU Image Finding Tool
+Comment[de]=Einrichtung für die Benutzung des GNU Bildersuchwerkzeugs (GNU Image Finding Tool)
+Comment[el]=Ρύθμιση για τη χρήση του εργαλείου αναζήτησης εικόνων GIFT
+Comment[es]=Configuración para utilizar la herramienta de búsqueda de imágenes de GNU
+Comment[et]=Seadistused GNU pildileidmisrakenduse kasutamiseks
+Comment[eu]=GNU irudi aurkitzailea erabiltzeko konfigurazioa
+Comment[fa]=پیکربندی برای استفاده از ابزار یافتن تصویر GNU
+Comment[fi]=Asetukset GNU Image Finding Tool -ohjelman käyttöä varten
+Comment[fr]=Configuration pour l'utilisation du GNU Image Finding Tool
+Comment[gl]=Configuración para empregar a «GNU Image Finding Tool»
+Comment[he]=שינוי הגדרות כלי חיפוש התמונות של GNU
+Comment[hi]=ग्नू छवि खोज औज़ार को उपयोग करने के लिए कॉन्फ़िगरेशन
+Comment[hu]=A GIFT képkereső szolgáltatás beállításai
+Comment[is]=Stillingar til þess að nota GNU myndleitartólið
+Comment[it]=Configurazione della ricerca delle immagini
+Comment[ja]=GIFT (GNU Image Finding Tool) を使用するための設定
+Comment[kk]=GNU Image Finding Tool кескінді табу құралын пайдалану баптаулары
+Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ដើម្បី​ប្រើ​ឧបករណ៍​ស្វែងរក​រូបភាព​របស់ GNU
+Comment[lt]=GNU paveikslėlių paieškos įrankio konfigūracija
+Comment[ms]=Konfigurasi untuk mengguna Alat Carian Imej GNU
+Comment[nb]=Tilpass GNU bildesøkingsverktøy
+Comment[nds]=Inrichten för dat GNU-Bildsöökwarktüüch
+Comment[ne]=GNU छवि फेला पार्ने उपकरण प्रयोगका लागि कन्फिगरेसन
+Comment[nl]=Configuratie voor het gebruik van de GNU Image Finding Tool
+Comment[nn]=Oppsett av GNU Image Finding Tool
+Comment[pl]=Konfiguracja Gifta (narzędzia do szukania obrazków GNU)
+Comment[pt]=Configuração da Ferramenta de Procura de Imagens da GNU
+Comment[pt_BR]=Configuração para o uso da Ferramenta de Procura de Imagens GNU
+Comment[ro]=Configurare pentru GNU Image Finding Tool
+Comment[ru]=Настройка использования программы поиска изображений GNU Image Finding Tool
+Comment[se]=Heivet GNU Image Finding Tool
+Comment[sk]=Konfigurácia pre GNU Image Finding Tool
+Comment[sl]=Nastavitve za uporabo orodja GNU za iskanje slik
+Comment[sr]=Подешавање коришћења GNU-овог алата за тражење слика
+Comment[sr@Latn]=Podešavanje korišćenja GNU-ovog alata za traženje slika
+Comment[sv]=Inställning för att använda GNU:s bildsökverktyg
+Comment[ta]=GNU பிம்ப தேடுதல் கருவியை பயன்படுத்துவதற்கான அமைப்பு
+Comment[tg]=Танзимоти истифодабарии барномаиҷустуҷӯи тасвироти GNU Image Finding Tool
+Comment[tr]=GNU Resim Bulma Aracı yapılandırması
+Comment[uk]=Налаштування засобу пошуку зображень GNU
+Comment[ven]=Nzudzanyo yau shumisa tshishumiswa tshau toda tshifanyiso tsha GNU
+Comment[wa]=Apontiaedje po-z eployî l' usteye di cweraedje d' imådjes di GNU
+Comment[xh]=Uqwalaselo lokusebenzisa Isixhobo Sokufumana Umfanekiso we GNU
+Comment[zh_CN]=使用 GNU 图像查找工具的配置
+Comment[zh_HK]=GNU 圖像搜尋工具的設定
+Comment[zh_TW]= GNU 影像搜尋工具組態
+Comment[zu]=Inhlanganiselo yokusebenzisa Ithuluzi Lokuthola Isithombe se-GNU
+
+Keywords=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR
+Keywords[ar]=صور,بحث,استعلام,Find,Gift,kmrml,mrml,CBIR
+Keywords[bg]=изображения, търсене, заявка, картинка, картинки, снимки, Images, Search, Query, Find, Gift, kmrml, mrml, CBIR
+Keywords[bs]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,slike,pretraga,upit,nađi
+Keywords[ca]=Imatges,Cerca,Consulta,Busca,Gift,kmrml,mrml,CBIR
+Keywords[cs]=Obrázky,Hledat,Dotaz,Najít,Gift,kmrml,mrml,CBIR
+Keywords[cy]=Delweddau,Chwilio,Canfod,Gift,kmrml,mrml,CBIR
+Keywords[da]=Billeder,Søgning,Forespørgsel,Find,Gave,kmrml,mrml,CBIR
+Keywords[de]=Bilder,Suche,Anfrage,finden,Geschenk,kmrml,mrml,CBIR
+Keywords[el]=Εικόνες,Αναζήτηση,Ερώτηση,Αναζήτηση,Gift,kmrml,mrml,CBIR
+Keywords[es]=Imágenes,Búsqueda,Consulta,Buscar,Gift,kmrml,mrml,CBIR
+Keywords[et]=pildid,otsing,päring,leia,Gift,kmrml,mrml,CBIR
+Keywords[eu]=Irudiak,Bilaketa,Bilatu,Galdetu,Gift,kmrml,mrml,CBIR
+Keywords[fa]=تصاویر، جستجو، پرس‌و‌جو، یافتن، Gift،kmrml،mrml،CBIR
+Keywords[fi]=Kuvat,Haku,Etsi,Lahja,kmrml,mrml,CBIR
+Keywords[fr]=Images,Recherche,Requête,Chercher,Gift,kmrml,mrml,CBIR
+Keywords[gl]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR, imaxes, procura
+Keywords[he]=תמונות,חיפוש,שאילתה,Gift,kmrml,mrml,CBIR, Images,Search,Query,Find
+Keywords[hi]=छवि, खोज,ढूंढ,तलाश,उपहार,केएमआरएमएल,एमआरएमएल,सीबीआईआर
+Keywords[hu]=képek,keresés,lekérdezés,találat,Gift,kmrml,mrml,CBIR
+Keywords[it]=immagini,ricerca,trovare,Gift,kmrml,mrml,CBIR
+Keywords[ja]=画像,検索,クエリ,検索,Gift,kmrml,mrml,CBIR
+Keywords[km]=រូបភាព,ស្វែងរក,សួរ,រក,Gift,kmrml,mrml,CBIR
+Keywords[lt]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR, paveikslėliai,paieška,paklausimas
+Keywords[nb]=Bilder,Søk,Spørringer,Finn,Gift,kmrml,mrml,CBIR
+Keywords[nds]=Biller,Söök,Anfraag,söken,Gaav,kmrml,mrml,CBIR
+Keywords[nl]=illustraties,figuren,figuur,afbeeldingen,plaatjes,zoeken,find,gift,kmrml,mrml,CBIR,images
+Keywords[nn]=bilete,søk,spørjing,finn,gåve,kmrml,mrml,CBIR
+Keywords[nso]=Diponagalo,Nyaka,Kgokgonego,Hwetsa,Mpho,kmrml,mrml,CBIR
+Keywords[pl]=Obrazki,Szukanie,Zapytanie,Szukaj,Gift,kmrml,mrml,CBIR
+Keywords[pt]=Imagens,Procurar,Pesquisar,Encontrar,Prenda,kmrml,mrml,CBIR
+Keywords[pt_BR]=Imagens,Busca,Consulta,Procurar,Presente,kmrml,mrml,CBIR
+Keywords[ro]=imagini,căutare,caută,interogare,găseşte,dar,kmrml,mrml,CBIR
+Keywords[ru]=изображения,поиск,запрос,kmrml,mrml,CBIR
+Keywords[sk]=Obrázky,Hľadanie,Dotazy,Nájsť,kmrml,mrml,CBIR
+Keywords[sl]=slike,iskanje,povpraševanje,išči,najdi,gift,kmrml,mrml,CBIR
+Keywords[sr]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,слике,тражи,упит,нађи,поклон
+Keywords[sr@Latn]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,slike,traži,upit,nađi,poklon
+Keywords[sv]=Bilder,Sök,Förfrågan,Hitta,Gift,kmrml,mrml,CBIR
+Keywords[ta]=பிம்பங்கள், தேடு, கேள்வி, கண்டுபிடி,பரிசு,kmrml,mrml,CBIR
+Keywords[tg]=тасвирот,ҷустуҷӯӣ,дархост,kmrml,mrml,CBIR
+Keywords[tr]=Resimler,Ara,Arama,kmrml,mrml,CBIR
+Keywords[uk]=зображення,пошук,запит,знайти,подарунок,kmrml,mrml,CBIR
+Keywords[ven]=Zwifanyiso,Toda,Mbudziso,Wana,Mpho,kmrml,mrml,CBIR
+Keywords[wa]=Imådjes,Cweri,Cweraedje,Trover,Gift,kmrml,mrml,CBIR
+Keywords[xh]=Imifanekiso,Uphendlo,Ubuzo,fumana,Isiphiwo,kmrml,mrml,CBIR
+Keywords[zh_CN]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,图像,搜索,查询,查找,礼物
+Keywords[zh_HK]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,圖像,搜尋,查詢,尋找
+Keywords[zh_TW]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,影像,搜尋,查詢,尋找
+Keywords[zu]=Izithombe,Funa,Buza,Thola,Isipho,kmrml,mrml,CBIR
+
+Categories=Qt;KDE;Settings;X-KDE-settings-system;
diff --git a/kmrml/kmrml/kcontrol/kcmkmrml.h b/kmrml/kmrml/kcontrol/kcmkmrml.h
new file mode 100644
index 00000000..b0bb2443
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/kcmkmrml.h
@@ -0,0 +1,52 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCMKMRML_H
+#define KCMKMRML_H
+
+#include <kcmodule.h>
+
+class KAboutData;
+class KURLRequester;
+
+namespace KMrmlConfig
+{
+ class MainPage;
+
+ class KCMKMrml : public KCModule
+ {
+ Q_OBJECT
+
+ public:
+ KCMKMrml(QWidget *parent, const char *name, const QStringList &);
+ virtual ~KCMKMrml();
+
+ virtual void defaults();
+ virtual void load();
+ virtual void save();
+ virtual QString quickHelp() const;
+
+ private:
+ void checkGiftInstallation();
+
+ MainPage *m_mainPage;
+ };
+
+}
+
+#endif
diff --git a/kmrml/kmrml/kcontrol/mainpage.cpp b/kmrml/kmrml/kcontrol/mainpage.cpp
new file mode 100644
index 00000000..514b9cf6
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/mainpage.cpp
@@ -0,0 +1,501 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qsizepolicy.h>
+#include <qtooltip.h>
+#include <qwidget.h>
+#include <qvgroupbox.h>
+
+#include <kcombobox.h>
+#include <kdialog.h>
+#include <keditlistbox.h>
+#include <kglobalsettings.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <knuminput.h>
+#include <kprogress.h>
+#include <kurlrequester.h>
+
+#include <kdeversion.h>
+#include <kdebug.h>
+#include <kio/slaveconfig.h>
+#include <kio/ioslave_defaults.h> // MAX_PORT_VALUE
+
+#include "serverconfigwidget.h"
+#include "mainpage.h"
+#include "indexer.h"
+#include "indexcleaner.h"
+
+#include <limits.h>
+#include <string.h>
+
+using namespace KMrmlConfig;
+
+
+MainPage::MainPage( QWidget *parent, const char *name )
+ : QVBox( parent, name ),
+ m_indexer( 0L ),
+ m_indexCleaner( 0L ),
+ m_progressDialog( 0L ),
+ m_performIndexing( false ),
+ m_locked( false )
+{
+ m_config = new KMrml::Config();
+ setSpacing( KDialog::spacingHint() );
+
+ QVGroupBox *gBox = new QVGroupBox( i18n("Indexing Server Configuration"),
+ this );
+ m_serverWidget = new ServerConfigWidget( gBox, "server config widget" );
+ QString tip = i18n("Hostname of the Indexing Server");
+ QToolTip::add( m_serverWidget->m_hostLabel, tip );
+ QToolTip::add( m_serverWidget->m_hostCombo, tip );
+
+ m_serverWidget->m_portInput->setRange( 0, MAX_PORT_VALUE );
+
+#if KDE_VERSION >= 306
+ KURLRequester *requester = new KURLRequester( this, "dir requester" );
+ requester->setMode( KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly );
+ requester->setURL( KGlobalSettings::documentPath() );
+ connect( requester, SIGNAL( openFileDialog( KURLRequester * )),
+ SLOT( slotRequesterClicked( KURLRequester * )));
+
+ m_listBox = new KEditListBox( i18n("Folders to Be Indexed" ),
+ requester->customEditor(), this, "listbox",
+ false,
+ KEditListBox::Add | KEditListBox::Remove );
+#else
+ m_listBox = new KEditListBox( i18n("Folders to Be Indexed" ),
+ this, "listbox", false,
+ KEditListBox::Add | KEditListBox::Remove );
+#endif
+
+ connect( m_listBox, SIGNAL( changed() ), SLOT( slotDirectoriesChanged() ));
+ connect( m_serverWidget->m_hostCombo, SIGNAL( textChanged(const QString&)),
+ SLOT( slotHostChanged() ));
+ connect( m_serverWidget->m_portInput, SIGNAL( valueChanged( int )),
+ SLOT( slotPortChanged( int ) ));
+ connect ( m_serverWidget->m_useAuth, SIGNAL( toggled(bool) ),
+ SLOT( slotUseAuthChanged( bool ) ));
+ connect( m_serverWidget->m_userEdit, SIGNAL( textChanged( const QString&)),
+ SLOT( slotUserChanged( const QString& ) ));
+ connect( m_serverWidget->m_passEdit, SIGNAL( textChanged( const QString&)),
+ SLOT( slotPassChanged( const QString& ) ));
+
+ connect( m_serverWidget->m_addButton, SIGNAL( clicked() ),
+ SLOT( slotAddClicked() ));
+ connect( m_serverWidget->m_removeButton, SIGNAL( clicked() ),
+ SLOT( slotRemoveClicked() ));
+
+ connect( m_serverWidget->m_hostCombo, SIGNAL( activated( const QString& )),
+ SLOT( slotHostActivated( const QString& )));
+ connect( m_serverWidget->m_hostCombo, SIGNAL( returnPressed() ),
+ SLOT( slotAddClicked() ));
+
+ connect( m_serverWidget->m_autoPort, SIGNAL( toggled( bool ) ),
+ SLOT( slotAutoPortChanged( bool ) ));
+
+ m_serverWidget->m_hostCombo->setTrapReturnKey( true );
+ m_serverWidget->m_hostCombo->setFocus();
+}
+
+MainPage::~MainPage()
+{
+ delete m_config;
+}
+
+void MainPage::resetDefaults()
+{
+ blockSignals( true );
+
+ initFromSettings( KMrml::ServerSettings::defaults() );
+
+ m_serverWidget->m_hostCombo->clear();
+ m_serverWidget->m_hostCombo->insertItem( m_settings.host );
+
+ m_listBox->clear();
+
+ // slotHostChanged(); not necessary, will be called by Qt signals
+ slotUseAuthChanged( m_serverWidget->m_useAuth->isChecked() );
+
+ blockSignals( false );
+}
+
+void MainPage::load()
+{
+ blockSignals( true );
+
+ initFromSettings( m_config->defaultSettings() );
+
+ m_serverWidget->m_hostCombo->clear();
+ m_serverWidget->m_hostCombo->insertStringList( m_config->hosts() );
+ m_serverWidget->m_hostCombo->setCurrentItem( m_settings.host );
+
+ m_listBox->clear();
+ m_listBox->insertStringList( m_config->indexableDirectories() );
+
+ // slotHostChanged(); not necessary, will be called by Qt signals
+ slotUseAuthChanged( m_serverWidget->m_useAuth->isChecked() );
+
+ blockSignals( false );
+}
+
+void MainPage::save()
+{
+ m_config->addSettings( m_settings );
+ m_config->setDefaultHost( m_settings.host );
+
+ QStringList indexDirs = m_listBox->items();
+ QStringList oldIndexDirs = m_config->indexableDirectories();
+ QStringList removedDirs = difference( oldIndexDirs, indexDirs );
+
+ m_config->setIndexableDirectories( indexDirs );
+ if ( indexDirs.isEmpty() )
+ KMessageBox::information( this,
+ i18n("You did not specify any folders to "
+ "be indexed. This means you will be "
+ "unable to perform queries on your "
+ "computer."),
+ "kcmkmrml_no_directories_specified" );
+
+ if ( m_config->sync() )
+ KIO::SlaveConfig::self()->reset();
+
+ processIndexDirs( removedDirs );
+}
+
+QStringList MainPage::difference( const QStringList& oldIndexDirs,
+ const QStringList& newIndexDirs ) const
+{
+ QStringList result;
+
+ QString slash = QString::fromLatin1("/");
+ QStringList::ConstIterator oldIt = oldIndexDirs.begin();
+ QString oldDir, newDir;
+
+ for ( ; oldIt != oldIndexDirs.end(); oldIt++ )
+ {
+ bool removed = true;
+ oldDir = *oldIt;
+
+ while ( oldDir.endsWith( slash ) ) // remove slashes
+ oldDir.remove( oldDir.length() - 1, 1 );
+
+ QStringList::ConstIterator newIt = newIndexDirs.begin();
+ for ( ; newIt != newIndexDirs.end(); newIt++ )
+ {
+ newDir = *newIt;
+ while ( newDir.endsWith( slash ) ) // remove slashes
+ newDir.remove( newDir.length() - 1, 1 );
+
+ if ( oldDir == newDir )
+ {
+ removed = false;
+ break;
+ }
+ }
+
+ if ( removed )
+ result.append( *oldIt ); // not oldDir -- maybe gift needs slashes
+ }
+
+ return result;
+}
+
+void MainPage::initFromSettings( const KMrml::ServerSettings& settings )
+{
+ m_settings = settings;
+
+ m_locked = true;
+
+ m_serverWidget->m_portInput->setValue( settings.configuredPort );
+ m_serverWidget->m_autoPort->setChecked( settings.autoPort );
+ m_serverWidget->m_useAuth->setChecked( settings.useAuth );
+ m_serverWidget->m_userEdit->setText( settings.user );
+ m_serverWidget->m_passEdit->setText( settings.pass );
+
+ m_locked = false;
+}
+
+void MainPage::slotHostActivated( const QString& host )
+{
+ // implicitly save the current settings when another host was chosen
+ m_config->addSettings( m_settings );
+
+ initFromSettings( m_config->settingsForHost( host ) );
+}
+
+void MainPage::slotHostChanged()
+{
+ QString host = m_serverWidget->m_hostCombo->currentText();
+ m_listBox->setEnabled( (host == "localhost") );
+
+ KMrml::ServerSettings settings = m_config->settingsForHost( host );
+ enableWidgetsFor( settings );
+}
+
+void MainPage::slotUseAuthChanged( bool enable )
+{
+ m_settings.useAuth = enable;
+ m_serverWidget->m_userEdit->setEnabled( enable );
+ m_serverWidget->m_passEdit->setEnabled( enable );
+
+ if ( enable )
+ m_serverWidget->m_userEdit->setFocus();
+
+ if ( !m_locked )
+ changed();
+}
+
+void MainPage::slotUserChanged( const QString& user )
+{
+ if ( m_locked )
+ return;
+
+ m_settings.user = user;
+ changed();
+}
+
+void MainPage::slotPassChanged( const QString& pass )
+{
+ if ( m_locked )
+ return;
+
+ m_settings.pass = pass;
+ changed();
+}
+
+void MainPage::slotPortChanged( int port )
+{
+ if ( m_locked )
+ return;
+
+ m_settings.configuredPort = (unsigned short int) port;
+ changed();
+}
+
+void MainPage::slotAutoPortChanged( bool on )
+{
+ if ( m_locked )
+ return;
+
+ m_settings.autoPort = on;
+ m_serverWidget->m_portInput->setEnabled( !on );
+ changed();
+}
+
+void MainPage::slotRequesterClicked( KURLRequester *requester )
+{
+ static bool init = true;
+ if ( !init )
+ return;
+
+ init = false;
+
+ requester->setCaption(i18n("Select Folder You Want to Index"));
+}
+
+void MainPage::slotAddClicked()
+{
+ QString host = m_serverWidget->m_hostCombo->currentText();
+ m_settings.host = host;
+
+ m_config->addSettings( m_settings );
+ m_serverWidget->m_hostCombo->insertItem( host );
+ m_serverWidget->m_hostCombo->setCurrentItem( host );
+
+ enableWidgetsFor( m_settings );
+}
+
+void MainPage::slotRemoveClicked()
+{
+ QString host = m_serverWidget->m_hostCombo->currentText();
+ if ( host.isEmpty() ) // should never happen
+ return;
+
+ m_config->removeSettings( host );
+ m_serverWidget->m_hostCombo->removeItem( m_serverWidget->m_hostCombo->currentItem() );
+ m_serverWidget->m_hostCombo->setCurrentItem( 0 );
+
+ host = m_serverWidget->m_hostCombo->currentText();
+ initFromSettings( m_config->settingsForHost( host ) );
+}
+
+void MainPage::enableWidgetsFor( const KMrml::ServerSettings& settings )
+{
+ QString host = settings.host;
+ bool enableWidgets = (m_config->hosts().findIndex( host ) > -1);
+ m_serverWidget->m_addButton->setEnabled(!enableWidgets && !host.isEmpty());
+ m_serverWidget->m_removeButton->setEnabled( enableWidgets &&
+ !host.isEmpty() &&
+ host != "localhost" );
+
+ m_serverWidget->m_autoPort->setEnabled( host == "localhost" );
+ bool portEnable = enableWidgets && (settings.autoPort ||
+ !m_serverWidget->m_autoPort->isEnabled());
+ m_serverWidget->m_portLabel->setEnabled( portEnable && !m_serverWidget->m_autoPort->isChecked());
+ m_serverWidget->m_portInput->setEnabled( portEnable && !m_serverWidget->m_autoPort->isChecked());
+
+ m_serverWidget->m_useAuth->setEnabled( enableWidgets );
+ m_serverWidget->m_userLabel->setEnabled( enableWidgets );
+ m_serverWidget->m_passLabel->setEnabled( enableWidgets );
+ m_serverWidget->m_userEdit->setEnabled( enableWidgets );
+ m_serverWidget->m_passEdit->setEnabled( enableWidgets );
+
+ bool useAuth = m_serverWidget->m_useAuth->isChecked();
+ m_serverWidget->m_userEdit->setEnabled( useAuth );
+ m_serverWidget->m_passEdit->setEnabled( useAuth );
+}
+
+void MainPage::slotDirectoriesChanged()
+{
+ m_performIndexing = true;
+ changed();
+}
+
+void MainPage::processIndexDirs( const QStringList& removeDirs )
+{
+ // ### how to remove indexed directories?
+ if ( !m_performIndexing ||
+ (removeDirs.isEmpty() && m_config->indexableDirectories().isEmpty()) )
+ return;
+
+ delete m_progressDialog;
+ delete m_indexCleaner;
+ m_indexCleaner = 0L;
+ delete m_indexer;
+ m_indexer = 0L;
+
+ m_progressDialog = new KProgressDialog( this, "indexing dialog",
+ i18n("Removing old Index Files"),
+ i18n("Processing..."),
+ true );
+ m_progressDialog->setAutoClose( false );
+ m_progressDialog->setMinimumWidth( 300 );
+ connect( m_progressDialog, SIGNAL( cancelClicked() ),
+ SLOT( slotCancelIndexing() ));
+
+ // argh -- don't automatically show the dialog
+ m_progressDialog->setMinimumDuration( INT_MAX );
+
+ if ( !removeDirs.isEmpty() )
+ {
+ m_indexCleaner = new IndexCleaner( removeDirs, m_config, this );
+ connect( m_indexCleaner, SIGNAL( advance( int ) ),
+ m_progressDialog->progressBar(), SLOT( advance( int ) ));
+ connect( m_indexCleaner, SIGNAL( finished() ),
+ SLOT( slotMaybeIndex() ) );
+ m_indexCleaner->start();
+ }
+ else
+ {
+ slotMaybeIndex();
+ }
+ if ( m_progressDialog )
+ m_progressDialog->exec();
+}
+
+void MainPage::slotMaybeIndex()
+{
+ delete m_indexCleaner; // Stop in the name of the law!
+ m_indexCleaner = 0L;
+
+ m_progressDialog->setLabel( i18n("Finished.") );
+
+ if ( m_config->indexableDirectories().isEmpty() )
+ return;
+
+ if ( KMessageBox::questionYesNo( this,
+ i18n("The settings have been saved. Now, "
+ "the configured directories need to "
+ "be indexed. This may take a while. "
+ "Do you want to do this now?"),
+ i18n("Start Indexing Now?"),
+ i18n("Index"), i18n("Do Not Index"),
+ "ask_startIndexing"
+ ) != KMessageBox::Yes )
+ return;
+ m_progressDialog->setCaption( i18n("Indexing Folders") );
+ m_progressDialog->setLabel( i18n("Processing...") );
+ m_progressDialog->progressBar()->setProgress( 0 );
+
+ // do the indexing
+ m_indexer = new Indexer( m_config, this, "Indexer" );
+ connect( m_indexer, SIGNAL( progress( int, const QString& )),
+ SLOT( slotIndexingProgress( int, const QString& ) ));
+ connect( m_indexer, SIGNAL( finished( int )),
+ SLOT( slotIndexingFinished( int ) ));
+ m_indexer->startIndexing( m_config->indexableDirectories() );
+}
+
+
+void MainPage::slotIndexingProgress( int percent, const QString& message )
+{
+ m_progressDialog->progressBar()->setValue( percent );
+ m_progressDialog->setLabel( message );
+}
+
+void MainPage::slotIndexingFinished( int returnCode )
+{
+ if ( returnCode != 0 )
+ {
+ QString syserr;
+ if ( returnCode == 127 )
+ syserr = i18n("Is the \"GNU Image Finding Tool\" properly installed?");
+ else
+ {
+ char *err = strerror( returnCode );
+ if ( err )
+ syserr = QString::fromLocal8Bit( err );
+ else
+ syserr = i18n("Unknown error: %1").arg( returnCode );
+ }
+
+ KMessageBox::detailedError( this, i18n("An error occurred during indexing. The index might be invalid."),
+ syserr, i18n("Indexing Aborted") );
+ }
+ else
+ m_performIndexing = false;
+
+ delete m_indexer;
+ m_indexer = 0L;
+ if ( m_progressDialog )
+ {
+ m_progressDialog->deleteLater();
+ m_progressDialog = 0L;
+ }
+}
+
+void MainPage::slotCancelIndexing()
+{
+ delete m_indexCleaner;
+ m_indexCleaner = 0L;
+
+ delete m_indexer;
+ m_indexer = 0L;
+ if ( m_progressDialog )
+ {
+ m_progressDialog->deleteLater();
+ m_progressDialog = 0L;
+ }
+}
+
+
+#include "mainpage.moc"
diff --git a/kmrml/kmrml/kcontrol/mainpage.h b/kmrml/kmrml/kcontrol/mainpage.h
new file mode 100644
index 00000000..e91b4168
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/mainpage.h
@@ -0,0 +1,109 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MAINPAGE_H
+#define MAINPAGE_H
+
+#include <qvbox.h>
+
+#include <kmrml_config.h>
+
+class QCheckBox;
+class KComboBox;
+class KEditListBox;
+class KIntNumInput;
+class KLineEdit;
+class KProgressDialog;
+class KURLRequester;
+
+namespace KMrml
+{
+ class Config;
+}
+
+class ServerConfigWidget;
+
+namespace KMrmlConfig
+{
+ class Indexer;
+ class IndexCleaner;
+
+ class MainPage : public QVBox
+ {
+ Q_OBJECT
+
+ public:
+ MainPage( QWidget *parent, const char *name );
+ ~MainPage();
+
+ void resetDefaults();
+ void load();
+ void save();
+
+ signals:
+ void changed( bool );
+
+ private slots:
+ void changed() { emit changed( true ); }
+ void slotRequesterClicked( KURLRequester * );
+ void slotHostChanged();
+ void slotUseAuthChanged( bool );
+ void slotUserChanged( const QString& );
+ void slotPassChanged( const QString& );
+ void slotPortChanged( int );
+ void slotAutoPortChanged( bool );
+
+ void slotAddClicked();
+ void slotRemoveClicked();
+
+ void slotHostActivated( const QString& );
+
+ void slotDirectoriesChanged();
+
+ void slotMaybeIndex();
+ void slotIndexingProgress( int percent, const QString& message );
+ void slotIndexingFinished( int returnCode );
+ void slotCancelIndexing();
+
+
+ private:
+ void enableWidgetsFor( const KMrml::ServerSettings& settings );
+ void initFromSettings( const KMrml::ServerSettings& settings );
+
+ void processIndexDirs( const QStringList& removedDirs );
+
+ QStringList difference( const QStringList& oldIndexDirs,
+ const QStringList& newIndexDirs ) const;
+
+ ServerConfigWidget *m_serverWidget;
+ KEditListBox *m_listBox;
+ KMrml::Config *m_config;
+ KMrmlConfig::Indexer *m_indexer;
+ KMrmlConfig::IndexCleaner *m_indexCleaner;
+ KProgressDialog *m_progressDialog;
+
+ KMrml::ServerSettings m_settings;
+ bool m_performIndexing;
+ bool m_locked;
+ };
+
+}
+
+
+
+#endif // MAINPAGE_H
diff --git a/kmrml/kmrml/kcontrol/serverconfigwidget.ui b/kmrml/kmrml/kcontrol/serverconfigwidget.ui
new file mode 100644
index 00000000..e0a08007
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/serverconfigwidget.ui
@@ -0,0 +1,272 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>ServerConfigWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ServerConfigWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>455</width>
+ <height>321</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout7</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>Layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KComboBox">
+ <property name="name">
+ <cstring>m_hostCombo</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_addButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Add</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_removeButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="1">
+ <property name="name">
+ <cstring>Layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>m_portInput</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>TCP/IP Port Number of the Indexing Server</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_autoPort</cstring>
+ </property>
+ <property name="text">
+ <string>Au&amp;to</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Tries to automatically determine the port. This works only for local servers.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>200</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>m_hostLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Ho&amp;stname:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_hostCombo</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>m_portLabel</cstring>
+ </property>
+ <property name="text">
+ <string>P&amp;ort:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_portInput</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_useAuth</cstring>
+ </property>
+ <property name="text">
+ <string>Per&amp;form authentication</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout6</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>m_userLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Username:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_userEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_passEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>m_passLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Password:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_passEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_userEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<tabstops>
+ <tabstop>m_hostCombo</tabstop>
+ <tabstop>m_addButton</tabstop>
+ <tabstop>m_removeButton</tabstop>
+ <tabstop>m_portInput</tabstop>
+ <tabstop>m_useAuth</tabstop>
+ <tabstop>m_userEdit</tabstop>
+ <tabstop>m_passEdit</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmrml/kmrml/lib/Makefile.am b/kmrml/kmrml/lib/Makefile.am
new file mode 100644
index 00000000..4201f04f
--- /dev/null
+++ b/kmrml/kmrml/lib/Makefile.am
@@ -0,0 +1,11 @@
+noinst_LTLIBRARIES = libkmrmlstuff.la
+libkmrmlstuff_la_SOURCES = kmrml_config.cpp mrml_shared.cpp mrml_utils.cpp\
+watcher_stub.cpp
+noinst_HEADERS = kmrml_config.h mrml_shared.h mrml_utils.h watcher_stub.h
+
+METASOURCES = AUTO
+
+libkmrmlstuff_la_LDFLAGS = $(all_libraries) -no-undefined
+libkmrmlstuff_la_LIBADD = $(LIB_KDECORE)
+
+INCLUDES = -I$(top_srcdir) $(all_includes)
diff --git a/kmrml/kmrml/lib/kmrml_config.cpp b/kmrml/kmrml/lib/kmrml_config.cpp
new file mode 100644
index 00000000..a88e8404
--- /dev/null
+++ b/kmrml/kmrml/lib/kmrml_config.cpp
@@ -0,0 +1,339 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qtextcodec.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+
+#include "kmrml_config.h"
+
+#include <kdeversion.h>
+#if KDE_VERSION < 307
+ #define QUOTE( x ) x
+#else
+ #define QUOTE( x ) KProcess::quote( x )
+#endif
+
+using namespace KMrml;
+
+// #define DEFAULT_ADDCOLLECTION_CMD "gift-add-collection.pl --thumbnail-dir=%t --local-encoding %d"
+#define DEFAULT_ADDCOLLECTION_CMD "gift-add-collection.pl --gift-home=%h --thumbnail-dir=%t --local-encoding=%e %d"
+#define DEFAULT_REMOVECOLLECTION_CMD "gift-add-collection.pl --gift-home=%h --local-encoding=%e --remove-collection %d"
+
+#define DEFAULT_MRMLD_CMD "gift --port %p --datadir %d"
+#define DEFAULT_MRMLD_CMD_AUTOPORT "gift --datadir %d"
+
+#define CONFIG_GROUP "MRML Settings"
+#define DEFAULT_HOST "localhost"
+#define DEFAULT_USER "kmrml"
+#define DEFAULT_PASS "none"
+#define DEFAULT_AUTH false
+#define DEFAULT_AUTOPORT true
+const int DEFAULT_PORT = 12789;
+
+Config::Config()
+{
+ m_ownConfig = new KConfig( "kio_mrmlrc", false, false );
+ m_config = m_ownConfig;
+
+ init();
+}
+
+Config::Config( KConfig *config )
+ : m_config( config ),
+ m_ownConfig( 0L )
+{
+ init();
+}
+
+Config::~Config()
+{
+ delete m_ownConfig;
+}
+
+void Config::init()
+{
+ m_config->setGroup( CONFIG_GROUP );
+ m_defaultHost = m_config->readEntry( "Default Host" );
+ if ( m_defaultHost.isEmpty() )
+ m_defaultHost = DEFAULT_HOST;
+
+ m_hostList = m_config->readListEntry( "Host List" );
+ if ( m_hostList.isEmpty() )
+ m_hostList.append( DEFAULT_HOST );
+
+ m_serverStartedIndividually =
+ m_config->readBoolEntry( "ServerStartedIndividually", false );
+}
+
+bool Config::sync()
+{
+ bool notifySlaves = m_config->isDirty();
+ m_config->sync();
+ return notifySlaves;
+
+ // This moved to kcontrol/MainPage::save() so we don't have to link against
+ // KIO and need a full KApplication instance to work (so that the tiny
+ // mrmlsearch binary can also use this class)
+ // tell the ioslaves about the new configuration
+// if ( notifySlaves )
+// KIO::SlaveConfig::self()->reset();
+}
+
+void Config::setDefaultHost( const QString& host )
+{
+ m_defaultHost = host.isEmpty() ?
+ QString::fromLatin1(DEFAULT_HOST) : host;
+
+ m_config->setGroup( CONFIG_GROUP );
+ m_config->writeEntry( "Default Host", m_defaultHost );
+}
+
+ServerSettings Config::settingsForLocalHost() const
+{
+ return settingsForHost( "localhost" );
+}
+
+ServerSettings Config::settingsForHost( const QString& host ) const
+{
+ KConfigGroup config( m_config, settingsGroup( host ) );
+ ServerSettings settings;
+
+ settings.host = host;
+ settings.configuredPort = config.readUnsignedNumEntry( "Port",
+ DEFAULT_PORT );
+ settings.autoPort = (host == "localhost") &&
+ config.readBoolEntry("Automatically determine Port",
+ DEFAULT_AUTOPORT );
+ settings.user = config.readEntry( "Username", DEFAULT_USER );
+ settings.pass = config.readEntry( "Password", DEFAULT_PASS );
+ settings.useAuth = config.readBoolEntry( "Perform Authentication",
+ DEFAULT_AUTH );
+
+ return settings;
+}
+
+void Config::addSettings( const ServerSettings& settings )
+{
+ QString host = settings.host;
+ if ( m_hostList.find( host ) == m_hostList.end() )
+ m_hostList.append( host );
+
+ m_config->setGroup( CONFIG_GROUP );
+ m_config->writeEntry( "Host List", m_hostList );
+
+ m_config->setGroup( settingsGroup( host ) );
+ m_config->writeEntry( "Host", host );
+ m_config->writeEntry( "Port", settings.configuredPort );
+ m_config->writeEntry( "Automatically determine Port", settings.autoPort );
+ m_config->writeEntry( "Username", settings.user );
+ m_config->writeEntry( "Password", settings.pass );
+ m_config->writeEntry( "Perform Authentication", settings.useAuth );
+}
+
+bool Config::removeSettings( const QString& host )
+{
+ bool success = m_config->deleteGroup( settingsGroup( host ) );
+ if ( success )
+ {
+ m_hostList.remove( host );
+ m_config->setGroup( CONFIG_GROUP );
+ }
+
+ return success;
+}
+
+QStringList Config::indexableDirectories() const
+{
+ m_config->setGroup( CONFIG_GROUP );
+ return m_config->readListEntry( "Indexable Directories" );
+}
+
+void Config::setIndexableDirectories( const QStringList& dirs )
+{
+ m_config->setGroup( CONFIG_GROUP );
+ m_config->writeEntry( "Indexable Directories", dirs );
+}
+
+QString Config::addCollectionCommandLine() const
+{
+ m_config->setGroup( CONFIG_GROUP );
+ QString cmd = m_config->readEntry( "AddCollection Commandline",
+ DEFAULT_ADDCOLLECTION_CMD );
+ int index = cmd.find( "%h" );
+ if ( index != -1 )
+ cmd.replace( index, 2, QUOTE( mrmldDataDir() ) );
+
+ index = cmd.find( "%e" );
+ if ( index != -1 )
+ cmd.replace( index, 2, QTextCodec::codecForLocale()->mimeName() );
+
+ return cmd;
+}
+
+void Config::setAddCollectionCommandLine( const QString& cmd )
+{
+ m_config->setGroup( CONFIG_GROUP );
+ m_config->writeEntry( "AddCollection Commandline", cmd );
+}
+
+QString Config::removeCollectionCommandLine() const
+{
+ m_config->setGroup( CONFIG_GROUP );
+ QString cmd = m_config->readEntry( "RemoveCollection Commandline",
+ DEFAULT_REMOVECOLLECTION_CMD );
+ int index = cmd.find( "%h" );
+ if ( index != -1 )
+ cmd.replace( index, 2, QUOTE( mrmldDataDir() ) );
+
+ index = cmd.find( "%e" );
+ if ( index != -1 )
+ cmd.replace( index, 2, QTextCodec::codecForLocale()->mimeName() );
+
+ return cmd;
+}
+
+void Config::setRemoveCollectionCommandLine( const QString& cmd )
+{
+ m_config->setGroup( CONFIG_GROUP );
+ m_config->writeEntry( "RemoveCollection Commandline", cmd );
+}
+
+QString Config::mrmldCommandline() const
+{
+ ServerSettings settings = settingsForLocalHost();
+
+ m_config->setGroup( CONFIG_GROUP );
+ QString cmd = m_config->readEntry( "MrmmlDaemon Commandline",
+ settings.autoPort ?
+ DEFAULT_MRMLD_CMD_AUTOPORT :
+ DEFAULT_MRMLD_CMD );
+
+ // add data directory and port to the commandline
+ int index = cmd.find( "%p" );
+ if ( index != -1 )
+ {
+ QString port = settings.autoPort ?
+ QString::null : QString::number( settings.configuredPort );
+ cmd.replace( index, 2, port );
+ }
+ index = cmd.find( "%d" );
+ if ( index != -1 )
+ {
+ cmd.replace( index, 2, QUOTE( mrmldDataDir() ) );
+ }
+
+ qDebug("***** commandline: %s", cmd.latin1());
+
+ return cmd;
+}
+
+QString Config::mrmldDataDir()
+{
+ QString dir = KGlobal::dirs()->saveLocation( "data",
+ "kmrml/mrmld-data/" );
+ if ( dir.isEmpty() ) // fallback
+ dir = QDir::homeDirPath() + "/";
+
+ return dir;
+}
+
+void Config::setMrmldCommandLine( const QString& cmd )
+{
+ m_config->setGroup( CONFIG_GROUP );
+ m_config->writeEntry( "MrmmlDaemon Commandline", cmd );
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+ServerSettings::ServerSettings()
+ : configuredPort( 0 ),
+ autoPort( true ),
+ useAuth( false )
+{
+}
+
+ServerSettings::ServerSettings( const QString& host, unsigned short int port,
+ bool autoPort, bool useAuth,
+ const QString& user, const QString& pass )
+{
+ this->host = host;
+ this->configuredPort = port;
+ this->autoPort = autoPort;
+ this->useAuth = useAuth;
+ this->user = user;
+ this->pass = pass;
+}
+
+// static
+ServerSettings ServerSettings::defaults()
+{
+ return ServerSettings( DEFAULT_HOST, DEFAULT_PORT,
+ (!strcmp(DEFAULT_HOST, "localhost") && DEFAULT_PORT),
+ DEFAULT_AUTH, DEFAULT_USER, DEFAULT_PASS );
+}
+
+KURL ServerSettings::getUrl() const
+{
+ KURL url;
+ url.setProtocol( "mrml" );
+ url.setHost( host );
+ if ( !autoPort )
+ url.setPort( configuredPort );
+
+ if ( useAuth && user.isEmpty() )
+ {
+ url.setUser( user );
+ url.setPass( pass );
+ }
+
+ return url;
+}
+
+unsigned short int ServerSettings::port() const
+{
+ if ( autoPort )
+ {
+ QString portsFile = Config::mrmldDataDir() + "gift-port.txt";
+ QFile file( portsFile );
+ if ( file.open( IO_ReadOnly ) )
+ {
+ QString line;
+ (void) file.readLine( line, 6 );
+// qDebug("**** read: %s", line.latin1());
+
+ file.close();
+
+ bool ok;
+ unsigned short int p = line.toUShort( &ok );
+ if ( ok )
+ return p;
+ }
+ else
+ kdWarning() << "Can't open \"" << portsFile << "\" to automatically determine the gift port" << endl;
+ }
+
+ return configuredPort;
+}
diff --git a/kmrml/kmrml/lib/kmrml_config.h b/kmrml/kmrml/lib/kmrml_config.h
new file mode 100644
index 00000000..3b6baa40
--- /dev/null
+++ b/kmrml/kmrml/lib/kmrml_config.h
@@ -0,0 +1,123 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KMRML_CONFIG_H
+#define KMRML_CONFIG_H
+
+class KConfig;
+
+#include <qstringlist.h>
+#include <kurl.h>
+
+namespace KMrml
+{
+ class ServerSettings
+ {
+ public:
+ ServerSettings();
+ ServerSettings(const QString& host, unsigned short int port,
+ bool autoPort, bool useAuth, const
+ QString& user, const QString& pass);
+
+ // does NOT set the port in the KURL object, if autoPort is selected
+ // kio_mrml is going to determine itself (via ServerSettings::port()).
+ // This deuglifies the mrml:/ url a bit (no port is shown)
+ KURL getUrl() const;
+
+ QString host;
+ QString user;
+ QString pass;
+ unsigned short int configuredPort;
+ bool autoPort :1; // only possible with host == localhost
+ bool useAuth :1;
+
+ static ServerSettings defaults();
+
+ // returns configuredPort or the automatically determined port,
+ // depending on the value of autoPort
+ unsigned short int port() const;
+ };
+
+ class Config
+ {
+ public:
+ Config();
+ Config( KConfig *config ); // does not take ownership of KConfig
+ ~Config();
+
+ bool sync();
+
+ ServerSettings defaultSettings() const
+ {
+ return settingsForHost( m_defaultHost );
+ }
+
+ ServerSettings settingsForLocalHost() const;
+ ServerSettings settingsForHost( const QString& host ) const;
+
+ void setDefaultHost( const QString& host );
+
+ /**
+ * Indexed by the hostname -- ensures there are no dupes
+ */
+ void addSettings( const ServerSettings& settings );
+
+ bool removeSettings( const QString& host );
+
+ QStringList hosts() const { return m_hostList; }
+
+ /**
+ * The list of indexable directories -- only applicable to "localhost"
+ */
+ QStringList indexableDirectories() const;
+ void setIndexableDirectories( const QStringList& dirs );
+
+ QString addCollectionCommandLine() const;
+ void setAddCollectionCommandLine( const QString& cmd );
+
+ QString removeCollectionCommandLine() const;
+ void setRemoveCollectionCommandLine( const QString& cmd );
+
+ void setMrmldCommandLine( const QString& cmd );
+ QString mrmldCommandline() const;
+
+ // e.g. Wolfgang needs this :)
+ bool serverStartedIndividually() const {
+ return m_serverStartedIndividually;
+ }
+
+ static QString mrmldDataDir();
+
+ private:
+ void init();
+
+ QString settingsGroup( const QString& host ) const
+ {
+ return QString::fromLatin1( "SettingsFor: " ).append( host );
+ }
+
+ bool m_serverStartedIndividually;
+ QString m_defaultHost;
+ QStringList m_hostList;
+
+ KConfig *m_config;
+ KConfig *m_ownConfig;
+ };
+}
+
+#endif // KMRML_CONFIG_H
diff --git a/kmrml/kmrml/lib/mrml_shared.cpp b/kmrml/kmrml/lib/mrml_shared.cpp
new file mode 100644
index 00000000..0c5b692b
--- /dev/null
+++ b/kmrml/kmrml/lib/mrml_shared.cpp
@@ -0,0 +1,235 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mrml_shared.h"
+
+// mrml stuff
+const QString * MrmlShared::m_sessionId = 0L;
+const QString * MrmlShared::m_transactionId = 0L;
+const QString * MrmlShared::m_algorithm = 0L;
+const QString * MrmlShared::m_algorithmId = 0L;
+const QString * MrmlShared::m_algorithmName = 0L;
+const QString * MrmlShared::m_algorithmList = 0L;
+const QString * MrmlShared::m_algorithmType = 0L;
+const QString * MrmlShared::m_collectionId = 0L;
+const QString * MrmlShared::m_collectionList = 0L;
+const QString * MrmlShared::m_collection = 0L;
+const QString * MrmlShared::m_collectionName = 0L;
+const QString * MrmlShared::m_queryParadigm = 0L;
+const QString * MrmlShared::m_queryParadigmList = 0L;
+const QString * MrmlShared::m_configureSession = 0L;
+
+const QString * MrmlShared::m_propertySheet = 0L;
+const QString * MrmlShared::m_propertySheetId = 0L;
+const QString * MrmlShared::m_propertySheetType = 0L;
+const QString * MrmlShared::m_sendName = 0L;
+const QString * MrmlShared::m_sendType = 0L;
+const QString * MrmlShared::m_sendValue = 0L;
+const QString * MrmlShared::m_maxSubsetSize = 0L;
+const QString * MrmlShared::m_minSubsetSize = 0L;
+const QString * MrmlShared::m_caption = 0L;
+const QString * MrmlShared::m_from = 0L;
+const QString * MrmlShared::m_to = 0L;
+const QString * MrmlShared::m_step = 0L;
+const QString * MrmlShared::m_sendBooleanInverted = 0L;
+
+const QString * MrmlShared::m_element = 0L;
+const QString * MrmlShared::m_attribute = 0L;
+const QString * MrmlShared::m_attributeName = 0L;
+const QString * MrmlShared::m_attributeValue = 0L;
+const QString * MrmlShared::m_children = 0L;
+const QString * MrmlShared::m_none = 0L;
+
+const QString * MrmlShared::m_multiSet = 0L;
+const QString * MrmlShared::m_subset = 0L;
+const QString * MrmlShared::m_setElement = 0L;
+const QString * MrmlShared::m_boolean = 0L;
+const QString * MrmlShared::m_numeric = 0L;
+const QString * MrmlShared::m_textual = 0L;
+const QString * MrmlShared::m_panel = 0L;
+const QString * MrmlShared::m_clone = 0L;
+const QString * MrmlShared::m_reference = 0L;
+
+const QString * MrmlShared::m_visibility = 0L;
+const QString * MrmlShared::m_visible = 0L;
+const QString * MrmlShared::m_invisible = 0L;
+const QString * MrmlShared::m_popup = 0L;
+// const QString * MrmlShared::m_ = 0L;
+
+// meta-data
+const QString * MrmlShared::m_mrml_data = 0L;
+
+// kio_mrml tasks
+const QString * MrmlShared::m_kio_task = 0L;
+const QString * MrmlShared::m_kio_initialize = 0L;
+const QString * MrmlShared::m_kio_startQuery = 0L;
+
+
+int MrmlShared::s_references = 0;
+
+void MrmlShared::ref()
+{
+ if ( s_references == 0 )
+ init();
+
+ s_references++;
+}
+
+bool MrmlShared::deref()
+{
+ if ( s_references > 0 )
+ s_references--;
+
+ if ( s_references == 0 )
+ {
+ // ### delete all strings here...
+
+ return true;
+ }
+
+ return false;
+}
+
+void MrmlShared::init()
+{
+ m_sessionId = new QString ( "session-id" ) ;
+ m_transactionId = new QString ( "transaction-id" ) ;
+ m_algorithm = new QString ( "algorithm" ) ;
+ m_algorithmId = new QString ( "algorithm-id" ) ;
+ m_algorithmName = new QString ( "algorithm-name" ) ;
+ m_algorithmList = new QString ( "algorithm-list" ) ;
+ m_algorithmType = new QString ( "algorithm-type" ) ;
+ m_collectionId = new QString ( "collection-id" ) ;
+ m_collectionList = new QString ( "collection-list" ) ;
+ m_collection = new QString ( "collection" ) ;
+ m_collectionName = new QString ( "collection-name" ) ;
+ m_queryParadigm = new QString ( "query-paradigm" ) ;
+ m_queryParadigmList = new QString ( "query-paradigm-list" ) ;
+ m_configureSession = new QString ( "configure-session" ) ;
+
+ m_propertySheet = new QString ( "property-sheet" ) ;
+ m_propertySheetId = new QString ( "property-sheet-id" ) ;
+ m_propertySheetType = new QString ( "property-sheet-type" ) ;
+ m_sendName = new QString ( "send-name" ) ;
+ m_sendType = new QString ( "send-type" ) ;
+ m_sendValue = new QString ( "send-value" ) ;
+ m_maxSubsetSize = new QString ( "maxsubsetsize" ) ;
+ m_minSubsetSize = new QString ( "minsubsetsize" ) ;
+ m_caption = new QString ( "caption" ) ;
+ m_from = new QString ( "from" ) ;
+ m_to = new QString ( "to" ) ;
+ m_step = new QString ( "step" ) ;
+ m_sendBooleanInverted = new QString ( "send-boolean-inverted" ) ;
+
+ m_element = new QString ( "element" ) ;
+ m_attribute = new QString ( "attribute" ) ;
+ m_attributeName = new QString ( "attribute-name" ) ;
+ m_attributeValue = new QString ( "attribute-value" ) ;
+ m_children = new QString ( "children" ) ;
+ m_none = new QString ( "none" ) ;
+
+ m_multiSet = new QString ( "multi-set" ) ;
+ m_subset = new QString ( "subset" ) ;
+ m_setElement = new QString ( "set-element" ) ;
+ m_boolean = new QString ( "boolean" ) ;
+ m_numeric = new QString ( "numeric" ) ;
+ m_textual = new QString ( "textual" ) ;
+ m_panel = new QString ( "panel" ) ;
+ m_clone = new QString ( "clone" ) ;
+ m_reference = new QString ( "reference" ) ;
+
+ m_visibility = new QString ( "visibility" ) ;
+ m_visible = new QString ( "visible" ) ;
+ m_invisible = new QString ( "invisible" ) ;
+ m_popup = new QString ( "popup" ) ;
+// m_ = new QString ( "" ) ;
+
+// meta-data
+ m_mrml_data = new QString ( "mrml_data" ) ;
+
+// kio_mrml tasks
+ m_kio_task = new QString ( "kio_task" ) ;
+ m_kio_initialize = new QString ( "kio_initialize" ) ;
+ m_kio_startQuery = new QString ( "kio_startQuery" ) ;
+}
+
+void MrmlShared::cleanup()
+{
+ delete m_sessionId;
+ delete m_transactionId;
+ delete m_algorithm;
+ delete m_algorithmId;
+ delete m_algorithmName;
+ delete m_algorithmList;
+ delete m_algorithmType;
+ delete m_collectionId;
+ delete m_collectionList;
+ delete m_collection;
+ delete m_collectionName;
+ delete m_queryParadigm;
+ delete m_queryParadigmList;
+ delete m_configureSession;
+
+ // property sheet stuff
+ delete m_propertySheet;
+ delete m_propertySheetId;
+ delete m_propertySheetType;
+ delete m_sendName;
+ delete m_sendType;
+ delete m_sendValue;
+ delete m_maxSubsetSize;
+ delete m_minSubsetSize;
+ delete m_caption;
+ delete m_from;
+ delete m_to;
+ delete m_step;
+ delete m_sendBooleanInverted;
+
+ delete m_multiSet;
+ delete m_subset;
+ delete m_setElement;
+ delete m_boolean;
+ delete m_numeric;
+ delete m_textual;
+ delete m_panel;
+ delete m_clone;
+ delete m_reference;
+
+ delete m_element;
+ delete m_attribute;
+ delete m_attributeName;
+ delete m_attributeValue;
+ delete m_children;
+ delete m_none;
+
+ delete m_visibility;
+ delete m_visible;
+ delete m_invisible;
+ delete m_popup;
+// delete m_;
+
+ // meta-data
+ delete m_mrml_data;
+
+ // kio_mrml tasks
+ delete m_kio_task;
+ delete m_kio_initialize;
+ delete m_kio_startQuery;
+
+}
diff --git a/kmrml/kmrml/lib/mrml_shared.h b/kmrml/kmrml/lib/mrml_shared.h
new file mode 100644
index 00000000..aff2a98d
--- /dev/null
+++ b/kmrml/kmrml/lib/mrml_shared.h
@@ -0,0 +1,166 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SHARED_H
+#define SHARED_H
+
+// maybe use mrml_const.h from libMRML, unfortunately not installed
+// by gift 0.1.6pre2
+
+#include <qshared.h>
+#include <qstring.h>
+
+class MrmlShared
+{
+public:
+// attribute/element names for mrml
+ static void ref();
+ static bool deref();
+
+ static const QString& sessionId() { return *m_sessionId; }
+ static const QString& transactionId() { return *m_transactionId; }
+ static const QString& algorithm() { return *m_algorithm; }
+ static const QString& algorithmId() { return *m_algorithmId; }
+ static const QString& algorithmName() { return *m_algorithmName; }
+ static const QString& algorithmList() { return *m_algorithmList; }
+ static const QString& algorithmType() { return *m_algorithmType; }
+ static const QString& collectionId() { return *m_collectionId; }
+ static const QString& collectionList() { return *m_collectionList; }
+ static const QString& collection() { return *m_collection; }
+ static const QString& collectionName() { return *m_collectionName; }
+ static const QString& queryParadigm() { return *m_queryParadigm; }
+ static const QString& queryParadigmList() { return *m_queryParadigmList; }
+ static const QString& configureSession() { return *m_configureSession; }
+
+ // property sheet stuff
+ static const QString& propertySheet() { return *m_propertySheet; }
+ static const QString& propertySheetId() { return *m_propertySheetId; }
+ static const QString& propertySheetType() { return *m_propertySheetType; }
+ static const QString& sendName() { return *m_sendName; }
+ static const QString& sendType() { return *m_sendType; }
+ static const QString& sendValue() { return *m_sendValue; }
+ static const QString& maxSubsetSize() { return *m_maxSubsetSize; }
+ static const QString& minSubsetSize() { return *m_minSubsetSize; }
+ static const QString& caption() { return *m_caption; }
+ static const QString& from() { return *m_from; }
+ static const QString& to() { return *m_to; }
+ static const QString& step() { return *m_step; }
+ static const QString& sendBooleanInverted() { return *m_sendBooleanInverted; }
+
+ static const QString& multiSet() { return *m_multiSet; }
+ static const QString& subset() { return *m_subset; }
+ static const QString& setElement() { return *m_setElement; }
+ static const QString& boolean() { return *m_boolean; }
+ static const QString& numeric() { return *m_numeric; }
+ static const QString& textual() { return *m_textual; }
+ static const QString& panel() { return *m_panel; }
+ static const QString& clone() { return *m_clone; }
+ static const QString& reference() { return *m_reference; }
+
+ static const QString& element() { return *m_element; }
+ static const QString& attribute() { return *m_attribute; }
+ static const QString& attributeName() { return *m_attributeName; }
+ static const QString& attributeValue() { return *m_attributeValue; }
+ static const QString& children() { return *m_children; }
+ static const QString& none() { return *m_none; }
+
+ static const QString& visibility() { return *m_visibility; }
+ static const QString& visible() { return *m_visible; }
+ static const QString& invisible() { return *m_invisible; }
+ static const QString& popup() { return *m_popup; }
+// static const QString& () { return *m_; }
+
+ // meta-data
+ static const QString& mrml_data() { return *m_mrml_data; }
+
+ // kio_mrml tasks
+ static const QString& kio_task() { return *m_kio_task; }
+ static const QString& kio_initialize() { return *m_kio_initialize; }
+ static const QString& kio_startQuery() { return *m_kio_startQuery; }
+
+
+private:
+ static const QString * m_sessionId;
+ static const QString * m_transactionId;
+ static const QString * m_algorithm;
+ static const QString * m_algorithmId;
+ static const QString * m_algorithmName;
+ static const QString * m_algorithmList;
+ static const QString * m_algorithmType;
+ static const QString * m_collectionId;
+ static const QString * m_collectionList;
+ static const QString * m_collection;
+ static const QString * m_collectionName;
+ static const QString * m_queryParadigm;
+ static const QString * m_queryParadigmList;
+ static const QString * m_configureSession;
+
+ // property sheet stuff
+ static const QString * m_propertySheet;
+ static const QString * m_propertySheetId;
+ static const QString * m_propertySheetType;
+ static const QString * m_sendName;
+ static const QString * m_sendType;
+ static const QString * m_sendValue;
+ static const QString * m_maxSubsetSize;
+ static const QString * m_minSubsetSize;
+ static const QString * m_caption;
+ static const QString * m_from;
+ static const QString * m_to;
+ static const QString * m_step;
+ static const QString * m_sendBooleanInverted;
+
+ static const QString * m_multiSet;
+ static const QString * m_subset;
+ static const QString * m_setElement;
+ static const QString * m_boolean;
+ static const QString * m_numeric;
+ static const QString * m_textual;
+ static const QString * m_panel;
+ static const QString * m_clone;
+ static const QString * m_reference;
+
+ static const QString * m_element;
+ static const QString * m_attribute;
+ static const QString * m_attributeName;
+ static const QString * m_attributeValue;
+ static const QString * m_children;
+ static const QString * m_none;
+
+ static const QString * m_visibility;
+ static const QString * m_visible;
+ static const QString * m_invisible;
+ static const QString * m_popup;
+// static const QString * m_;
+
+ // meta-data
+ static const QString * m_mrml_data;
+
+ // kio_mrml tasks
+ static const QString * m_kio_task;
+ static const QString * m_kio_initialize;
+ static const QString * m_kio_startQuery;
+
+private:
+ static void cleanup();
+ static void init();
+
+ static int s_references;
+};
+
+#endif // SHARED_H
diff --git a/kmrml/kmrml/lib/mrml_utils.cpp b/kmrml/kmrml/lib/mrml_utils.cpp
new file mode 100644
index 00000000..f20dad6a
--- /dev/null
+++ b/kmrml/kmrml/lib/mrml_utils.cpp
@@ -0,0 +1,89 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <dcopclient.h>
+#include <kapplication.h>
+#include <kprocess.h>
+#include <kstaticdeleter.h>
+
+#include "watcher_stub.h"
+
+#include "mrml_utils.h"
+
+// after 100 of no use, terminate the mrmld
+#define TIMEOUT 100
+// how often to restart the mrmld in case of failure
+#define NUM_RESTARTS 5
+
+using namespace KMrml;
+
+KStaticDeleter<Util> utils_sd;
+
+Util *Util::s_self = 0L;
+
+Util::Util()
+{
+ // we need our own dcopclient, when used in kio_mrml
+ if ( !DCOPClient::mainClient() )
+ {
+ DCOPClient::setMainClient( new DCOPClient() );
+ if ( !DCOPClient::mainClient()->attach() )
+ qWarning( "kio_mrml: Can't attach to DCOP Server.");
+ }
+}
+
+Util::~Util()
+{
+ if ( this == s_self )
+ s_self = 0L;
+}
+
+Util *Util::self()
+{
+ if ( !s_self )
+ s_self = utils_sd.setObject( new Util() );
+ return s_self;
+}
+
+bool Util::requiresLocalServerFor( const KURL& url )
+{
+ return url.host().isEmpty() || url.host() == "localhost";
+}
+
+bool Util::startLocalServer( const Config& config )
+{
+ if ( config.serverStartedIndividually() )
+ return true;
+
+ DCOPClient *client = DCOPClient::mainClient();
+
+ // ### check if it's already running (add dcop method to Watcher)
+ Watcher_stub watcher( client, "kded", "daemonwatcher");
+ return ( watcher.requireDaemon( client->appId(),
+ "mrmld", config.mrmldCommandline(),
+ TIMEOUT, NUM_RESTARTS )
+ && watcher.ok() );
+}
+
+void Util::unrequireLocalServer()
+{
+ DCOPClient *client = DCOPClient::mainClient();
+
+ Watcher_stub watcher( client, "kded", "daemonwatcher");
+ watcher.unrequireDaemon( client->appId(), "mrmld" );
+}
diff --git a/kmrml/kmrml/lib/mrml_utils.h b/kmrml/kmrml/lib/mrml_utils.h
new file mode 100644
index 00000000..25f39d98
--- /dev/null
+++ b/kmrml/kmrml/lib/mrml_utils.h
@@ -0,0 +1,50 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef MRML_UTILS_H
+#define MRML_UTILS_H
+
+#include <qobject.h>
+
+#include <kurl.h>
+
+#include "kmrml_config.h"
+
+namespace KMrml
+{
+ class Util : public QObject
+ {
+ public:
+ static Util * self();
+ ~Util();
+
+ bool requiresLocalServerFor( const KURL& url );
+ bool startLocalServer( const Config& config );
+ void unrequireLocalServer();
+// bool isLocalServerRunning();
+
+ private:
+ static Util *s_self;
+ Util();
+ };
+
+
+}
+
+#endif // MRML_UTILS_H
diff --git a/kmrml/kmrml/lib/version.h b/kmrml/kmrml/lib/version.h
new file mode 100644
index 00000000..5cf8e270
--- /dev/null
+++ b/kmrml/kmrml/lib/version.h
@@ -0,0 +1,6 @@
+#ifndef VERSION_H
+#define VERSION_H
+
+#define KMRML_VERSION "0.3.2"
+
+#endif // VERSION_H
diff --git a/kmrml/kmrml/lib/watcher_stub.cpp b/kmrml/kmrml/lib/watcher_stub.cpp
new file mode 100644
index 00000000..cf84818b
--- /dev/null
+++ b/kmrml/kmrml/lib/watcher_stub.cpp
@@ -0,0 +1,95 @@
+//
+// Generated in ../server/ via dcopidl -- needs to be in the lib tho.
+// Regenerate when necessary by uncommenting the watcher.stub in
+// ../server/Makefile.am
+//
+
+#include "watcher_stub.h"
+#include <dcopclient.h>
+
+#include <kdatastream.h>
+
+namespace KMrml {
+
+Watcher_stub::Watcher_stub( const QCString& app, const QCString& obj )
+ : DCOPStub( app, obj )
+{
+}
+
+Watcher_stub::Watcher_stub( DCOPClient* client, const QCString& app, const QCString& obj )
+ : DCOPStub( client, app, obj )
+{
+}
+
+bool Watcher_stub::requireDaemon( const QCString& arg0, const QString& arg1, const QString& arg2, uint arg3, int arg4 )
+{
+ bool result;
+ if ( !dcopClient() ) {
+ setStatus( CallFailed );
+ return false;
+ }
+ QByteArray data, replyData;
+ QCString replyType;
+ QDataStream arg( data, IO_WriteOnly );
+ arg << arg0;
+ arg << arg1;
+ arg << arg2;
+ arg << arg3;
+ arg << arg4;
+ if ( dcopClient()->call( app(), obj(), "requireDaemon(QCString,QString,QString,uint,int)", data, replyType, replyData ) ) {
+ if ( replyType == "bool" ) {
+ QDataStream _reply_stream( replyData, IO_ReadOnly );
+ _reply_stream >> result;
+ setStatus( CallSucceeded );
+ } else {
+ callFailed();
+ }
+ } else {
+ callFailed();
+ }
+ return result;
+}
+
+void Watcher_stub::unrequireDaemon( const QCString& arg0, const QString& arg1 )
+{
+ if ( !dcopClient() ) {
+ setStatus( CallFailed );
+ return;
+ }
+ QByteArray data, replyData;
+ QCString replyType;
+ QDataStream arg( data, IO_WriteOnly );
+ arg << arg0;
+ arg << arg1;
+ if ( dcopClient()->call( app(), obj(), "unrequireDaemon(QCString,QString)", data, replyType, replyData ) ) {
+ setStatus( CallSucceeded );
+ } else {
+ callFailed();
+ }
+}
+
+QStringList Watcher_stub::runningDaemons()
+{
+ QStringList result;
+ if ( !dcopClient() ) {
+ setStatus( CallFailed );
+ return result;
+ }
+ QByteArray data, replyData;
+ QCString replyType;
+ if ( dcopClient()->call( app(), obj(), "runningDaemons()", data, replyType, replyData ) ) {
+ if ( replyType == "QStringList" ) {
+ QDataStream _reply_stream( replyData, IO_ReadOnly );
+ _reply_stream >> result;
+ setStatus( CallSucceeded );
+ } else {
+ callFailed();
+ }
+ } else {
+ callFailed();
+ }
+ return result;
+}
+
+} // namespace
+
diff --git a/kmrml/kmrml/lib/watcher_stub.h b/kmrml/kmrml/lib/watcher_stub.h
new file mode 100644
index 00000000..04b1292e
--- /dev/null
+++ b/kmrml/kmrml/lib/watcher_stub.h
@@ -0,0 +1,36 @@
+//
+// Generated in ../server/ via dcopidl -- needs to be in the lib tho.
+// Regenerate when necessary by uncommenting the watcher.stub in
+// ../server/Makefile.am
+//
+
+#ifndef __WATCHER_STUB__
+#define __WATCHER_STUB__
+
+#include <dcopstub.h>
+#include <qdict.h>
+#include <qptrlist.h>
+#include <qmap.h>
+#include <qstrlist.h>
+#include <qstringlist.h>
+#include <qtimer.h>
+#include <kdedmodule.h>
+#include <kprocess.h>
+
+namespace KMrml {
+
+class Watcher_stub : public DCOPStub
+{
+public:
+ Watcher_stub( const QCString& app, const QCString& id );
+ Watcher_stub( DCOPClient* client, const QCString& app, const QCString& id );
+ virtual bool requireDaemon( const QCString& clientAppId, const QString& daemonKey, const QString& commandline, uint timeout, int numRestarts );
+ virtual void unrequireDaemon( const QCString& clientAppId, const QString& daemonKey );
+ virtual QStringList runningDaemons();
+protected:
+ Watcher_stub() : DCOPStub( never_use ) {};
+};
+
+} // namespace
+
+#endif
diff --git a/kmrml/kmrml/loader.cpp b/kmrml/kmrml/loader.cpp
new file mode 100644
index 00000000..cc59c172
--- /dev/null
+++ b/kmrml/kmrml/loader.cpp
@@ -0,0 +1,121 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kstaticdeleter.h>
+#include <kio/scheduler.h>
+
+#include "loader.h"
+
+Loader *Loader::s_self = 0L;
+
+KStaticDeleter<Loader> sd;
+
+Loader * Loader::self()
+{
+ if ( !s_self )
+ s_self = sd.setObject( new Loader() );
+
+ return s_self;
+}
+
+Loader::Loader() : QObject()
+{
+}
+
+Loader::~Loader()
+{
+ disconnect( this, SIGNAL( finished( const KURL&, const QByteArray& )));
+
+ DownloadIterator it = m_downloads.begin();
+ for ( ; it != m_downloads.end(); ++it ) {
+ it.key()->kill();
+ delete it.data();
+ }
+
+ s_self = 0L;
+}
+
+void Loader::requestDownload( const KURL& url )
+{
+ DownloadIterator it = m_downloads.begin();
+ for ( ; it != m_downloads.end(); ++it ) {
+ if ( it.key()->url() == url )
+ return;
+ }
+
+ KIO::TransferJob *job = KIO::get( url, false, false );
+ KIO::Scheduler::scheduleJob(job);
+
+ connect( job , SIGNAL( data( KIO::Job *, const QByteArray& )),
+ SLOT( slotData( KIO::Job *, const QByteArray& )));
+ connect( job , SIGNAL( result( KIO::Job * )),
+ SLOT( slotResult( KIO::Job * )));
+
+ Download *d = new Download();
+ m_downloads.insert( job, d );
+}
+
+void Loader::slotData( KIO::Job *job, const QByteArray& data )
+{
+ DownloadIterator it = m_downloads.find( static_cast<KIO::TransferJob*>(job) );
+ if ( it != m_downloads.end() ) {
+ QBuffer& buffer = it.data()->m_buffer;
+ if ( !buffer.isOpen() )
+ buffer.open( IO_ReadWrite );
+ if ( !buffer.isOpen() ) {
+ qDebug("********* EEK, can't open buffer for thumbnail download!");
+ return;
+ }
+
+ buffer.writeBlock( data.data(), data.size() );
+ }
+}
+
+void Loader::slotResult( KIO::Job *job )
+{
+ KIO::TransferJob *tjob = static_cast<KIO::TransferJob*>( job );
+
+ DownloadIterator it = m_downloads.find( tjob );
+ if ( it != m_downloads.end() ) {
+ Download *d = it.data();
+
+ if ( job->error() != 0 )
+ emit finished( tjob->url(), QByteArray() );
+ else
+ emit finished( tjob->url(), d->m_buffer.buffer() );
+
+ delete d;
+ m_downloads.remove( it );
+ }
+}
+
+
+// ### simultaneous downloads with multiple views? reference count downloads!
+void Loader::removeDownload( const KURL& url )
+{
+ DownloadIterator it = m_downloads.begin();
+ for ( ; it != m_downloads.end(); ++it ) {
+ if ( it.key()->url() == url ) {
+ it.key()->kill();
+ delete it.data();
+ return;
+ }
+ }
+}
+
+#include "loader.moc"
diff --git a/kmrml/kmrml/loader.h b/kmrml/kmrml/loader.h
new file mode 100644
index 00000000..5e81a2e4
--- /dev/null
+++ b/kmrml/kmrml/loader.h
@@ -0,0 +1,72 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef LOADER_H
+#define LOADER_H
+
+#include <qbuffer.h>
+#include <qcstring.h>
+#include <qmap.h>
+#include <qobject.h>
+
+#include <kio/job.h>
+#include <kurl.h>
+
+class Download
+{
+public:
+ ~Download() {
+ if ( m_buffer.isOpen() )
+ m_buffer.close();
+ }
+ QBuffer m_buffer;
+ // add context of MrmlPart for progress?
+};
+
+
+class Loader : public QObject
+{
+ friend class gcc_sucks;
+ Q_OBJECT
+
+public:
+ static Loader *self();
+ ~Loader();
+
+ void requestDownload( const KURL& url );
+
+ void removeDownload( const KURL& url );
+
+signals:
+ void finished( const KURL& url, const QByteArray& );
+
+private slots:
+ void slotData( KIO::Job *, const QByteArray& );
+ void slotResult( KIO::Job * );
+
+private:
+ Loader();
+
+ QMap<KIO::TransferJob*,Download*> m_downloads;
+ typedef QMapIterator<KIO::TransferJob*,Download*> DownloadIterator;
+
+ static Loader *s_self;
+
+};
+
+#endif // LOADER_H
diff --git a/kmrml/kmrml/mrml-servicemenu.desktop b/kmrml/kmrml/mrml-servicemenu.desktop
new file mode 100644
index 00000000..2d9a938c
--- /dev/null
+++ b/kmrml/kmrml/mrml-servicemenu.desktop
@@ -0,0 +1,67 @@
+[Desktop Entry]
+ServiceTypes=image/png,image/jpeg,image/gif,image/tiff,image/bmp,image/x-xpm,image/x-xbm,image/x-png
+Actions=search;
+
+[Desktop Action search]
+Name=Search for Similar Images...
+Name[af]=Soektog vir Soortgelyk Beelde...
+Name[ar]=بحث عن الصور المتشابهه...
+Name[bg]=Търсене на подобни изображения...
+Name[bs]=Traženje sličnih slika...
+Name[ca]=Cerca imatges similars...
+Name[cs]=Hledat podobný obrázek...
+Name[cy]=Chwilio am Ddelweddau Tebyg...
+Name[da]=Søg efter lignende filer...
+Name[de]=Nach ähnlichen Bildern suchen ...
+Name[el]=Αναζήτηση για παρόμοιες εικόνες...
+Name[eo]=Serĉi Similajn Bildojn...
+Name[es]=Búsqueda de imágenes similares...
+Name[et]=Otsi sarnaseid pilte...
+Name[eu]=Bilatu antzeko irudiak...
+Name[fa]=جستجو برای تصاویر مشابه...
+Name[fi]=Etsi samankaltaisia kuvia...
+Name[fr]=Recherche d'images semblables...
+Name[gl]=Procurar imaxes semellantes...
+Name[he]=חיפוש תמונות דומות...
+Name[hi]=एक जैसे छवियों के लिए ढूंढें...
+Name[hu]=Ehhez hasonló képek keresése...
+Name[is]=Leita að svipuðum myndum...
+Name[it]=Cerca immagini simili...
+Name[ja]=同じような画像を検索...
+Name[kk]=Ұқсас кескіндерді іздеу...
+Name[km]=ស្វែងរក​រូបភាព​ស្រដៀង​គ្នា...
+Name[lt]=Panašių paveikslėlių paieška...
+Name[ms]=Cari Imej Serupa...
+Name[nb]=Søk etter liknende bilder …
+Name[nds]=Na lieke Biller söken...
+Name[ne]=उस्तै छविका लागि खोजी गर्नुहोस्...
+Name[nl]=Zoeken naar vergelijkbare afbeeldingen...
+Name[nn]=Søk etter liknande bilete …
+Name[nso]=Nyako ya Diponagalo tseo di Swanago...
+Name[pl]=Szukaj podobnych obrazków
+Name[pt]=Procurar por Imagens Semelhantes...
+Name[pt_BR]=Procurar por Imagens Parecidas...
+Name[ro]=Caută imagini similare...
+Name[ru]=Поиск похожих изображений...
+Name[se]=Oza seammalágana govaid …
+Name[sk]=Hľadať podobné obrázky...
+Name[sl]=Išči podobne slike ...
+Name[sr]=Потражи сличне слике...
+Name[sr@Latn]=Potraži slične slike...
+Name[sv]=Sök efter liknande bilder...
+Name[ta]=இதே போன்ற பிம்பங்களை தேடுக...
+Name[tg]=Ҷустуҷӯи тасвироти якхела...
+Name[th]=ค้นหาภาพที่เหมือนกัน...
+Name[tr]=Benzer Resimleri Ara...
+Name[uk]=Пошук схожих зображень...
+Name[uz]=Oʻxshash rasmlarni qidirish
+Name[uz@cyrillic]=Ўхшаш расмларни қидириш
+Name[ven]=Todani zwifanyiso zwielanaho...
+Name[wa]=Cweri après des rshonnantès imådjes...
+Name[xh]=Phendla Imifanekiso Efanayo...
+Name[zh_CN]=搜索类似图像...
+Name[zh_HK]=尋找類似的圖像...
+Name[zh_TW]=尋找類似的影像...
+Name[zu]=Sesha ukuthola Izithombe Ezifanayo....
+Icon=image
+Exec=mrmlsearch %U
diff --git a/kmrml/kmrml/mrml.cpp b/kmrml/kmrml/mrml.cpp
new file mode 100644
index 00000000..082d037b
--- /dev/null
+++ b/kmrml/kmrml/mrml.cpp
@@ -0,0 +1,267 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kinstance.h>
+#include <klocale.h>
+
+#include <mrml_utils.h>
+
+#include "mrml.h"
+
+extern "C" {
+ KDE_EXPORT int kdemain( int argc, char **argv )
+ {
+ KLocale::setMainCatalogue("kdelibs");
+ KInstance instance( "kio_mrml" );
+ KGlobal::locale()->insertCatalogue( "kmrml" );
+
+ kdDebug() << "Starting MRML " << getpid() << endl;
+
+ if (argc != 4)
+ {
+ fprintf(stderr, "Usage: kio_mrml protocol domain-socket1 domain-socket2\n");
+ exit(-1);
+ }
+
+ Mrml slave(argv[2], argv[3]);
+ slave.dispatchLoop();
+
+ kdDebug() << "Done" << endl;
+ return 0;
+ }
+}
+
+const int Mrml::bufsize = 8192;
+
+Mrml::Mrml( const QCString& pool_socket, const QCString& app_socket )
+ : TCPSlaveBase( 12789, "mrml", pool_socket, app_socket ),
+ m_config( KGlobal::config() )
+{
+ MrmlShared::ref();
+}
+
+Mrml::~Mrml()
+{
+ KMrml::Util::self()->unrequireLocalServer();
+
+ closeDescriptor();
+ MrmlShared::deref();
+}
+
+bool Mrml::checkLocalServer( const KURL& url )
+{
+ if ( KMrml::Util::self()->requiresLocalServerFor( url ) )
+ {
+ if ( !KMrml::Util::self()->startLocalServer( m_config ) )
+ return false;
+ }
+
+ return true;
+}
+
+void Mrml::get( const KURL& url )
+{
+// qDebug("******* getting: %s (user: %s)", url.url().latin1(), url.user().latin1());
+
+ if ( !checkLocalServer( url ) )
+ {
+ error( KIO::ERR_SLAVE_DEFINED, i18n("Unable to start the Indexing Server. "
+ "Aborting the query.") );
+ return;
+ }
+
+ int retriesLeft = 5;
+tryConnect:
+
+ QCString utf8;
+ bool sendError = (retriesLeft <= 0);
+
+ if ( connectToHost( url.host(), port(url), sendError ) )
+ {
+// qDebug(" connected!");
+
+ QString task = metaData( MrmlShared::kio_task() );
+
+ if ( task == MrmlShared::kio_initialize() ) {
+ startSession( url );
+ }
+
+ else if ( task == MrmlShared::kio_startQuery() ) {
+ QString meta = metaData( MrmlShared::mrml_data() );
+ if ( meta.isEmpty() ) {
+ closeDescriptor();
+ error( KIO::ERR_SLAVE_DEFINED, i18n("No MRML data is available.") );
+ return;
+ }
+
+ utf8 = meta.utf8();
+ write( utf8, utf8.length() );
+
+ emitData( readAll() );
+ }
+
+ // no task metadata available, we're called from KonqRun or something
+ // like that. Emitting the mimetype seems to suffice for now. After
+ // that, MrmlPart is going to start and start the get() again.
+ else
+ {
+ mimeType( "text/mrml" );
+ finished();
+ }
+
+ }
+ else
+ {
+ if ( retriesLeft-- >= 0 )
+ {
+#ifdef HAVE_USLEEP
+ usleep( 500 ); // wait a while for gift to start up
+#endif
+ goto tryConnect;
+ return;
+ }
+
+ error( KIO::ERR_COULD_NOT_CONNECT,
+ i18n("Could not connect to GIFT server.") );
+ return;
+ }
+
+ closeDescriptor();
+ //data( QByteArray() ); // send an empty QByteArray to signal end of data.
+ finished();
+}
+
+// make sure we're connected when you call this!
+QCString Mrml::readAll()
+{
+ QCString data;
+
+ char buf[bufsize];
+ ssize_t bytes = 0;
+
+ while ( (bytes = read( buf, bufsize-1 )) > 0 ) {
+ buf[bytes] = '\0';
+ data.append( buf );
+ }
+
+// qDebug("*** readAll()::: %i, %s", data.length(), data.data());
+ return data;
+}
+
+QCString Mrml::loginString()
+{
+ return "<mrml><get-server-properties/></mrml>";
+}
+
+QCString Mrml::getConfigurationString()
+{
+ return "<mrml><get-configuration/></mrml>";
+}
+
+// ### needed?
+QCString Mrml::getSessionsString( const QString& username,
+ const QString& password )
+{
+ QCString data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><mrml><get-sessions ";
+ if ( !username.isEmpty() ) { // ### pop up auth-dialog???
+ data.append( "user-name=\"");
+ data.append( username.utf8() );
+ data.append( "\"");
+
+ if ( !password.isEmpty() ) {
+ data.append( " password=\"");
+ data.append( password.utf8() );
+ data.append( "\"" );
+ }
+
+ }
+ data.append( "/></mrml>" );
+
+ return data;
+}
+
+
+bool Mrml::startSession( const KURL& url )
+{
+ // might first ask for collections, and then for algorithms for the
+ // desired collection-id
+
+ // Wolfgang says, we shouldn't create an own session-id here, as gcc 2.95
+ // apparently makes problems in exception handling somehow. So we simply
+ // accept the server's session-id.
+ QString msg = mrmlString( QString::null ).arg(
+ "<open-session user-name=\"%1\" session-name=\"kio_mrml session\" /> \
+ <get-algorithms /> \
+ <get-collections /> \
+ </mrml>" ).arg( user( url ));
+
+ QCString utf8 = msg.utf8();
+// qDebug(":::Writing: %s", utf8.data());
+ write( utf8, utf8.length() );
+
+ emitData( readAll() );
+
+ return true;
+}
+
+QString Mrml::mrmlString( const QString& sessionId, const QString& transactionId )
+{
+ QString msg =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?> \
+ <!DOCTYPE mrml SYSTEM \"http://isrpc85.epfl.ch/Charmer/code/mrml.dtd\"> \
+ %1 \
+ </mrml>";
+
+ if ( sessionId.isEmpty() ) // when we don't have one yet
+ return msg.arg( "<mrml>%1" );
+
+ if ( transactionId.isNull() )
+ return msg.arg( "<mrml session-id=\"%1\">%1" ).arg( sessionId );
+ else
+ return msg.arg( "<mrml session-id=\"%1\" transaction-id=\"%1\">%1")
+ .arg( sessionId ).arg( transactionId );
+}
+
+void Mrml::emitData( const QCString& msg )
+{
+ mimeType( "text/mrml" );
+ data( msg );
+ processedSize( msg.count() );
+}
+
+void Mrml::mimetype( const KURL& url )
+{
+ if ( url.protocol() == "mrml" ) {
+ mimeType( "text/mrml" );
+ finished();
+ }
+ else
+ KIO::TCPSlaveBase::mimetype( url );
+}
diff --git a/kmrml/kmrml/mrml.desktop b/kmrml/kmrml/mrml.desktop
new file mode 100644
index 00000000..73abf1e0
--- /dev/null
+++ b/kmrml/kmrml/mrml.desktop
@@ -0,0 +1,60 @@
+[Desktop Entry]
+Comment=Multimedia Retrieval Markup Language Document
+Comment[af]=Multimedia Onttrekking Opmerk Taal Dokument
+Comment[ar]=مستند لغة ترميز استرجاع الوسائط المتعددة
+Comment[bs]=Multimedia Retrieval Markup Language dokument
+Comment[ca]=Document de llenguatge de marcatge de recuperació multimèdia
+Comment[cs]=Multimedia Retrieval Markup Language dokument
+Comment[cy]=Dogfen Multimedia Retrieval Markup Language
+Comment[da]=Multimedia Retrieval Markup Language-dokument
+Comment[de]=Multimedia Suche- und Beschreibungssprache-Dokument (MRML-Dokument)
+Comment[el]=Έγγραφο Multimedia Retrieval Markup Language
+Comment[es]=Documento de lenguaje de descripción de descargas multimedia
+Comment[et]=Multimeedia otsingu märgistuskeele (MRML) dokument
+Comment[eu]=Multimedia Retrieval Markup Language dokumentua
+Comment[fa]=سند زبان نشان‌گذاری بازیابی چند رسانه‌ای
+Comment[fi]=Multimedianhakuasiakirja
+Comment[fr]=Document en langage Multimedia Retrieval Markup (MRML)
+Comment[he]=מסמך שפת סימון לאחזור מולטימדיה
+Comment[hi]=मल्टीमीडिया रिट्राइवल मार्कअप लैंग्वेज दस्तावेज़
+Comment[hu]=MRML-fájl
+Comment[is]=Multimedia Retrieval Markup Language skjal
+Comment[it]=Documento MRML
+Comment[ja]=Multimedia Retrieval Markup Language ドキュメント
+Comment[kk]=MRML (Multimedia Retrieval Markup Language) құжаты
+Comment[km]=ឯកសារ Multimedia Retrieval Markup Language
+Comment[lt]=Multimedia Retrieval Markup kalbos dokumentas
+Comment[ms]=Dokumen Bahasa Capaian Tandatas Multimedia
+Comment[nb]=«Multimedia Retrieval Markup Language»-dokument
+Comment[nds]=Dokment in de Affraag-Utteekspraak för Multimedia-Dokmenten
+Comment[ne]=मल्टिमिडिया पुन: प्राप्ति मार्कअप भाषा कागजात
+Comment[nl]=Multimedia Retrieval Markup Language-document
+Comment[nn]=«Multimedia Retrieval Markup Language»-dokument
+Comment[nso]=Tokomane ya Leleme la Peakanyo ya Kutullo ya Multimedia
+Comment[pl]=Dokument MRML (Język Znacznikowy Pozyskiwania Multimediów)
+Comment[pt]=Documento de Multimedia Retrieval Markup Language
+Comment[pt_BR]=Documento da Linguagem de Marcação de Recuperação Multimídia
+Comment[ro]=Document MRML (limbaj de marcare pentru căutări multimedia)
+Comment[ru]=Документ MRML (Multimedia Retrieval Markup Language)
+Comment[se]=«Multimedia Retrieval Markup Language»-dokumeanta
+Comment[sk]=Dokument Multimedia Retrieval Markup Language
+Comment[sl]=Dokument Multimedia Retrieval Markup Language
+Comment[sr]=Документ у обележивачком језику за добављање мултимедије (MRML)
+Comment[sr@Latn]=Dokument u obeleživačkom jeziku za dobavljanje multimedije (MRML)
+Comment[sv]=Multimedia Retrieval Markup Language-dokument
+Comment[ta]=பல் ஊடக திரும்பப்பெறு அடையாள மொழி ஆவணம்
+Comment[tg]=Санади MRML (Multimedia Retrieval Markup Language)
+Comment[th]=เอกสาร Multimedia Retrieval Markup Language
+Comment[tr]=Multimedia Retrieval Markup Language Belgesi
+Comment[uk]=Документ формату зберігання мультимедіа
+Comment[ven]=Manwalwa a luambo lwau humbula zwa khasho nnzhi
+Comment[xh]=Uxwebhu Lolwimi Lophawulo phezulu Lokufumana i Multimedia
+Comment[zh_CN]=多媒体检索标记语言文档
+Comment[zh_HK]=多媒體取得標記語言文件
+Comment[zh_TW]=多媒體補償標記語言文件
+Comment[zu]=Ushicilelo Lwe-Multimedia Retrieval Markup Language
+Icon=html
+Type=MimeType
+MimeType=text/mrml
+Patterns=*.mrml;*.MRML;
+X-KDE-AutoEmbed=true
diff --git a/kmrml/kmrml/mrml.h b/kmrml/kmrml/mrml.h
new file mode 100644
index 00000000..f8088ef6
--- /dev/null
+++ b/kmrml/kmrml/mrml.h
@@ -0,0 +1,84 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MRML_H
+#define MRML_H
+
+
+#include <kio/tcpslavebase.h>
+#include <kurl.h>
+
+#include <kmrml_config.h>
+#include "mrml_shared.h"
+
+class Mrml : public KIO::TCPSlaveBase
+{
+public:
+ Mrml( const QCString&, const QCString& );
+ ~Mrml();
+
+ virtual void get( const KURL& url );
+
+ virtual void mimetype( const KURL& url );
+
+private:
+ QCString readAll();
+ void emitData( const QCString& );
+
+ bool startSession( const KURL& url );
+
+ // helpers
+ inline QString sessionId() {
+ return metaData( MrmlShared::sessionId() );
+ }
+
+ // misc
+ short int port( const KURL& url )
+ {
+ return (url.port() != 0) ?
+ url.port() :
+ m_config.settingsForHost( url.host() ).port();
+ }
+
+ static QString mrmlString( const QString& sessionId,
+ const QString& transactionId = QString::null );
+
+ static QCString loginString();
+ static QCString getConfigurationString();
+ static QCString getSessionsString( const QString& username,
+ const QString& password );
+ QString user( const KURL& url ) {
+ return url.hasUser() ?
+ url.user() : m_config.defaultSettings().user;
+ }
+ QString pass( const KURL& url ) {
+ return url.hasPass() ?
+ url.pass() : m_config.defaultSettings().pass;
+ }
+
+ bool checkLocalServer( const KURL& url );
+
+ static const int bufsize;
+ QString defaultUser;
+ QString defaultPass;
+
+ KMrml::Config m_config;
+
+};
+
+#endif // MRML_H
diff --git a/kmrml/kmrml/mrml.protocol b/kmrml/kmrml/mrml.protocol
new file mode 100644
index 00000000..c3a732eb
--- /dev/null
+++ b/kmrml/kmrml/mrml.protocol
@@ -0,0 +1,10 @@
+[Protocol]
+exec=kio_mrml
+protocol=mrml
+input=none
+output=filesystem
+reading=true
+defaultMimetype=text/mrml
+determineMimetypeFromExtension=false
+Icon=image
+DocPath=kioslave/mrml.html
diff --git a/kmrml/kmrml/mrml_creator.cpp b/kmrml/kmrml/mrml_creator.cpp
new file mode 100644
index 00000000..fce84e36
--- /dev/null
+++ b/kmrml/kmrml/mrml_creator.cpp
@@ -0,0 +1,76 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mrml_creator.h"
+
+QDomElement MrmlCreator::createMrml( QDomDocument& doc,
+ const QString& sessionId,
+ const QString& transactionId )
+{
+ QDomElement mrml = doc.createElement( "mrml" );
+ doc.appendChild( mrml );
+ mrml.setAttribute( MrmlShared::sessionId(), sessionId );
+ if ( !transactionId.isNull() )
+ mrml.setAttribute( MrmlShared::transactionId(), transactionId );
+
+ return mrml;
+}
+
+QDomElement MrmlCreator::configureSession( QDomElement& mrml,
+ const KMrml::Algorithm& algo,
+ const QString& sessionId )
+{
+ QDomDocument doc = mrml.ownerDocument();
+ QDomElement config = doc.createElement( MrmlShared::configureSession() );
+ mrml.appendChild( config );
+ config.setAttribute( MrmlShared::sessionId(), sessionId );
+ algo.toElement( config );
+
+ return config;
+}
+
+QDomElement MrmlCreator::addQuery( QDomElement& mrml, int resultSize )
+{
+ QDomElement query = mrml.ownerDocument().createElement("query-step");
+ mrml.appendChild( query );
+ // query.setAttribute( "query-step-id", "5" ); // ###
+ query.setAttribute( "result-size", QString::number( resultSize ));
+ return query;
+}
+
+QDomElement MrmlCreator::addRelevanceList( QDomElement& query )
+{
+ QDomElement elem =
+ query.ownerDocument().createElement("user-relevance-element-list");
+ query.appendChild( elem );
+ return elem;
+}
+
+/**
+ * Creates a <user-relevance-element> with the given attributes set.
+ */
+void MrmlCreator::createRelevanceElement( QDomDocument& doc,
+ QDomElement& parent,
+ const QString& url,
+ Relevance relevance )
+{
+ QDomElement element = doc.createElement( "user-relevance-element" );
+ element.setAttribute( "image-location", url );
+ element.setAttribute( "user-relevance", QString::number( relevance ) );
+ parent.appendChild( element );
+}
diff --git a/kmrml/kmrml/mrml_creator.h b/kmrml/kmrml/mrml_creator.h
new file mode 100644
index 00000000..2cc59e7a
--- /dev/null
+++ b/kmrml/kmrml/mrml_creator.h
@@ -0,0 +1,49 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MRML_CREATOR_H
+#define MRML_CREATOR_H
+
+#include <qdom.h>
+
+#include <kurl.h>
+
+#include "mrml_elements.h"
+#include "mrml_shared.h"
+
+namespace MrmlCreator
+{
+ enum Relevance { Relevant = 1, Irrelevant = -1 };
+
+ QDomElement createMrml( QDomDocument& doc,
+ const QString& sessionId,
+ const QString& transactionId = QString::null );
+ QDomElement configureSession( QDomElement& mrml,
+ const KMrml::Algorithm& algo,
+ const QString& sessionId );
+ QDomElement addQuery( QDomElement& mrml, int resultSize );
+ QDomElement addRelevanceList( QDomElement& query );
+ /**
+ * Creates a <user-relevance-element> with the given attributes set.
+ */
+ void createRelevanceElement( QDomDocument& doc, QDomElement& parent,
+ const QString& url, Relevance relevance );
+
+}
+
+#endif // MRML_CREATOR_H
diff --git a/kmrml/kmrml/mrml_elements.cpp b/kmrml/kmrml/mrml_elements.cpp
new file mode 100644
index 00000000..20f3d04e
--- /dev/null
+++ b/kmrml/kmrml/mrml_elements.cpp
@@ -0,0 +1,358 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mrml_elements.h"
+#include "mrml_shared.h"
+
+#include <kdatastream.h>
+
+#include <qdom.h>
+
+using namespace KMrml;
+
+//
+// MrmlElement is currently the baseclass for Algorithm and Collection. Both
+// may have a single child-element <query-paradigm-list>, with a number of
+// <query-paradigm> elements as children.
+//
+
+MrmlElement::MrmlElement( const QDomElement& elem )
+{
+ QValueList<QDomElement> list =
+ KMrml::directChildElements( elem, MrmlShared::queryParadigmList() );
+
+ Q_ASSERT( list.count() < 2 ); // There can be only one.
+
+ if ( list.count() )
+ m_paradigms.initFromDOM( list.first() );
+}
+
+
+void MrmlElement::setOtherAttributes( QDomElement& elem ) const
+{
+ QMapConstIterator<QString,QString> it = m_attributes.begin();
+ for ( ; it != m_attributes.end(); ++it )
+ {
+ elem.setAttribute( it.key(), it.data() );
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+AlgorithmList AlgorithmList::algorithmsForCollection( const Collection& coll ) const
+{
+ AlgorithmList list;
+
+ AlgorithmList::ConstIterator it = begin();
+ for ( ; it != end(); ++it )
+ {
+ Algorithm algo = *it;
+ if ( algo.paradigms().matches( coll.paradigms() ) )
+ {
+ algo.setCollectionId( coll.id() );
+ list.append( algo );
+ }
+ }
+
+ return list;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+Collection::Collection( const QDomElement& elem )
+ : MrmlElement( elem )
+{
+ QDomNamedNodeMap attrs = elem.attributes();
+ for ( uint i = 0; i < attrs.length(); i++ )
+ {
+ QDomAttr attribute = attrs.item( i ).toAttr();
+ QString name = attribute.name();
+
+ if ( name == MrmlShared::collectionName() )
+ m_name = attribute.value();
+ else if ( name == MrmlShared::collectionId() )
+ m_id = attribute.value();
+
+ else // custom attributes
+ m_attributes.insert( name, attribute.value() );
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+Algorithm::Algorithm( const QDomElement& elem )
+ : MrmlElement( elem )
+{
+ QDomNamedNodeMap attrs = elem.attributes();
+
+ for ( uint i = 0; i < attrs.length(); i++ )
+ {
+ QDomAttr attribute = attrs.item( i ).toAttr();
+ QString name = attribute.name();
+
+ if ( name == MrmlShared::algorithmName() )
+ m_name = attribute.value();
+ else if ( name == MrmlShared::algorithmId() )
+ m_id = attribute.value();
+ else if ( name == MrmlShared::algorithmType() )
+ m_type = attribute.value();
+
+ // not really necessary
+ else if ( name == MrmlShared::collectionId() )
+ m_collectionId = attribute.value();
+
+ else // custom attributes
+ m_attributes.insert( name, attribute.value() );
+ }
+
+ QDomElement propsElem = firstChildElement(elem, MrmlShared::propertySheet());
+ m_propertySheet.initFromDOM( propsElem );
+
+ qDebug("############# new algorithm: name: %s, id: %s, type: %s", m_name.latin1(), m_id.latin1(), m_type.latin1());
+}
+
+Algorithm Algorithm::defaultAlgorithm()
+{
+ Algorithm algo;
+ algo.m_id = "adefault";
+ algo.m_type = "adefault"; // ### not in the DTD
+ algo.m_name = "dummy";
+
+ return algo;
+}
+
+QDomElement Algorithm::toElement( QDomElement& parent ) const
+{
+ QDomDocument doc = parent.ownerDocument();
+ QDomElement algorithm = doc.createElement( MrmlShared::algorithm() );
+ parent.appendChild( algorithm );
+ setOtherAttributes( algorithm );
+
+ if ( !m_name.isEmpty() )
+ algorithm.setAttribute( MrmlShared::algorithmName(), m_name );
+ if ( !m_id.isEmpty() )
+ algorithm.setAttribute( MrmlShared::algorithmId(), m_id );
+ if ( !m_type.isEmpty() )
+ algorithm.setAttribute( MrmlShared::algorithmType(), m_type );
+
+ if ( !m_collectionId.isEmpty() )
+ algorithm.setAttribute( MrmlShared::collectionId(), m_collectionId );
+ return algorithm;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+QueryParadigm::QueryParadigm( const QDomElement& elem )
+{
+ QDomNamedNodeMap attrs = elem.attributes();
+ for ( uint i = 0; i < attrs.count(); i++ )
+ {
+ QDomAttr attr = attrs.item( i ).toAttr();
+ m_attributes.insert( attr.name(), attr.value() );
+ if ( attr.name() == "type" )
+ m_type = attr.value();
+ }
+}
+
+bool QueryParadigm::matches( const QueryParadigm& other ) const
+{
+ return m_attributes.isEmpty() || other.m_attributes.isEmpty() ||
+ equalMaps( m_attributes, other.m_attributes );
+}
+
+bool QueryParadigm::equalMaps( const QMap<QString,QString> m1,
+ const QMap<QString,QString> m2 )
+{
+ if ( m1.count() != m2.count() )
+ return false;
+
+ QMapConstIterator<QString,QString> it = m1.begin();
+ for ( ; it != m1.end(); ++it )
+ {
+ QMapConstIterator<QString,QString> it2 = m2.find( it.key() );
+ if ( it2 == m2.end() || it.data() != it2.data() )
+ return false;
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+void QueryParadigmList::initFromDOM( const QDomElement& elem )
+{
+ clear();
+
+ QValueList<QDomElement> list =
+ KMrml::directChildElements( elem, MrmlShared::queryParadigm() );
+
+ QValueListConstIterator<QDomElement> it = list.begin();
+ for ( ; it != list.end(); ++it )
+ {
+ append( QueryParadigm( *it ));
+ }
+}
+
+// two QueryParadigmLists match, when there is at least one pair of
+// QueryParadigms that match (all attribute-value pairs are equal, or there
+// are no attributes at all).
+bool QueryParadigmList::matches( const QueryParadigmList& other ) const
+{
+ ConstIterator it = begin();
+
+ for ( ; it != end(); ++it )
+ {
+ ConstIterator oit = other.begin();
+ for ( ; oit != other.end(); ++oit )
+ if ( (*it).matches( *oit ) )
+ return true;
+ }
+
+ return false;
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+QValueList<QDomElement> KMrml::directChildElements( const QDomElement& parent,
+ const QString& tagName )
+{
+ QValueList<QDomElement> list;
+
+ QDomNode node = parent.firstChild();
+ while ( !node.isNull() )
+ {
+ if ( node.isElement() && node.nodeName() == tagName )
+ list.append( node.toElement() );
+
+ node = node.nextSibling();
+ }
+
+ return list;
+}
+
+QDomElement KMrml::firstChildElement( const QDomElement& parent,
+ const QString& tagName )
+{
+ QDomNode node = parent.firstChild();
+ while ( !node.isNull() )
+ {
+ if ( node.isElement() && node.nodeName() == tagName )
+ return node.toElement();
+
+ node = node.nextSibling();
+ }
+
+ return QDomElement();
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+QDataStream& KMrml::operator<<( QDataStream& stream, const QueryParadigm& )
+{
+
+ return stream;
+}
+QDataStream& KMrml::operator>>( QDataStream& stream, QueryParadigm& )
+{
+
+ return stream;
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream, const QueryParadigmList& )
+{
+
+ return stream;
+}
+QDataStream& KMrml::operator>>( QDataStream& stream, QueryParadigmList& )
+{
+
+ return stream;
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream, const MrmlElement& )
+{
+
+ return stream;
+}
+QDataStream& KMrml::operator>>( QDataStream& stream, MrmlElement& )
+{
+
+ return stream;
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream, const Algorithm& )
+{
+
+ return stream;
+}
+QDataStream& KMrml::operator>>( QDataStream& stream, Algorithm& )
+{
+
+ return stream;
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream, const Collection& )
+{
+
+ return stream;
+}
+QDataStream& KMrml::operator>>( QDataStream& stream, Collection& )
+{
+ return stream;
+}
+
+template <class t> QDataStream& KMrml::operator<<( QDataStream& stream,
+ const MrmlElementList<t>& )
+{
+
+ return stream;
+}
+template <class t> QDataStream& KMrml::operator>>( QDataStream& stream,
+ MrmlElementList<t>& )
+{
+
+ return stream;
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream, const AlgorithmList& )
+{
+
+ return stream;
+}
+QDataStream& KMrml::operator>>( QDataStream& stream, AlgorithmList& )
+{
+
+ return stream;
+}
+
diff --git a/kmrml/kmrml/mrml_elements.h b/kmrml/kmrml/mrml_elements.h
new file mode 100644
index 00000000..09d2a4a8
--- /dev/null
+++ b/kmrml/kmrml/mrml_elements.h
@@ -0,0 +1,255 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MRML_ELEMENTS_H
+#define MRML_ELEMENTS_H
+
+#include <qdom.h>
+#include <qmap.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+
+#include "mrml_shared.h"
+#include "propertysheet.h"
+
+#include <assert.h>
+
+namespace KMrml
+{
+ class PropertySheet;
+
+ class QueryParadigm
+ {
+ public:
+ QueryParadigm() {}
+ QueryParadigm( const QDomElement& elem );
+ bool matches( const QueryParadigm& other ) const;
+ QString type() const { return m_type; }
+
+// bool operator== ( const QueryParadigm& p1, const QueryParadigm& p2 )
+
+ private:
+ QString m_type;
+ QMap<QString,QString> m_attributes;
+
+ static bool equalMaps( const QMap<QString,QString>,
+ const QMap<QString,QString> );
+ };
+
+ class QueryParadigmList : protected QValueList<QueryParadigm>
+ {
+ public:
+ typedef QValueListIterator<QueryParadigm> Iterator;
+ typedef QValueListConstIterator<QueryParadigm> ConstIterator;
+
+ void initFromDOM( const QDomElement& elem );
+ bool matches( const QueryParadigmList& other ) const;
+ };
+
+ class MrmlElement
+ {
+ public:
+ MrmlElement() {}
+ MrmlElement( const QDomElement& elem );
+ virtual ~MrmlElement() {}
+
+ QString id() const { return m_id; }
+ QString name() const { return m_name; }
+ QString attribute( const QString& name ) const { return m_attributes[ name ]; }
+ QueryParadigmList paradigms() const { return m_paradigms; }
+
+
+ QMapConstIterator<QString,QString> attributeIterator() const {
+ return m_attributes.begin();
+ }
+ QMapConstIterator<QString,QString> end() const { return m_attributes.end(); }
+
+ bool isValid() const { return !m_name.isNull() && !m_id.isNull(); }
+
+ protected:
+ QString m_id;
+ QString m_name;
+ QueryParadigmList m_paradigms;
+ QMap<QString,QString> m_attributes;
+
+ void setOtherAttributes( QDomElement& elem ) const;
+ };
+
+ class Algorithm : public MrmlElement
+ {
+ public:
+ Algorithm() { m_collectionId = "adefault"; }
+ Algorithm( const QDomElement& elem );
+ QString type() const { return m_type; }
+
+ QString collectionId() const
+ {
+ return m_collectionId;
+ }
+ void setCollectionId( const QString& id )
+ {
+ m_collectionId = id;
+ }
+
+ QDomElement toElement( QDomElement& parent ) const;
+ const PropertySheet& propertySheet() const;
+
+ static Algorithm defaultAlgorithm();
+
+ private:
+ QString m_type;
+ PropertySheet m_propertySheet;
+
+ QString m_collectionId;
+ };
+
+ class Collection : public MrmlElement
+ {
+ public:
+ Collection() {}
+ Collection( const QDomElement& elem );
+ };
+
+ template <class t> class MrmlElementList : public QValueList<t>
+ {
+ public:
+ typedef QValueListIterator<t> Iterator;
+ typedef QValueListConstIterator<t> ConstIterator;
+
+ /**
+ * Creates an invalid element.
+ */
+ MrmlElementList( const QString& tagName ) :
+ QValueList<t>(),
+ m_tagName( tagName ) {}
+ MrmlElementList( const QDomElement& elem, const QString& tagName ) :
+ QValueList<t>(),
+ m_tagName( tagName )
+ {
+ initFromDOM( elem );
+ }
+ virtual ~MrmlElementList() {};
+
+ void initFromDOM( const QDomElement& elem )
+ {
+ assert( !m_tagName.isEmpty() );
+
+ QValueList<t>::clear();
+
+ QDomNodeList list = elem.elementsByTagName( m_tagName );
+ for ( uint i = 0; i < list.length(); i++ )
+ {
+ QDomElement elem = list.item( i ).toElement();
+ t item( elem );
+ if ( item.isValid() )
+ append( item );
+ }
+ }
+
+ t findByName( const QString& name ) const
+ {
+ QValueListConstIterator<t> it = QValueList<t>::begin();
+ for ( ; it != QValueList<t>::end(); ++it )
+ {
+ if ( (*it).name() == name )
+ return *it;
+ }
+
+ return t();
+ }
+
+ t findById( const QString& id ) const
+ {
+ QValueListConstIterator<t> it = QValueList<t>::begin();
+ for ( ; it != QValueList<t>::end(); ++it )
+ {
+ if ( (*it).id() == id )
+ return *it;
+ }
+
+ return MrmlElement();
+ }
+
+ QStringList itemNames() const {
+ QStringList list;
+ QValueListConstIterator<t> it = QValueList<t>::begin();
+ for ( ; it != QValueList<t>::end(); ++it )
+ list.append( (*it).name() );
+
+ return list;
+ }
+
+ void setItemName( const QString& tagName ) { m_tagName = tagName; }
+ QString tagName() const { return m_tagName; }
+
+ private:
+ QString m_tagName;
+ MrmlElementList();
+ };
+
+ class AlgorithmList : public MrmlElementList<Algorithm>
+ {
+ public:
+ AlgorithmList() :
+ MrmlElementList<Algorithm>( MrmlShared::algorithm() )
+ {}
+
+ AlgorithmList algorithmsForCollection( const Collection& coll ) const;
+ };
+
+ class CollectionList : public MrmlElementList<Collection>
+ {
+ public:
+ CollectionList() :
+ MrmlElementList<Collection>( MrmlShared::collection() )
+ {}
+ };
+
+
+ QValueList<QDomElement> directChildElements( const QDomElement& parent,
+ const QString& tagName);
+ QDomElement firstChildElement( const QDomElement& parent,
+ const QString& tagName );
+
+
+ QDataStream& operator<<( QDataStream& stream, const QueryParadigm& );
+ QDataStream& operator>>( QDataStream& stream, QueryParadigm& );
+
+ QDataStream& operator<<( QDataStream& stream, const QueryParadigmList& );
+ QDataStream& operator>>( QDataStream& stream, QueryParadigmList& );
+
+ QDataStream& operator<<( QDataStream& stream, const MrmlElement& );
+ QDataStream& operator>>( QDataStream& stream, MrmlElement& );
+
+ QDataStream& operator<<( QDataStream& stream, const Algorithm& );
+ QDataStream& operator>>( QDataStream& stream, Algorithm& );
+
+ QDataStream& operator<<( QDataStream& stream, const Collection& );
+ QDataStream& operator>>( QDataStream& stream, Collection& );
+
+ template <class t> QDataStream& operator<<( QDataStream&,
+ const MrmlElementList<t>& );
+ template <class t> QDataStream& operator>>( QDataStream&,
+ MrmlElementList<t>& );
+
+ QDataStream& operator<<( QDataStream&, const AlgorithmList& );
+ QDataStream& operator>>( QDataStream&, AlgorithmList& );
+
+}
+
+#endif // MRML_ELEMENTS_H
diff --git a/kmrml/kmrml/mrml_part.cpp b/kmrml/kmrml/mrml_part.cpp
new file mode 100644
index 00000000..4d3f65e6
--- /dev/null
+++ b/kmrml/kmrml/mrml_part.cpp
@@ -0,0 +1,857 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qcheckbox.h>
+#include <qcursor.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qgrid.h>
+#include <qhgroupbox.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qtooltip.h>
+#include <qvbox.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <kconfig.h>
+#include <kdatastream.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <kio/job.h>
+#include <kio/jobclasses.h>
+#include <kmessagebox.h>
+#include <knuminput.h>
+#include <kprotocolinfo.h>
+#include <kparts/genericfactory.h>
+#include <ktempfile.h>
+
+#include <mrml_utils.h>
+
+#include "algorithmdialog.h"
+#include "browser.h"
+#include "collectioncombo.h"
+#include "mrml_creator.h"
+#include "mrml_elements.h"
+#include "mrml_shared.h"
+#include "mrml_view.h"
+#include "mrml_part.h"
+#include "version.h"
+
+using namespace KMrml;
+
+extern "C"
+{
+ void * init_libkmrmlpart() {
+ return new KMrml::PartFactory();
+ }
+}
+
+KInstance * PartFactory::s_instance = 0L;
+
+PartFactory::PartFactory()
+ : KParts::Factory()
+{
+ MrmlShared::ref();
+}
+
+PartFactory::~PartFactory()
+{
+ MrmlShared::deref();
+ delete s_instance;
+ s_instance = 0L;
+}
+
+KInstance * PartFactory::instance()
+{
+ if ( !s_instance ) {
+ s_instance = new KInstance( "kmrml" );
+ KGlobal::locale()->insertCatalogue( "kmrml" );
+ }
+ return s_instance;
+}
+
+KParts::Part * PartFactory::createPartObject( QWidget *parentWidget,
+ const char *widgetName,
+ QObject *parent,
+ const char *name,
+ const char *,
+ const QStringList& args )
+{
+ return new MrmlPart( parentWidget, widgetName, parent, name, args );
+}
+
+
+// can't use this due to MrmlShared ref-counting
+// typedef KParts::GenericFactory<KMrml::MrmlPart> PartFactory;
+// K_EXPORT_COMPONENT_FACTORY( mrmlpart, PartFactory )
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+uint MrmlPart::s_sessionId = 0;
+
+MrmlPart::MrmlPart( QWidget *parentWidget, const char * /* widgetName */,
+ QObject *parent, const char *name,
+ const QStringList& /* args */ )
+ : KParts::ReadOnlyPart( parent, name ),
+ m_job( 0L ),
+ m_status( NeedCollection )
+{
+ m_sessionId = QString::number( s_sessionId++ ).prepend("kmrml_");
+
+ setName( "MRML Part" );
+ m_browser = new Browser( this, "mrml browserextension");
+ setInstance( PartFactory::instance(), true ); // do load plugins :)
+ KConfig *config = PartFactory::instance()->config();
+ config->setGroup("MRML Settings");
+
+ QVBox *box = new QVBox( parentWidget, "main mrml box" );
+ m_view = new MrmlView( box, "MrmlView" );
+ connect( m_view, SIGNAL( activated( const KURL&, ButtonState )),
+ this, SLOT( slotActivated( const KURL&, ButtonState )));
+ connect( m_view, SIGNAL( onItem( const KURL& )),
+ this, SLOT( slotSetStatusBar( const KURL& )));
+
+ m_panel = new QHGroupBox( box, "buttons box" );
+
+ QGrid *comboGrid = new QGrid( 2, m_panel, "combo grid" );
+ comboGrid->setSpacing( KDialog::spacingHint() );
+
+ (void) new QLabel( i18n("Server to query:"), comboGrid );
+
+ m_hostCombo = new KComboBox( false, comboGrid, "host combo" );
+ initHostCombo();
+ connect( m_hostCombo, SIGNAL( activated( const QString& ) ),
+ SLOT( slotHostComboActivated( const QString& )));
+
+ (void) new QLabel( i18n("Search in collection:"), comboGrid );
+ m_collectionCombo = new CollectionCombo( comboGrid, "collection-combo" );
+ // will be re-set in initCollections(), but we need to set it here to
+ // prevent crashes when the connection to the server fails
+ m_collectionCombo->setCollections( &m_collections );
+
+ m_algoButton = new QPushButton( QString::null, m_panel );
+ m_algoButton->setPixmap( SmallIcon("configure") );
+ m_algoButton->setFixedSize( m_algoButton->sizeHint() );
+ connect( m_algoButton, SIGNAL( clicked() ),
+ SLOT( slotConfigureAlgorithm() ));
+ QToolTip::add( m_algoButton, i18n("Configure algorithm") );
+
+ QWidget *spacer = new QWidget( m_panel );
+ spacer->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding,
+ QSizePolicy::Minimum ) );
+
+ int resultSize = config->readNumEntry( "Result-size", 20 );
+ m_resultSizeInput = new KIntNumInput( resultSize, m_panel );
+ m_resultSizeInput->setRange( 1, 100 );
+ m_resultSizeInput->setLabel( i18n("Maximum result images:") );
+
+ QVBox *tmp = new QVBox( m_panel );
+ m_random = new QCheckBox( i18n("Random search"), tmp );
+
+ m_startButton = new QPushButton( QString::null, tmp );
+ connect( m_startButton, SIGNAL( clicked() ), SLOT( slotStartClicked() ));
+ setStatus( NeedCollection );
+
+ setWidget( box );
+
+ // setXMLFile( "mrml_part.rc" );
+
+ slotSetStatusBar( QString::null );
+
+ enableServerDependentWidgets( false );
+}
+
+MrmlPart::~MrmlPart()
+{
+ closeURL();
+}
+
+void MrmlPart::enableServerDependentWidgets( bool enable )
+{
+ m_collectionCombo->setEnabled( enable );
+ m_algoButton->setEnabled( enable && false ); // ### re-enable!!!
+}
+
+void MrmlPart::initCollections( const QDomElement& elem )
+{
+ m_collections.initFromDOM( elem );
+
+ m_collectionCombo->setCollections( &m_collections );
+ enableServerDependentWidgets( m_collectionCombo->count() > 0 );
+
+ if ( m_collectionCombo->count() == 0 )
+ {
+ KMessageBox::information( widget(),
+ i18n("There is no image collection available\n"
+ "at %1.\n"), i18n("No Image Collection"));
+ setStatus( NeedCollection );
+ }
+ else
+ m_collectionCombo->updateGeometry(); // adjust the entire grid
+}
+
+void MrmlPart::initAlgorithms( const QDomElement& elem )
+{
+ m_algorithms.initFromDOM( elem );
+}
+
+// this is where we start!
+bool MrmlPart::openURL( const KURL& url )
+{
+ closeURL();
+
+ if ( url.protocol() != "mrml" || !url.isValid() ) {
+ qWarning("MrmlPart::openURL: cannot handle url: %s", url.prettyURL().latin1());
+ return false; // what to do with that?
+ }
+
+ m_url = url;
+ QString host = url.host().isEmpty() ?
+ QString::fromLatin1("localhost") : url.host();
+
+ m_hostCombo->setCurrentItem( host );
+
+ // urls we need to download before starting the query
+ KURL::List downloadList;
+
+ m_queryList.clear();
+ QString param = url.queryItem( "relevant" );
+ QStringList list = QStringList::split( ';', param );
+
+ // we can only search by example on localhost
+ if ( host != "localhost" )
+ {
+ if ( !list.isEmpty() )
+ KMessageBox::sorry( m_view,
+ i18n("You can only search by example images "
+ "on a local indexing server."),
+ i18n("Only Local Servers Possible") );
+ }
+
+ else // localhost query
+ {
+ for( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
+ {
+ KURL u;
+ if ( (*it).at(0) == '/' )
+ u.setPath( *it );
+ else
+ u = *it;
+
+ if ( u.isValid() )
+ {
+ if ( u.isLocalFile() )
+ m_queryList.append( u );
+ else
+ downloadList.append( u );
+ }
+ }
+
+
+ // ### we need a real solution for this!
+ // gift refuses to start when no config file is available.
+ if ( !QFile::exists( m_config.mrmldDataDir() + "/gift-config.mrml" ) )
+ {
+ if ( KMessageBox::questionYesNo(0L,
+ i18n("There are no indexable folders "
+ "specified. Do you want to configure them "
+ "now?"),
+ i18n("Configuration Missing"),
+ i18n("Configure"),
+ i18n("Do Not Configure"),
+ "kmrml_ask_configure_gift" )
+ == KMessageBox::Yes )
+ {
+ KApplication::kdeinitExec( "kcmshell",
+ QString::fromLatin1("kcmkmrml"));
+ setStatus( NeedCollection );
+ return false;
+ }
+ }
+ }
+
+
+ if ( !downloadList.isEmpty() )
+ downloadReferenceFiles( downloadList );
+ else
+ contactServer( m_url );
+
+ return true;
+}
+
+void MrmlPart::contactServer( const KURL& url )
+{
+ m_job = transferJob( url );
+
+ m_job->addMetaData( MrmlShared::kio_task(), MrmlShared::kio_initialize() );
+
+ QString host = url.host().isEmpty() ?
+ QString::fromLatin1("localhost") : url.host();
+
+ slotSetStatusBar( i18n("Connecting to indexing server at %1...").arg( host ));
+}
+
+//
+// schedules a download all urls of downloadList (all remote and wellformed)
+// No other downloads are running (closeURL() has been called before)
+//
+void MrmlPart::downloadReferenceFiles( const KURL::List& downloadList )
+{
+ assert( m_downloadJobs.isEmpty() );
+
+ KURL::List::ConstIterator it = downloadList.begin();
+ for ( ; it != downloadList.end(); it++ )
+ {
+ QString extension;
+ int index = (*it).fileName().findRev( '.' );
+ if ( index != -1 )
+ extension = (*it).fileName().mid( index );
+
+ KTempFile tmpFile( QString::null, extension );
+ if ( tmpFile.status() != 0 )
+ {
+ kdWarning() << "Can't create temporary file, skipping: " << *it << endl;
+
+ continue;
+ }
+
+ m_tempFiles.append( tmpFile.name() );
+ KURL destURL;
+ destURL.setPath( tmpFile.name() );
+
+ KIO::FileCopyJob *job = KIO::file_copy( *it, destURL, -1,
+ true /* overwrite tmpfile */ );
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotDownloadResult( KIO::Job * ) ));
+ m_downloadJobs.append( job );
+ // ### should this be only called for one job?
+ emit started( job );
+ }
+
+ if ( !m_downloadJobs.isEmpty() )
+ slotSetStatusBar( i18n("Downloading reference files...") );
+ else // probably never happens
+ contactServer( m_url );
+}
+
+bool MrmlPart::closeURL()
+{
+ m_view->stopDownloads();
+ m_view->clear();
+
+ QPtrListIterator<KIO::FileCopyJob> it( m_downloadJobs );
+ for ( ; it.current(); ++it )
+ it.current()->kill();
+ m_downloadJobs.clear();
+
+ QStringList::Iterator tit = m_tempFiles.begin();
+ for ( ; tit != m_tempFiles.end(); ++tit )
+ QFile::remove( *tit );
+ m_tempFiles.clear();
+
+ if ( m_job ) {
+ m_job->kill();
+ m_job = 0L;
+ }
+
+ setStatus( NeedCollection );
+
+ return true;
+}
+
+KIO::TransferJob * MrmlPart::transferJob( const KURL& url )
+{
+ KIO::TransferJob *job = KIO::get( url, true, false ); // reload, no gui
+ job->setAutoErrorHandlingEnabled( true, m_view );
+ connect( job, SIGNAL( result( KIO::Job * )),
+ SLOT( slotResult( KIO::Job * )));
+ connect( job, SIGNAL( data( KIO::Job *, const QByteArray& )),
+ SLOT( slotData( KIO::Job *, const QByteArray& )));
+
+// ###
+// connect( job, SIGNAL( infoMessage( KIO::Job *, const QString& )),
+// SLOT( slotResult( KIO::Job *, const QString& )));
+
+ job->setWindow( widget() );
+ if ( !m_sessionId.isEmpty() )
+ job->addMetaData( MrmlShared::sessionId(), m_sessionId );
+
+ emit started( job );
+ emit setWindowCaption( url.prettyURL() );
+ setStatus( InProgress );
+
+ return job;
+}
+
+void MrmlPart::slotResult( KIO::Job *job )
+{
+ if ( job == m_job )
+ m_job = 0L;
+
+ slotSetStatusBar( QString::null );
+
+ if ( !job->error() )
+ emit completed();
+ else {
+ emit canceled( job->errorString() );
+// qDebug("*** canceled: error: %s", job->errorString().latin1());
+ }
+
+
+ bool auto_random = m_view->isEmpty() && m_queryList.isEmpty();
+ m_random->setChecked( auto_random );
+ m_random->setEnabled( !auto_random );
+ setStatus( job->error() ? NeedCollection : CanSearch );
+
+ if ( !job->error() && !m_queryList.isEmpty() ) {
+ // we have a connection and we got a list of relevant URLs to query for
+ // (via the URL)
+
+ createQuery( &m_queryList );
+ m_queryList.clear();
+ }
+}
+
+// ### when user cancels download, we crash :(
+void MrmlPart::slotDownloadResult( KIO::Job *job )
+{
+ assert( job->inherits( "KIO::FileCopyJob" ) );
+ KIO::FileCopyJob *copyJob = static_cast<KIO::FileCopyJob*>( job );
+
+ if ( !copyJob->error() )
+ m_queryList.append( copyJob->destURL() );
+
+ m_downloadJobs.removeRef( copyJob );
+
+ if ( m_downloadJobs.isEmpty() ) // finally, we can start the query!
+ {
+ if ( m_queryList.isEmpty() ) // rather unlikely, but could happen ;)
+ {
+ kdWarning() << "Couldn't download the reference files. Will start a random search now" << endl;
+ }
+
+ contactServer( m_url );
+ }
+}
+
+// mrml-document in the bytearray
+void MrmlPart::slotData( KIO::Job *, const QByteArray& data )
+{
+ if ( data.isEmpty() )
+ return;
+
+ QDomDocument doc;
+ doc.setContent( data );
+
+ if ( !doc.isNull() )
+ parseMrml( doc );
+}
+
+void MrmlPart::parseMrml( QDomDocument& doc )
+{
+ QDomNode mrml = doc.documentElement(); // root element
+ if ( !mrml.isNull() ) {
+ QDomNode child = mrml.firstChild();
+ for ( ; !child.isNull(); child = child.nextSibling() ) {
+// qDebug("**** HERE %s", child.nodeName().latin1());
+ if ( child.isElement() ) {
+ QDomElement elem = child.toElement();
+
+ QString tagName = elem.tagName();
+
+ if ( tagName == "acknowledge-session-op" )
+ m_sessionId = elem.attribute( MrmlShared::sessionId() );
+
+ else if ( tagName == MrmlShared::algorithmList() ) {
+ initAlgorithms( elem );
+ }
+
+ else if ( tagName == MrmlShared::collectionList() ) {
+ initCollections( elem );
+ }
+
+ else if ( tagName == "error" ) {
+ KMessageBox::information( widget(),
+ i18n("Server returned error:\n%1\n")
+ .arg( elem.attribute( "message" )),
+ i18n("Server Error") );
+ }
+
+ else if ( tagName == "query-result" ) {
+ m_view->clear();
+ parseQueryResult( elem );
+ }
+
+
+ } // child.isElement()
+ }
+ } // !mrml.isNull()
+}
+
+void MrmlPart::parseQueryResult( QDomElement& queryResult )
+{
+ QDomNode child = queryResult.firstChild();
+ for ( ; !child.isNull(); child = child.nextSibling() ) {
+ if ( child.isElement() ) {
+ QDomElement elem = child.toElement();
+ QString tagName = elem.tagName();
+
+ if ( tagName == "query-result-element-list" ) {
+ QValueList<QDomElement> list =
+ KMrml::directChildElements( elem, "query-result-element" );
+
+ QValueListConstIterator<QDomElement> it = list.begin();
+ for ( ; it != list.end(); ++it )
+ {
+ QDomNamedNodeMap a = (*it).attributes();
+ m_view->addItem( KURL( (*it).attribute("image-location" ) ),
+ KURL( (*it).attribute("thumbnail-location" ) ),
+ (*it).attribute("calculated-similarity"));
+
+ }
+ }
+
+ else if ( tagName == "query-result" )
+ parseQueryResult( elem );
+ }
+ }
+}
+
+// creates/stops the query when the Start/Stop button was pressed
+void MrmlPart::slotStartClicked()
+{
+ if ( m_status == InProgress )
+ {
+ closeURL();
+ m_startButton->setText( i18n("&Search" ) );
+ return;
+ }
+
+ // we need to reconnect, if the initial openURL() didn't work due to
+ // the gift not being available.
+ if ( m_status == NeedCollection )
+ {
+ openURL( m_url );
+ return;
+ }
+
+ // cut off an eventual query and reference from the url, when the user
+ // performs a real query (otherwise restoreState() would restore and
+ // re-do the query from the URL
+ m_url.setRef( QString::null );
+ m_url.setQuery( QString::null );
+
+ createQuery();
+ m_browser->openURLNotify();
+}
+
+//
+// relevantItems is 0L when called from slotStartClicked() and set to a
+// non-empty list when called initially, from the commandline.
+//
+void MrmlPart::createQuery( const KURL::List * relevantItems )
+{
+ if ( relevantItems && relevantItems->isEmpty() )
+ return;
+
+ QDomDocument doc( "mrml" );
+ QDomElement mrml = MrmlCreator::createMrml( doc,
+ sessionId(),
+ transactionId() );
+
+ Collection coll = currentCollection();
+// qDebug("** collection: name: %s, id: %s, valid: %i", coll.name().latin1(), coll.id().latin1(), coll.isValid());
+ Algorithm algo = firstAlgorithmForCollection( coll );
+// qDebug("** algorithm: name: %s, id: %s, valid: %i, collection-id: %s", algo.name().latin1(), algo.id().latin1(), algo.isValid(), algo.collectionId().latin1());
+
+ if ( algo.isValid() )
+ {
+ MrmlCreator::configureSession( mrml, algo, sessionId() );
+ }
+
+ QDomElement query = MrmlCreator::addQuery( mrml,
+ m_resultSizeInput->value() );
+ if ( algo.isValid() )
+ query.setAttribute( MrmlShared::algorithmId(), algo.id() );
+
+ // ### result-cutoff, query-type?
+
+ // start-up with/without urls on the commandline via mrmlsearch
+ if ( relevantItems )
+ {
+ QDomElement elem = MrmlCreator::addRelevanceList( query );
+ KURL::List::ConstIterator it = relevantItems->begin();
+ for ( ; it != relevantItems->end(); ++it )
+ MrmlCreator::createRelevanceElement( doc, elem, (*it).url(),
+ MrmlCreator::Relevant );
+ }
+
+ // get relevant items from the view? Only do this when relevantItems is 0L
+ else if ( !m_random->isChecked() )
+ {
+ QDomElement relevants = MrmlCreator::addRelevanceList( query );
+ m_view->addRelevanceToQuery( doc, relevants );
+ }
+
+ performQuery( doc );
+}
+
+Collection MrmlPart::currentCollection() const
+{
+ return m_collectionCombo->current();
+}
+
+Algorithm MrmlPart::firstAlgorithmForCollection( const Collection& coll ) const
+{
+ if ( !m_algorithms.isEmpty() )
+ {
+ AlgorithmList::ConstIterator it = m_algorithms.begin();
+ for ( ; it != m_algorithms.end(); ++it )
+ {
+ Algorithm algo = *it;
+ if ( algo.paradigms().matches( coll.paradigms() ) )
+ {
+ algo.setCollectionId( coll.id() );
+ return algo;
+ }
+ }
+ }
+
+ qDebug("#################### -> ADEFAULT!");
+ Algorithm algo = Algorithm::defaultAlgorithm();
+ algo.setCollectionId( coll.id() );
+ return algo;
+}
+
+// emits the given QDomDocument for eventual plugins, checks after that
+// if there are any relevance elements. If there are none, random search is
+// implied and performed.
+// finally, the search is actually started
+void MrmlPart::performQuery( QDomDocument& doc )
+{
+ QDomElement mrml = doc.documentElement();
+
+ emit aboutToStartQuery( doc ); // let plugins play with it :)
+
+ // no items available? All "neutral"? -> random search
+
+ QDomElement queryStep = KMrml::firstChildElement( mrml, "query-step" );
+ bool randomSearch = false;
+
+ if ( !queryStep.isNull() )
+ {
+ QDomElement relevanceList =
+ KMrml::firstChildElement(queryStep, "user-relevance-element-list");
+ QValueList<QDomElement> relevanceElements =
+ KMrml::directChildElements( relevanceList,
+ "user-relevance-element" );
+
+ randomSearch = relevanceElements.isEmpty();
+
+ if ( randomSearch )
+ {
+ m_random->setChecked( true );
+ m_random->setEnabled( false );
+ queryStep.setAttribute("query-type", "at-random");
+
+ // remove user-relevance-element-list element for random search
+ relevanceList.parentNode().removeChild( relevanceList );
+ }
+ }
+ else
+ {
+ KMessageBox::error( m_view, i18n("Error formulating the query. The "
+ "\"query-step\" element is missing."),
+ i18n("Query Error") );
+ }
+
+ m_job = transferJob( url() );
+ slotSetStatusBar( randomSearch ? i18n("Random search...") :
+ i18n("Searching...") );
+ m_job->addMetaData( MrmlShared::kio_task(), MrmlShared::kio_startQuery() );
+ qDebug("\n\nSending XML:\n%s", doc.toString().latin1());
+ m_job->addMetaData( MrmlShared::mrml_data(), doc.toString() );
+}
+
+void MrmlPart::slotSetStatusBar( const QString& text )
+{
+ if ( text.isEmpty() )
+ emit setStatusBarText( i18n("Ready.") );
+ else
+ emit setStatusBarText( text );
+}
+
+void MrmlPart::slotActivated( const KURL& url, ButtonState button )
+{
+ if ( button == LeftButton )
+ emit m_browser->openURLRequest( url );
+ else if ( button == MidButton )
+ emit m_browser->createNewWindow( url );
+ else if ( button == RightButton ) {
+ // enableExtensionActions( url, true ); // for now
+ emit m_browser->popupMenu( QCursor::pos(), url, QString::null );
+ // enableExtensionActions( url, false );
+ }
+}
+
+void MrmlPart::enableExtensionActions( const KURL& url, bool enable )
+{
+ bool del = KProtocolInfo::supportsDeleting( url );
+ emit m_browser->enableAction( "copy", enable );
+ emit m_browser->enableAction( "trash", del );
+ emit m_browser->enableAction( "del", del );
+ emit m_browser->enableAction( "shred", url.isLocalFile() );
+ emit m_browser->enableAction( "properties", enable );
+ // emit m_browser->enableAction( "print", enable ); // ### later
+}
+
+
+// only implemented because it's abstract in the baseclass
+bool MrmlPart::openFile()
+{
+ return false;
+}
+
+void MrmlPart::slotConfigureAlgorithm()
+{
+ m_algoButton->setEnabled( false );
+
+ m_algoConfig = new AlgorithmDialog( m_algorithms, m_collections,
+ currentCollection(),
+ m_view, "algorithm configuration" );
+ connect( m_algoConfig, SIGNAL( applyClicked() ),
+ SLOT( slotApplyAlgoConfig() ));
+ connect( m_algoConfig, SIGNAL( finished() ),
+ SLOT( slotAlgoConfigFinished() ));
+
+ m_algoConfig->show();
+}
+
+void MrmlPart::slotApplyAlgoConfig()
+{
+ // ###
+}
+
+void MrmlPart::slotAlgoConfigFinished()
+{
+ if ( m_algoConfig->result() == QDialog::Accepted )
+ slotApplyAlgoConfig();
+
+ m_algoButton->setEnabled( true );
+ m_algoConfig->deleteLater();
+ m_algoConfig = 0L;
+}
+
+void MrmlPart::initHostCombo()
+{
+ m_hostCombo->clear();
+ m_hostCombo->insertStringList( m_config.hosts() );
+}
+
+void MrmlPart::slotHostComboActivated( const QString& host )
+{
+ ServerSettings settings = m_config.settingsForHost( host );
+ openURL( settings.getUrl() );
+}
+
+void MrmlPart::setStatus( Status status )
+{
+ switch ( status )
+ {
+ case NeedCollection:
+ m_startButton->setText( i18n("&Connect") );
+ break;
+ case CanSearch:
+ m_startButton->setText( i18n("&Search") );
+ break;
+ case InProgress:
+ m_startButton->setText( i18n("Sto&p") );
+ break;
+ };
+
+ m_status = status;
+}
+
+
+void MrmlPart::saveState( QDataStream& stream )
+{
+ stream << url();
+ stream << m_sessionId;
+ stream << m_queryList;
+// stream << m_algorithms;
+// stream << m_collections;
+
+ stream << m_resultSizeInput->value();
+ stream << *m_collectionCombo;
+
+ m_view->saveState( stream );
+}
+
+void MrmlPart::restoreState( QDataStream& stream )
+{
+ KURL url;
+ stream >> url;
+
+ stream >> m_sessionId;
+ stream >> m_queryList;
+// stream >> m_algorithms;
+// stream >> m_collections;
+
+ int resultSize;
+ stream >> resultSize;
+ m_resultSizeInput->setValue( resultSize );
+ stream >> *m_collectionCombo;
+
+ m_view->restoreState( stream );
+
+// openURL( url );
+ m_url = url;
+}
+
+KAboutData * MrmlPart::createAboutData()
+{
+ KAboutData *data = new KAboutData(
+ "kmrml",
+ I18N_NOOP("MRML Client for KDE"),
+ KMRML_VERSION,
+ I18N_NOOP("A tool to search for images by their content"),
+ KAboutData::License_GPL,
+ I18N_NOOP("(c) 2001-2002, Carsten Pfeiffer"),
+ 0,
+ I18N_NOOP("http://devel-home.kde.org/~pfeiffer/kmrml/") );
+
+ data->addAuthor( "Carsten Pfeiffer",
+ I18N_NOOP("Developer, Maintainer"),
+ "pfeiffer@kde.org" );
+ data->addCredit( "Wolfgang Mller",
+ I18N_NOOP("Developer of the GIFT, Helping Hand") );
+
+ return data;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+#include "mrml_part.moc"
diff --git a/kmrml/kmrml/mrml_part.desktop b/kmrml/kmrml/mrml_part.desktop
new file mode 100644
index 00000000..90017794
--- /dev/null
+++ b/kmrml/kmrml/mrml_part.desktop
@@ -0,0 +1,67 @@
+[Desktop Entry]
+Type=Service
+Exec=blahfoo
+Name=MRML View
+Name[ar]=برنامج MRML View
+Name[br]=Gwel MRML
+Name[ca]=Vista MRML
+Name[cs]=MRML pohled
+Name[cy]=Gwelydd MRML
+Name[da]=MRML-visning
+Name[de]=MRML-Ansicht
+Name[el]=Προβολή MRML
+Name[eo]=MRML-Rigardo
+Name[es]=Vista de MRML
+Name[et]=MRML vaade
+Name[eu]=MRML ikuspegia
+Name[fa]=نمای MRML
+Name[fi]=MRML-näkymä
+Name[fr]=Affichage MRML
+Name[ga]=Amharc MRML
+Name[gl]=Visor MRML
+Name[he]=תצוגת MRML
+Name[hi]=MRML दृश्य
+Name[hu]=MRML-nézet
+Name[is]=MRML sýn
+Name[it]=Visione MRML
+Name[ja]=MRML ビュー
+Name[kk]=MRML файлдарды қарау
+Name[km]=ទិដ្ឋភាព MRML
+Name[lt]=MRML peržiūra
+Name[ms]=Paparan MRML
+Name[nds]=MRML-Ansicht
+Name[ne]=MRML दृश्य
+Name[nl]=MRML-weergave
+Name[nso]=Pono ya MRML
+Name[pa]=MRML ਝਲਕ
+Name[pl]=Widok MRML
+Name[pt]=Janela de MRML
+Name[pt_BR]=Visualização de MRML
+Name[ro]=Vizualizare MRML
+Name[ru]=Просмотр MRML
+Name[se]=MRML-čájeheapmi
+Name[sk]=Prehliadač MRML
+Name[sl]=Pregledovalnik MRML
+Name[sr]=MRML приказивач
+Name[sr@Latn]=MRML prikazivač
+Name[ta]=MRML காட்சி
+Name[tg]=Намоиши MRML
+Name[th]=ดู MRML
+Name[tr]=MRML Görünümü
+Name[uk]=Перегляд MRML
+Name[ven]=Mbonalelo ya MRML
+Name[xh]=MRML Imbono
+Name[zh_CN]=MRML 查看器
+Name[zh_HK]=MRML 檢視
+Name[zh_TW]=MRML 檢視器
+Name[zu]=Umbukiso we-MRML
+MimeType=text/mrml
+ServiceTypes=KParts/ReadOnlyPart
+X-KDE-Library=libkmrmlpart
+#X-KDE-BrowserView-AllowAsDefault=true
+#X-KDE-BrowserView-HideFromMenus=true
+#X-KDE-BrowserView-Args=IconView
+#X-KDE-BrowserView-ModeProperty=viewMode
+#X-KDE-BrowserView-ModePropertyValue=IconView
+Icon=view_icon
+InitialPreference=10
diff --git a/kmrml/kmrml/mrml_part.h b/kmrml/kmrml/mrml_part.h
new file mode 100644
index 00000000..110d290a
--- /dev/null
+++ b/kmrml/kmrml/mrml_part.h
@@ -0,0 +1,175 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MRMLPART_H
+#define MRMLPART_H
+
+#include <qcstring.h>
+#include <qstringlist.h>
+
+#include <kurl.h>
+#include <kparts/factory.h>
+#include <kparts/part.h>
+
+#include <kmrml_config.h>
+
+#include "mrml_elements.h"
+
+class QCheckBox;
+class QHGroupBox;
+class QPushButton;
+
+class KAboutData;
+class KComboBox;
+class KIntNumInput;
+
+namespace KIO {
+ class FileCopyJob;
+ class TransferJob;
+}
+
+namespace KMrml
+{
+
+class AlgorithmDialog;
+class Browser;
+class CollectionCombo;
+class MrmlView;
+
+class MrmlPart : public KParts::ReadOnlyPart
+{
+ Q_OBJECT
+
+public:
+ enum Status { NeedCollection, CanSearch, InProgress };
+
+ MrmlPart( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name, const QStringList& args );
+ ~MrmlPart();
+
+ QString sessionId() const { return m_sessionId; }
+ QString transactionId() const { return QString::null; } // ###
+
+ void saveState( QDataStream& stream );
+ void restoreState( QDataStream& stream );
+
+ static KAboutData *createAboutData();
+
+public slots:
+ virtual bool openURL( const KURL& );
+ virtual bool closeURL();
+
+ void slotActivated( const KURL& url, ButtonState );
+
+protected:
+ virtual bool openFile();
+ Algorithm firstAlgorithmForCollection( const Collection& coll ) const;
+ Collection currentCollection() const;
+
+signals:
+ /**
+ * allow plugins to extend the query
+ */
+ void aboutToStartQuery( QDomDocument& );
+
+private slots:
+ void slotStartClicked();
+ void slotSetStatusBar( const QString& );
+ void slotSetStatusBar( const KURL& url ) { slotSetStatusBar( url.prettyURL() ); }
+ void slotHostComboActivated( const QString& );
+
+ void slotResult( KIO::Job * );
+ void slotData( KIO::Job *, const QByteArray& );
+
+ void slotDownloadResult( KIO::Job * );
+
+ void slotConfigureAlgorithm();
+ void slotApplyAlgoConfig();
+ void slotAlgoConfigFinished();
+
+private:
+ void createQuery( const KURL::List * relevantItems = 0L );
+ void initCollections( const QDomElement& );
+ void initAlgorithms( const QDomElement& );
+ void performQuery( QDomDocument& doc );
+ void parseMrml( QDomDocument& doc );
+ void parseQueryResult( QDomElement& );
+ void enableExtensionActions( const KURL& url, bool enable );
+ KIO::TransferJob * transferJob( const KURL& url );
+
+ void initHostCombo();
+ void enableServerDependentWidgets( bool enable );
+
+ void setStatus( Status status );
+
+ void contactServer( const KURL& url );
+ void downloadReferenceFiles( const KURL::List& downloadList );
+
+ KIO::TransferJob *m_job;
+ MrmlView *m_view;
+ Config m_config;
+ KIntNumInput * m_resultSizeInput;
+ CollectionCombo * m_collectionCombo;
+ QPushButton *m_algoButton;
+ QHGroupBox *m_panel;
+ QPushButton *m_startButton;
+ QCheckBox *m_random;
+ Browser *m_browser;
+ AlgorithmDialog *m_algoConfig;
+ KComboBox *m_hostCombo;
+
+ QPtrList<KIO::FileCopyJob> m_downloadJobs;
+ QStringList m_tempFiles;
+
+ QString m_sessionId;
+ KURL::List m_queryList; // a list of valid LOCAL (!) urls to query for
+
+ CollectionList m_collections;
+ AlgorithmList m_algorithms;
+
+ Status m_status;
+ static uint s_sessionId;
+
+};
+
+class PartFactory : public KParts::Factory
+{
+ Q_OBJECT
+
+public:
+ PartFactory();
+ ~PartFactory();
+
+ static KInstance * instance();
+
+protected:
+ virtual KParts::Part * createPartObject( QWidget *parentWidget = 0,
+ const char *widgetName = 0,
+ QObject *parent = 0,
+ const char *name = 0,
+ const char *classname = "KParts::Part",
+ const QStringList& args = QStringList() );
+
+private:
+ static KInstance * s_instance;
+
+};
+
+}
+
+#endif // MRMLPART_H
diff --git a/kmrml/kmrml/mrml_view.cpp b/kmrml/kmrml/mrml_view.cpp
new file mode 100644
index 00000000..71f3c741
--- /dev/null
+++ b/kmrml/kmrml/mrml_view.cpp
@@ -0,0 +1,480 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qdom.h>
+#include <qlabel.h>
+#include <qpainter.h>
+#include <qtimer.h>
+#include <qtooltip.h>
+
+#include <kcursor.h>
+#include <kdatastream.h>
+#include <klocale.h>
+#include <kcombobox.h>
+#include <kmimetype.h>
+#include <kurl.h>
+#include <kurldrag.h>
+
+#include "loader.h"
+#include "mrml_creator.h"
+#include "mrml_view.h"
+
+using namespace KMrml;
+
+MrmlView::MrmlView( QWidget *parent, const char *name )
+ : QScrollView( parent, name )
+{
+ setStaticBackground( true );
+ setResizePolicy( Manual );
+ setHScrollBarMode( AlwaysOff );
+ enableClipper( true ); // ### test this
+
+ m_items.setAutoDelete( true );
+
+ connect( Loader::self(), SIGNAL( finished(const KURL&, const QByteArray&)),
+ SLOT( slotDownloadFinished( const KURL&, const QByteArray& )));
+
+ m_timer = new QTimer( this );
+ connect( m_timer, SIGNAL( timeout() ), SLOT( slotLayout() ));
+
+ // we need a pixmap to be shown when no thumbnail is available for a
+ // query result image
+ QLabel l( i18n( "No thumbnail available" ), 0L );
+ l.setFixedSize( 80, 80 );
+ l.setAlignment( WordBreak | AlignCenter );
+// l.setFrameStyle( QLabel::Box | QLabel::Plain );
+// l.setLineWidth( 1 );
+ l.setPaletteBackgroundColor( Qt::white );
+ l.setPaletteForegroundColor( Qt::black );
+ m_unavailablePixmap = QPixmap::grabWidget( &l );
+}
+
+MrmlView::~MrmlView()
+{
+}
+
+MrmlViewItem * MrmlView::addItem( const KURL& url, const KURL& thumbURL,
+ const QString& similarity )
+{
+ bool ok;
+ double value = similarity.toDouble( &ok );
+ if ( !ok || value < 0.05 )
+ return 0L;
+
+ return addItem( url, thumbURL, value );
+}
+
+MrmlViewItem * MrmlView::addItem( const KURL& url, const KURL& thumbURL,
+ double similarity )
+{
+ if ( !url.isValid() ) {
+ qWarning( "MrmlPart: received malformed URL from query: %s",
+ url.prettyURL().isNull() ? "(null)" : url.prettyURL().latin1() );
+ return 0L;
+ }
+
+// qDebug("** url: %s", thumbURL.url().latin1());
+
+ MrmlViewItem *item = new MrmlViewItem( url, thumbURL, similarity, this );
+ QPixmap *pixmap = getPixmap( thumbURL );
+ if ( pixmap )
+ item->setPixmap( *pixmap );
+
+ m_items.append( item );
+
+ m_timer->start( 0, true );
+ return item;
+}
+
+void MrmlView::addRelevanceToQuery( QDomDocument& document,
+ QDomElement& parent )
+{
+ QPtrListIterator<MrmlViewItem> it( m_items );
+ for( ; it.current(); ++it ) {
+ it.current()->createRelevanceElement( document, parent );
+ }
+}
+
+void MrmlView::clear()
+{
+ m_items.clear(); // items are deleted and removed from scrollview
+ setContentsPos( 0, 0 );
+}
+
+QPixmap * MrmlView::getPixmap( const KURL& url )
+{
+ QString u = url.url();
+ QPixmap *pix = m_pixmapCache.find( u );
+ if ( pix )
+ return pix;
+
+ if ( url.isLocalFile() ) {
+ QPixmap p;
+ if ( !p.load( url.path() ) )
+ p = m_unavailablePixmap;
+
+ m_pixmapCache.insert( u, p );
+ return m_pixmapCache.find( u );
+ }
+ else { // remote url, download with KIO
+ Loader::self()->requestDownload( url );
+ }
+
+ return 0L;
+}
+
+void MrmlView::slotDownloadFinished( const KURL& url, const QByteArray& data )
+{
+ QPtrListIterator<MrmlViewItem> it( m_items );
+ for( ; it.current(); ++it ) {
+ MrmlViewItem *item = it.current();
+ if ( item->thumbURL() == url )
+ {
+ QPixmap p;
+ if ( data.isEmpty() || !p.loadFromData( data ) )
+ p = m_unavailablePixmap;
+
+ m_pixmapCache.insert( url.url(), p );
+ item->setPixmap( p );
+
+ slotLayout();
+ return;
+ }
+ }
+}
+
+void MrmlView::stopDownloads()
+{
+ Loader *loader = Loader::self();
+ QPtrListIterator<MrmlViewItem> it( m_items );
+ for( ; it.current(); ++it ) {
+ MrmlViewItem *item = it.current();
+ if ( !item->hasRemotePixmap() )
+ loader->removeDownload( item->url() );
+ }
+}
+
+void MrmlView::slotLayout()
+{
+ int itemWidth = 0;
+ QPtrListIterator<MrmlViewItem> it( m_items );
+
+ for ( ; it.current(); ++it ) {
+ itemWidth = QMAX( itemWidth, it.current()->sizeHint().width() );
+ }
+
+ if ( itemWidth == 0 )
+ return;
+
+
+ uint itemsPerRow = visibleWidth() / itemWidth;
+ int margin = (visibleWidth() - (itemsPerRow * itemWidth)) / 2;
+ int rowHeight = 0;
+ uint item = 0;
+ uint y = 5;
+
+ // pointing to the first item of a row
+ QPtrListIterator<MrmlViewItem> rowIt( m_items );
+
+ for ( it.toFirst(); it.current(); ++it ) {
+ if ( item >= itemsPerRow ) {
+ item = 0;
+ y += rowHeight;
+ rowHeight = 0;
+ }
+
+ if ( item == 0 )
+ rowIt = it;
+
+ rowHeight = QMAX( rowHeight, it.current()->sizeHint().height() );
+ addChild( it.current(), margin + item * itemWidth, y );
+ it.current()->show();
+
+ item++;
+
+ // resize all items of the current row so they all have the same size
+ if ( item >= itemsPerRow || it.atLast() )
+ {
+ for ( uint i = 0; (i < itemsPerRow && rowIt.current()); i++ )
+ {
+ rowIt.current()->resize( itemWidth, rowHeight );
+ ++rowIt;
+ }
+ }
+ }
+
+ resizeContents( visibleWidth(), y + rowHeight );
+}
+
+void MrmlView::resizeEvent( QResizeEvent *e )
+{
+ int oldW = visibleWidth();
+ QScrollView::resizeEvent( e );
+
+ if ( visibleWidth() != oldW )
+ slotLayout();
+}
+
+void MrmlView::saveState( QDataStream& stream )
+{
+ stream << m_items.count();
+ QPtrListIterator<MrmlViewItem> it( m_items );
+ for( ; it.current(); ++it ) {
+ stream << *it.current();
+ }
+
+}
+
+void MrmlView::restoreState( QDataStream& stream )
+{
+ stopDownloads();
+ clear();
+
+ int count;
+ stream >> count;
+
+ KURL url, thumbURL;
+ double similarity;
+ Q_UINT32 relevance;
+ MrmlViewItem *item;
+
+
+ for ( int i = 0; i < count; i++ )
+ {
+ stream >> url;
+ stream >> thumbURL;
+ stream >> similarity;
+ stream >> relevance;
+
+ item = addItem( url, thumbURL, similarity );
+ if ( item )
+ item->setRelevance( (MrmlViewItem::Relevance) relevance );
+ }
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream,
+ const KMrml::MrmlViewItem& item )
+{
+ return stream << item.url()
+ << item.thumbURL()
+ << item.similarity()
+ << static_cast<Q_UINT32>( item.relevance() );
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+MrmlViewItem::MrmlViewItem( const KURL& url, const KURL& thumbURL,
+ double similarity, MrmlView *view,
+ const char *name )
+ : QFrame( view->viewport() , name ),
+ m_view( view ),
+ m_url( url ),
+ m_thumbURL( thumbURL ),
+ similarityFullWidth( 120 ), // ###
+ m_hasRemotePixmap( false )
+{
+ if ( m_similarity != -1 )
+ m_similarity = QMAX( 0.0, QMIN( 1.0, similarity ));
+ setFrameStyle( Panel | Sunken );
+ setMouseTracking( true );
+
+ m_combo = new KComboBox( this );
+ QToolTip::add( m_combo, i18n("You can refine queries by giving feedback about the current result and pressing the Search button again.") );
+ m_combo->insertItem( i18n("Relevant"), Relevant );
+ m_combo->insertItem( i18n("Neutral"), Neutral );
+ m_combo->insertItem( i18n("Irrelevant"), Irrelevant );
+ m_combo->adjustSize();
+ m_combo->setCurrentItem( Neutral );
+
+ /*
+ if ( similarity > -1 )
+ QToolTip::add( this, QString::fromLatin1("<qt>%1<br>%1</qt>")
+ .arg( url )
+ .arg(i18n("Similarity: %1").arg( QString::number(similarity))));
+ else
+ QToolTip::add( this, QString::fromLatin1("<qt>%1</qt>").arg( url ) );
+ */
+
+ setMinimumSize( 130, 130 ); // ###
+}
+
+MrmlViewItem::~MrmlViewItem()
+{
+}
+
+void MrmlViewItem::setPixmap( const QPixmap& pix )
+{
+ if ( !m_url.isLocalFile() )
+ m_hasRemotePixmap = true;
+
+ m_pixmap = pix;
+ adjustSize();
+ update();
+}
+
+void MrmlViewItem::paintEvent( QPaintEvent *e )
+{
+ QFrame::paintEvent( e );
+
+ if ( !m_pixmap.isNull() ) {
+ bitBlt( this, pixmapX(), pixmapY(),
+ &m_pixmap, 0, 0, m_pixmap.width(), m_pixmap.height(),
+ CopyROP );
+ }
+
+ if ( m_similarity >= 0 ) {
+ QPainter p( this );
+ QPen pen( colorGroup().highlight(), 1, QPen::SolidLine );
+ p.setPen( pen );
+ int x = margin;
+ int y = m_combo->y() - similarityHeight - 2;
+ int w = (int) (similarityFullWidth * m_similarity);
+ int h = similarityHeight;
+ p.drawRect( x, y, similarityFullWidth, h );
+ p.fillRect( x, y, w, h, colorGroup().highlight() );
+ }
+}
+
+void MrmlViewItem::resizeEvent( QResizeEvent *e )
+{
+ QFrame::resizeEvent( e );
+
+ int y = height() - m_combo->height() - margin;
+ m_combo->move( width()/2 - m_combo->width()/2, y );
+}
+
+QSize MrmlViewItem::sizeHint() const
+{
+ int w = QMAX( QMAX(minimumHeight(), m_combo->width()), m_pixmap.width() );
+ w += 2 * margin;
+
+ int h = m_pixmap.isNull() ? margin : margin + spacing + m_pixmap.height();
+ h += (m_similarity > -1) ? similarityHeight + spacing : 0;
+ h += m_combo->height() + margin;
+
+ return QSize( w, h );
+}
+
+void MrmlViewItem::mousePressEvent( QMouseEvent *e )
+{
+ QFrame::mousePressEvent( e );
+ pressedPos.setX( 0 );
+ pressedPos.setY( 0 );
+
+
+ if ( e->button() == LeftButton || e->button() == MidButton ) {
+ if ( hitsPixmap( e->pos() ) )
+ pressedPos = e->pos();
+ }
+ else if ( e->button() == RightButton && hitsPixmap( e->pos() ) )
+ emit view()->activated( m_url, e->button() );
+}
+
+void MrmlViewItem::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( hitsPixmap( e->pos() ) ) {
+ if ( !ownCursor() ) { // nice hacklet :)
+ setCursor( KCursor::handCursor() );
+ emit view()->onItem( m_url );
+ }
+ }
+ else {
+ if ( ownCursor() ) {
+ unsetCursor();
+ emit view()->onItem( KURL() );
+ }
+ }
+
+ if ( (e->state() & LeftButton) && !pressedPos.isNull() ) {
+ QPoint dist = e->pos() - pressedPos;
+ if ( dist.manhattanLength() > KGlobalSettings::dndEventDelay() ) {
+ // start drag here
+ KURL::List urls;
+ // ### support multiple files?
+ urls.append( m_url );
+ KURLDrag *drag = new KURLDrag( urls, this );
+ drag->setPixmap( KMimeType::pixmapForURL( m_url ) );
+ drag->drag();
+ }
+ }
+}
+
+void MrmlViewItem::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( hitsPixmap( e->pos() )) {
+ QPoint dist = e->pos() - pressedPos;
+ if ( dist.manhattanLength() < KGlobalSettings::dndEventDelay() ) {
+ emit view()->activated( m_url, e->button() );
+ }
+ }
+}
+
+bool MrmlViewItem::hitsPixmap( const QPoint& pos ) const
+{
+ if ( m_pixmap.isNull() )
+ return false;
+
+ if ( pos.x() > pixmapX() && pos.x() < pixmapX() + m_pixmap.width() &&
+ pos.y() > pixmapY() && pos.y() < pixmapY() + m_pixmap.height() )
+ return true;
+ return false;
+}
+
+void MrmlViewItem::createRelevanceElement( QDomDocument& document,
+ QDomElement& parent )
+{
+ int rel = m_combo->currentItem();
+ if ( rel == Neutral )
+ return;
+
+ MrmlCreator::createRelevanceElement( document, parent, m_url.url(),
+ (rel == Relevant) ? MrmlCreator::Relevant : MrmlCreator::Irrelevant );
+}
+
+MrmlViewItem::Relevance MrmlViewItem::relevance() const
+{
+ return (Relevance) m_combo->currentItem();
+}
+
+void MrmlViewItem::setRelevance( Relevance relevance )
+{
+ m_combo->setCurrentItem( relevance );
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+int MrmlViewItemList::compareItems( QPtrCollection::Item item1,
+ QPtrCollection::Item item2 )
+{
+ double s1 = (static_cast<MrmlViewItem*>( item1 ))->similarity();
+ double s2 = (static_cast<MrmlViewItem*>( item2 ))->similarity();
+
+ if ( s1 < s2 )
+ return 1;
+ else if ( s1 > s2 )
+ return -1;
+ else
+ return 0;
+}
+
+#include "mrml_view.moc"
diff --git a/kmrml/kmrml/mrml_view.h b/kmrml/kmrml/mrml_view.h
new file mode 100644
index 00000000..f6c9f58c
--- /dev/null
+++ b/kmrml/kmrml/mrml_view.h
@@ -0,0 +1,180 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MRML_VIEW_H
+#define MRML_VIEW_H
+
+#include <qevent.h>
+#include <qframe.h>
+#include <qptrlist.h>
+#include <qpixmap.h>
+#include <qpixmapcache.h>
+#include <qscrollview.h>
+
+class QDomDocument;
+class QDomElement;
+class QTimer;
+
+class KComboBox;
+
+namespace KMrml
+{
+
+class MrmlViewItem;
+
+
+class MrmlViewItemList : public QPtrList<MrmlViewItem>
+{
+protected:
+ // sort by similarity
+ virtual int compareItems( QPtrCollection::Item, QPtrCollection::Item );
+
+};
+
+
+class MrmlView : public QScrollView
+{
+ friend class MrmlViewItem;
+
+ Q_OBJECT
+
+public:
+ MrmlView( QWidget *parent = 0L, const char *name = 0L );
+ ~MrmlView();
+
+ MrmlViewItem * addItem( const KURL& url, const KURL& thumbURL,
+ const QString& similarity );
+ MrmlViewItem * addItem( const KURL& url, const KURL& thumbURL,
+ double similarity );
+
+
+ void addRelevanceToQuery( QDomDocument&, QDomElement& parent );
+
+ void clear();
+
+ bool isEmpty() const { return m_items.isEmpty(); }
+
+ void stopDownloads();
+
+ void saveState( QDataStream& stream );
+ void restoreState( QDataStream& stream );
+
+signals:
+ void activated( const KURL& url, ButtonState button );
+ void onItem( const KURL& url );
+
+protected:
+ virtual void resizeEvent( QResizeEvent * );
+
+private slots:
+ void slotLayout();
+ void slotDownloadFinished( const KURL&, const QByteArray& );
+
+private:
+ /**
+ * @returns a _temporary_ pointer to a pixmap. Copy it!
+ */
+ QPixmap * getPixmap( const KURL& url );
+
+ MrmlViewItemList m_items;
+ QTimer *m_timer;
+ QPixmapCache m_pixmapCache;
+ QPixmap m_unavailablePixmap;
+
+
+};
+
+
+class MrmlViewItem : public QFrame
+{
+ Q_OBJECT
+
+public:
+ enum Relevance
+ {
+ Relevant = 0,
+ Neutral = 1,
+ Irrelevant = 2
+ };
+
+ MrmlViewItem( const KURL& url, const KURL& thumbURL, double similarity,
+ MrmlView *view, const char *name=0L );
+ virtual ~MrmlViewItem();
+
+ void setPixmap( const QPixmap& pixmap );
+
+ void createRelevanceElement( QDomDocument& document, QDomElement& parent );
+
+ double similarity() const { return m_similarity; }
+
+ void setSimilarity( double value );
+
+ virtual QSize sizeHint() const;
+
+ const KURL& url() const { return m_url; }
+ const KURL& thumbURL() const { return m_thumbURL; }
+
+ bool hasRemotePixmap() const { return !m_thumbURL.isLocalFile() && m_hasRemotePixmap; }
+
+ Relevance relevance() const;
+ void setRelevance( Relevance relevance );
+
+protected:
+ virtual void paintEvent( QPaintEvent * );
+ virtual void resizeEvent( QResizeEvent * );
+
+ virtual void mousePressEvent( QMouseEvent * );
+ virtual void mouseMoveEvent( QMouseEvent * );
+ virtual void mouseReleaseEvent( QMouseEvent * );
+
+private:
+ bool hitsPixmap( const QPoint& ) const;
+ MrmlView * view() const { return m_view; }
+
+ inline int pixmapX() const {
+ return QMAX( margin, (width() - m_pixmap.width()) / 2);
+ }
+ inline int pixmapY() const {
+ return m_combo->y() - similarityHeight - m_pixmap.height() - margin;
+ }
+
+ KComboBox *m_combo; // for relevance
+ MrmlView *m_view;
+
+ KURL m_url;
+ KURL m_thumbURL;
+
+ QPixmap m_pixmap;
+
+ double m_similarity;
+ const int similarityFullWidth;
+ bool m_hasRemotePixmap;
+
+ QPoint pressedPos;
+
+ static const int spacing = 3;
+ static const int margin = 5;
+ static const int similarityHeight = 4;
+
+};
+
+QDataStream& operator <<( QDataStream& stream, const KMrml::MrmlViewItem& );
+
+}
+
+#endif // MRML_VIEW_H
diff --git a/kmrml/kmrml/mrmlsearch.cpp b/kmrml/kmrml/mrmlsearch.cpp
new file mode 100644
index 00000000..6f411313
--- /dev/null
+++ b/kmrml/kmrml/mrmlsearch.cpp
@@ -0,0 +1,74 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// This little baby is called from Konqueror's popupmenu, when you hit
+// "Search for similar images...". This program simply gets the URLs
+// from Konqueror and creates a query of the form
+// mrml://host.com/?relevant=url1;url2;url3;url4....
+// By default, the mrml URL is mrml://localhost", but you can override that
+// by editing ~/.kde/share/config/kio_mrmlrc and adding
+// [MRML Settings]
+// Default URL=mrml://url.to.your.giftserver.com
+//
+// mrmlsearch will then invoke "kfmclient openURL query" to start open
+// a new Konqueror window and perform the query.
+
+#include <unistd.h>
+
+#include <qfile.h>
+#include <qstring.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kinstance.h>
+#include <kurl.h>
+
+#include <kmrml_config.h>
+
+extern "C" KDE_EXPORT int kdemain( int argc, char **argv )
+{
+ QString query;
+
+ for ( int i = 1; i < argc; i++ ) {
+ if ( i > 1 )
+ query += ';';
+ QString path = QFile::decodeName( argv[i] );
+ if ( path.at( 0 ) == '/' ) {
+ KURL u;
+ u.setPath( path );
+ path = u.url();
+ }
+ query.append( path );
+ }
+
+ KInstance instance( "kio_mrml" );
+
+ KMrml::Config config( instance.config() );
+ KMrml::ServerSettings settings = config.defaultSettings();
+ KURL url;
+ url.setProtocol( "mrml" );
+ url.setHost( settings.host );
+
+ query = KURL::encode_string_no_slash( query );
+ query.prepend( "?relevant=" ); // this is not encoded!
+ url.setQuery( query );
+ qDebug("***** Query: %s ** URL: %s", query.latin1(), url.url().latin1());
+
+ return execlp( "kfmclient",
+ "kfmclient", "openURL", QFile::encodeName(url.url()).data(),
+ "text/mrml", (void *)0 );
+}
diff --git a/kmrml/kmrml/propertysheet.cpp b/kmrml/kmrml/propertysheet.cpp
new file mode 100644
index 00000000..ec46aac0
--- /dev/null
+++ b/kmrml/kmrml/propertysheet.cpp
@@ -0,0 +1,206 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "propertysheet.h"
+
+#include "mrml_elements.h"
+#include "mrml_shared.h"
+
+#include <knuminput.h>
+#include <qwidget.h>
+
+using namespace KMrml;
+
+template class QValueList<QDomElement>;
+
+PropertySheet::PropertySheet()
+{
+ init();
+}
+
+PropertySheet::PropertySheet( const QDomElement& elem )
+{
+ init();
+
+ initFromDOM( elem );
+}
+
+PropertySheet::PropertySheet( const PropertySheet& ps )
+{
+ *this = ps;
+}
+
+PropertySheet& PropertySheet::operator= ( const PropertySheet& ps )
+{
+ if ( &ps == this )
+ return *this;
+
+ m_visibility = ps.m_visibility;
+ m_type = ps.m_type;
+ m_caption = ps.m_caption;
+ m_id = ps.m_id;
+
+ m_sendType = ps.m_sendType;
+ m_sendName = ps.m_sendName;
+ m_sendValue = ps.m_sendValue;
+
+ m_minRange = ps.m_minRange;
+ m_maxRange = ps.m_maxRange;
+ m_stepSize = ps.m_stepSize;
+
+ m_minSubsetSize = ps.m_minSubsetSize;
+ m_maxSubsetSize = ps.m_maxSubsetSize;
+
+ // deep copy of m_subSheets
+ QPtrListIterator<PropertySheet> it( ps.m_subSheets );
+ for ( ; it.current(); ++it )
+ m_subSheets.append( new PropertySheet( *it.current() ) );
+
+ return *this;
+}
+
+void PropertySheet::init()
+{
+ m_subSheets.setAutoDelete( true );
+ m_visibility = Visible;
+}
+
+void PropertySheet::initFromDOM( const QDomElement& elem )
+{
+ m_subSheets.clear();
+
+ m_visibility = getVisibility( elem.attribute( MrmlShared::visibility() ));
+ m_type = getType( elem.attribute( MrmlShared::propertySheetType() ) );
+ m_caption = elem.attribute( MrmlShared::caption() );
+ m_id = elem.attribute( MrmlShared::propertySheetId() );
+ m_sendType = getSendType( elem.attribute( MrmlShared::sendType() ));
+ m_sendName = elem.attribute( MrmlShared::sendName() );
+ m_sendValue = elem.attribute( MrmlShared::sendValue() );
+ m_minRange = toInt( elem.attribute( MrmlShared::from() ));
+ m_maxRange = toInt( elem.attribute( MrmlShared::to() ));
+ m_stepSize = toInt( elem.attribute( MrmlShared::step() ));
+
+ m_minSubsetSize = toInt( elem.attribute( MrmlShared::minSubsetSize() ));
+ m_maxSubsetSize = toInt( elem.attribute( MrmlShared::maxSubsetSize() ));
+
+ QValueList<QDomElement> children =
+ KMrml::directChildElements( elem, MrmlShared::propertySheet() );
+ QValueListConstIterator<QDomElement> it = children.begin();
+ for ( ; it != children.end(); ++it )
+ m_subSheets.append( new PropertySheet( *it ) );
+}
+
+QWidget * PropertySheet::createWidget( QWidget */*parent*/, const char */*name*/ )
+{
+ QWidget *w = 0L;
+
+ switch ( m_type )
+ {
+ case Numeric:
+ {
+// KIntNumInput *input = new KIntNumInput();
+ break;
+ }
+
+ case Subset:
+ {
+ if ( m_minSubsetSize == 1 && m_maxSubsetSize == 1 )
+ {
+
+ }
+
+ break;
+ }
+
+ default:
+ qDebug("** can't create widget for type: %i", m_type);
+ }
+
+ return w;
+}
+
+
+//
+// static methods
+//
+PropertySheet::Visibility PropertySheet::getVisibility( const QString& value )
+{
+ Visibility vis;
+
+ if ( value == MrmlShared::invisible() )
+ vis = Invisible;
+ else if ( value == MrmlShared::popup() )
+ vis = Popup;
+ else
+ vis = Visible; // default value
+
+ return vis;
+}
+
+PropertySheet::Type PropertySheet::getType( const QString& value )
+{
+ Type type = (Type) 0;
+
+ if ( value == MrmlShared::multiSet() )
+ type = MultiSet;
+ else if ( value == MrmlShared::subset() )
+ type = Subset;
+ else if ( value == MrmlShared::setElement() )
+ type = SetElement;
+ else if ( value == MrmlShared::boolean() )
+ type = Boolean;
+ else if ( value == MrmlShared::numeric() )
+ type = Numeric;
+ else if ( value == MrmlShared::textual() )
+ type = Textual;
+ else if ( value == MrmlShared::panel() )
+ type = Panel;
+ else if ( value == MrmlShared::clone() )
+ type = Clone;
+ else if ( value == MrmlShared::reference() )
+ type = Reference;
+
+ return type;
+}
+
+PropertySheet::SendType PropertySheet::getSendType( const QString& value )
+{
+ SendType type = (SendType) 0;
+
+ if ( value == MrmlShared::element() )
+ type = Element;
+ else if ( value == MrmlShared::attribute() )
+ type = Attribute;
+ else if ( value == MrmlShared::attributeName() )
+ type = AttributeName;
+ else if ( value == MrmlShared::attributeValue() )
+ type = AttributeValue;
+ else if ( value == MrmlShared::children() )
+ type = Children;
+ else if ( value == MrmlShared::none() )
+ type = None;
+
+ return type;
+}
+
+int PropertySheet::toInt( const QString& value, int defaultValue )
+{
+ bool ok = false;
+ int res = value.toInt( &ok );
+ return ok ? res : defaultValue;
+}
diff --git a/kmrml/kmrml/propertysheet.h b/kmrml/kmrml/propertysheet.h
new file mode 100644
index 00000000..029d0242
--- /dev/null
+++ b/kmrml/kmrml/propertysheet.h
@@ -0,0 +1,113 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef PROPERTYSHEET_H
+#define PROPERTYSHEET_H
+
+#include <qdom.h>
+#include <qstring.h>
+#include <qptrlist.h>
+
+class QWidget;
+
+namespace KMrml
+{
+ class PropertySheet
+ {
+ public:
+ enum Type
+ {
+ MultiSet = 1, // ??
+ Subset, // radio-button/combobox or listbox
+ SetElement, // CheckBox -> disables/enables children?
+ Boolean, // CheckBox
+ Numeric, // Slider/Spinbox
+ Textual, // lineedit
+ Panel, // groupbox?
+ Clone,
+ Reference
+ };
+ enum Visibility
+ {
+ Visible,
+ Invisible,
+ Popup
+ };
+ enum SendType
+ {
+ Element = 1,
+ Attribute,
+ AttributeName,
+ AttributeValue,
+ Children,
+ None
+ };
+
+ PropertySheet();
+ PropertySheet( const QDomElement& elem );
+ PropertySheet( const PropertySheet& ps );
+ ~PropertySheet() {};
+
+ PropertySheet& operator=( const PropertySheet& ps );
+
+ bool isValid() const {
+ // required mrml attributes
+ return !m_id.isNull() && m_type != 0 && m_sendType != 0;
+ }
+ void initFromDOM( const QDomElement& elem );
+
+ void toElement( QDomElement& parent );
+
+ QWidget * createWidget( QWidget *parent, const char *name = 0 );
+
+ private:
+ static Visibility getVisibility( const QString& value );
+ static Type getType( const QString& value );
+ static SendType getSendType( const QString& value );
+ static int toInt( const QString& value, int defaultValue = 0 );
+
+ void init();
+
+
+ // update operator=() when adding data members!
+
+ QPtrList<PropertySheet> m_subSheets;
+ Visibility m_visibility;
+ Type m_type;
+ QString m_caption;
+ QString m_id;
+
+ SendType m_sendType;
+ QString m_sendName;
+ QString m_sendValue;
+
+ int m_minRange;
+ int m_maxRange;
+ int m_stepSize;
+
+ // Type = Subset && m_minSubsetSize == m_maxSubsetSize == 1 -> Combobox
+ // or radio buttons.
+ // > max > 1 -> Listbox with multiselection
+ int m_minSubsetSize;
+ int m_maxSubsetSize;
+
+ };
+
+}
+
+#endif // PROPERTYSHEET_H
diff --git a/kmrml/kmrml/propertywidgets.cpp b/kmrml/kmrml/propertywidgets.cpp
new file mode 100644
index 00000000..ef00b18f
--- /dev/null
+++ b/kmrml/kmrml/propertywidgets.cpp
@@ -0,0 +1,121 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "propertywidgets.h"
+
+IntegerWidget::IntegerWidget( const PropertySheet& sheet,
+ QWidget *parent, const char *name )
+ : QHBox( parent, name )
+{
+
+}
+
+IntegerWidget::~IntegerWidget()
+{
+
+}
+
+int IntegerWidget::value() const
+{
+
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+ComboWidget::ComboWidget( const PropertySheet& sheet,
+ QWidget *parent, const char *name )
+ : QHBox( parent, name )
+{
+
+}
+
+ComboWidget::~ComboWidget()
+{
+
+}
+
+QString ComboWidget::value() const
+{
+
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+CheckBoxWidget::CheckBoxWidget( const PropertySheet& sheet,
+ QWidget *parent, const char *name )
+ : QHBox( parent, name )
+{
+
+}
+
+CheckBoxWidget::~CheckBoxWidget()
+{
+
+}
+
+bool CheckBoxWidget::value() const
+{
+
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+LineEditWidget::LineEditWidget( const PropertySheet& sheet,
+ QWidget *parent, const char *name )
+ : QHBox( parent, name )
+{
+
+}
+
+LineEditWidget::~LineEditWidget()
+{
+
+}
+
+QString LineEditWidget::value() const
+{
+
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+ListBoxWidget::ListBoxWidget( const PropertySheet& sheet,
+ QWidget *parent, const char *name )
+ : QHBox( parent, name )
+{
+
+}
+
+ListBoxWidget::~ListBoxWidget()
+{
+
+}
+
+QStringList ListBoxWidget::value() const
+{
+
+}
+
+#include "propertywidgets.moc"
diff --git a/kmrml/kmrml/propertywidgets.h b/kmrml/kmrml/propertywidgets.h
new file mode 100644
index 00000000..c738d03d
--- /dev/null
+++ b/kmrml/kmrml/propertywidgets.h
@@ -0,0 +1,108 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef PROPERTYWIDGETS_H
+#define PROPERTYWIDGETS_H
+
+#include <qhbox.h>
+
+#include "propertysheet.h"
+
+namespace KMrml
+{
+ class IntegerWidget : public QHBox
+ {
+ Q_OBJECT
+
+ public:
+ IntegerWidget( const PropertySheet& sheet,
+ QWidget *parent = parent, const char *name = 0L );
+ ~IntegerWidget();
+
+ int value() const;
+
+ private:
+
+ };
+
+ class ComboWidget : public QHBox
+ {
+ Q_OBJECT
+
+ public:
+ ComboWidget( const PropertySheet& sheet,
+ QWidget *parent = parent, const char *name = 0L );
+ ~ComboWidget();
+
+ QString value() const;
+
+ private:
+
+ };
+
+ class CheckBoxWidget : public QHBox
+ {
+ Q_OBJECT
+
+ public:
+ CheckBoxWidget( const PropertySheet& sheet,
+ QWidget *parent = parent, const char *name = 0L );
+ ~CheckBoxWidget();
+
+ bool value();
+
+ private:
+
+
+ };
+
+
+ class LineEditWidget : public QHBox
+ {
+ Q_OBJECT
+
+ public:
+ LineEditWidget( const PropertySheet& sheet,
+ QWidget *parent = parent, const char *name = 0L );
+ ~LineEditWidget();
+
+ QString value();
+
+ private:
+
+ };
+
+ class ListBoxWidget : public QHBox
+ {
+ Q_OBJECT
+
+ public:
+ ListBoxWidget( const PropertySheet& sheet,
+ QWidget *parent = parent, const char *name = 0L );
+ ~ListBoxWidget();
+
+ QStringList values();
+
+ private:
+
+ };
+
+};
+
+
+#endif // PROPERTYWIDGETS_H
diff --git a/kmrml/kmrml/server/Makefile.am b/kmrml/kmrml/server/Makefile.am
new file mode 100644
index 00000000..875684b0
--- /dev/null
+++ b/kmrml/kmrml/server/Makefile.am
@@ -0,0 +1,12 @@
+kde_module_LTLIBRARIES = kded_daemonwatcher.la
+
+INCLUDES = $(all_includes)
+kded_daemonwatcher_la_SOURCES = watcher.cpp watcher.skel
+# watcher.stub
+kded_daemonwatcher_la_LDFLAGS = $(all_libraries) -module -avoid-version
+kded_daemonwatcher_la_LIBADD = $(LIB_KSYCOCA) $(LIB_KDEUI)
+
+METASOURCES = AUTO
+
+servicesdir = $(kde_servicesdir)/kded
+services_DATA = daemonwatcher.desktop
diff --git a/kmrml/kmrml/server/daemonwatcher.desktop b/kmrml/kmrml/server/daemonwatcher.desktop
new file mode 100644
index 00000000..c29495b4
--- /dev/null
+++ b/kmrml/kmrml/server/daemonwatcher.desktop
@@ -0,0 +1,103 @@
+[Desktop Entry]
+Type=Service
+Name=KDED KMRML Daemon Watcher
+Name[ar]=مراقب KDED KMRML Daemon
+Name[bs]=KDED KMRML nadzor demona
+Name[ca]=Dimoni vigilant KDED KMRL
+Name[cs]=Sledovač KMRML démonů
+Name[cy]=Gwyliwr Ellyll KMRML KDED
+Name[da]=KDED KMRML-dæmon-overvåger
+Name[de]=Überwachung der KDE-Bildersuche
+Name[el]=Επόπτης δαίμονα KMRML KDED
+Name[es]=Guardián del demonio KDED KMRML
+Name[et]=KDED KMRML deemoni jälgija
+Name[eu]=KDED KMRML deabru behatzailea
+Name[fa]=پایشگر شبح KDED KMRML
+Name[fi]=KDED KMRML-palvelimen tarkkailija
+Name[fr]=Observateur KDE du démon KMRML
+Name[gl]=Vixiante do daemon de KDED KMRML
+Name[he]=צופה תהליכי הרקע של KDED KMRML
+Name[hi]=KDED KMRML डेमन वाचर
+Name[hu]=KDED KMRML szolgáltatásfigyelő
+Name[is]=Eftirlit með KDED KMRML þjóninum
+Name[it]=Controllo del demone KDED KMRML
+Name[ja]=KDED KMRML デーモンウォッチャー
+Name[kk]=KDED KMRML қызметі
+Name[km]=កម្មវិធី​ឃ្លាំមើល​ដេមិន KDED KMRML
+Name[lt]=KDED KMRML tarnybos stebėtojas
+Name[ms]=Pemerhati Daemon KDED KMRML
+Name[nb]=KDED KMRML nisseovervåker
+Name[nds]=KMRML-Luerdämoon för KDED
+Name[ne]=KDED KMRML डेइमन दर्शक
+Name[nl]=KDED KMRML-daemonbeheer
+Name[nn]=KDED KMRML-nisseovervaking
+Name[pl]=Monitor usług KMRML
+Name[pt]=Monitor KMRML de Servidores KDED
+Name[pt_BR]=Sentinela de Serviços KDED
+Name[ro]=Demon KDED pentru MRML
+Name[ru]=Служба MRML
+Name[se]=KDED KMRML-duogášprográmmagoziheaddji
+Name[sk]=Sledovanie démona KDED KMRML
+Name[sl]=Opazovalnik demona KMRML za KDED
+Name[sr]=KDED KMRML демон за праћење
+Name[sr@Latn]=KDED KMRML demon za praćenje
+Name[sv]=KDED KMRML-demonbevakare
+Name[ta]=KDED டிமென் வாட்சர்
+Name[tg]=Мудири демони KDED KMRML
+Name[th]=ตัวเฝ้าดูแดมอน KDED KMRML
+Name[tr]=KDED KMRML Aracı İzleyici
+Name[uk]=Спостерігач демону KDED KMRML
+Name[zh_CN]=KDED KMRML 守护程序监视器
+Name[zh_HK]=KDED KMRML 系統程式監察器
+Name[zh_TW]=KDED KMRML 伺服程式監看器
+Comment=Starts daemons on demand and restarts them on failure
+Comment[bg]=Стартиране на демоните при заявка и рестартиране на демони при грешка
+Comment[bs]=Pokreće demone po potrebi i restartuje ih ako se sruše
+Comment[ca]=Engega els dimonis sota petició i els torna a engegar si fallen
+Comment[cs]=Spouští démony na požádání a restartuje je při selhání
+Comment[da]=Starter dæmoner ved forespørgsel og genstarter dem ved fejl
+Comment[de]=Startet KMRML-Dienste bei Bedarf und im Fehlerfall neu
+Comment[el]=Εκκινεί δαίμονες όταν ζητηθεί και τους επανεκκινεί κατά την αποτυχία
+Comment[es]=Inicia los demonios bajo demanda y los reinicia si fallan
+Comment[et]=Käivitab nõudmisel deemoneid ja taaskäivitab neid ebaõnnestumise korral
+Comment[eu]=Demonioak hasi eta bukau egiten ditu eskatzen zaionean
+Comment[fa]=شبحها را بر اساس نیاز آغاز می‌کند و هنگام خرابی آنها را بازآغازی می‌کند
+Comment[fi]=Käynnistää palvelimia tarpeen mukaan ja uudelleenkäynnistää ne virheen yhteydessä
+Comment[fr]=Lance les démons à la demande et les redémarre en cas d'échec
+Comment[gl]=Iniciar daemons cando sexa preciso e reinicialos se fallan.
+Comment[he]=מפעיל תהליכי רקע לפי דרישה ומפעיל אותם מחדש במקרה של כשל
+Comment[hu]=Szükség esetén elindítja, hiba esetén újraindítja a szolgáltatásokat
+Comment[is]=Ræsir þjóna þegar þarf og endurræsir þá ef þeir bregðast
+Comment[it]=Avvia i demoni su richiesta e li riavvia in caso di problemi
+Comment[ja]=デーモンをオンデマンドで起動し、失敗したときは再起動します。
+Comment[kk]=Талап бойынша қызметті жегу, жаңылса қайта жегу
+Comment[km]=ចាប់ផ្ដើម​ដេមិន​នៅ​ពេល​ត្រូវការ ហើយ​ចាប់ផ្ដើម​ពួក​វា​ឡើង​វិញ​នៅ​ពេល​បរាជ័យ
+Comment[lt]=Paleidžia tarnybas pagal pareikalavimą ir paleidžia iš naujo nesėkmės atveju
+Comment[ms]=Mulakan daemons atas permintaan dan mula semula atas kegagalan
+Comment[nb]=Starter nisser på forespørsler og starter dem igjen ved feil.
+Comment[nds]=Start Achtergrundperzessen op Nafraag un bi Fehlers nieg
+Comment[ne]=माग गरेको बेलामा डेइमन सुरु गर्दछ र अफफल भएमा फेरि सुरु गर्दछ
+Comment[nl]=Start achtergrondprogramma's op en herstart deze indien nodig
+Comment[nn]=Startar nissar når dei trengst og startar dei om att ved feil
+Comment[pl]=Uruchamia usługi na żądanie i wznawia je po awarii
+Comment[pt]=Inicia os servidores a pedido e reinicia-os em caso de falha
+Comment[pt_BR]=Inicia serviços sob demanda e reinicia-os em caso de falha
+Comment[ro]=Porneşte demonii la cerere şi îi reporneşte în caz de eroare
+Comment[ru]=Поддержка протокола MRML
+Comment[sk]=Spustí démonov podľa požiadaviek a pri zlyhaní ich reštartuje
+Comment[sl]=Na zahtevo zažene demone in jih ob napaki znova zažene
+Comment[sr]=На захтев покреће демоне и поново их покреће ако се сруше
+Comment[sr@Latn]=Na zahtev pokreće demone i ponovo ih pokreće ako se sruše
+Comment[sv]=Starta demoner vid behov och starta om dem vid fel
+Comment[ta]=அவசிய நேரத்தில் டிமென்னை துவக்குகிறது. இயலாதபோது திரும்ப துவக்குகிறது
+Comment[tg]=Оғози демон аз рӯи дархост ва ҳангоми нуқсони он аз сари нав оғоз намудан.
+Comment[tr]=İstek halinde programı başlatır ve hata durumunda yeniden başlatır.
+Comment[uk]=Запускає демони при потребі та перезапускає їх при аварії
+Comment[zh_CN]=按需启动守护程序并在失败时重新启动
+Comment[zh_HK]=依要求啟動系統程式並在失敗時重新啟動它們。
+Comment[zh_TW]=需要時啟動守護程式,失敗的話重新啟動
+ServiceTypes=KDEDModule
+X-KDE-ModuleType=Library
+X-KDE-Library=daemonwatcher
+X-KDE-FactoryName=daemonwatcher
+X-KDE-Kded-load-on-demand=true
diff --git a/kmrml/kmrml/server/watcher.cpp b/kmrml/kmrml/server/watcher.cpp
new file mode 100644
index 00000000..e6137cc5
--- /dev/null
+++ b/kmrml/kmrml/server/watcher.cpp
@@ -0,0 +1,280 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <dcopclient.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "watcher.h"
+
+using namespace KMrml;
+
+Watcher::Watcher( const QCString& name )
+ : KDEDModule( name )
+{
+ m_daemons.setAutoDelete( true );
+
+ // safety, for clients that die without unregistering
+ KApplication::dcopClient()->setNotifications( true );
+ connect( KApplication::dcopClient(),
+ SIGNAL( applicationRemoved( const QCString& )),
+ SLOT( slotAppUnregistered( const QCString& )));
+}
+
+Watcher::~Watcher()
+{
+ KApplication::dcopClient()->setNotifications( false );
+}
+
+bool Watcher::requireDaemon( const QCString& clientAppId,
+ const QString& daemonKey,
+ const QString& commandline,
+ uint timeout /* seconds */,
+ int restartOnFailure )
+{
+ if ( !KApplication::dcopClient()->isApplicationRegistered( clientAppId ) )
+ kdWarning() << "Watcher::requireDaemon: " << daemonKey
+ << ": Client AppID is not registered with DCOP: "
+ << clientAppId << endl;
+
+ DaemonData *daemon = m_daemons.find( daemonKey );
+
+ if ( daemon )
+ {
+ if ( !daemon->apps.find( clientAppId ) )
+ daemon->apps.append( clientAppId );
+
+ // timeout, commandline and restart values are: first come, first serve
+ return true; // process already running, all fine
+ }
+
+ else // start daemon
+ {
+ daemon = new DaemonData( daemonKey, commandline,
+ timeout, restartOnFailure );
+ m_daemons.insert( daemonKey, daemon );
+ daemon->apps.append( clientAppId );
+
+#if KDE_VERSION >= 306
+ daemon->process = new KProcess();
+ daemon->process->setUseShell( true );
+#else
+ daemon->process = new KShellProcess();
+#endif
+ daemon->process->setEnvironment( "LC_ALL", "C" );
+ daemon->process->setEnvironment( "LANG", "C" );
+ daemon->process->setEnvironment( "LANGUAGE", "C" );
+ *daemon->process << commandline;
+ connect( daemon->process, SIGNAL( processExited( KProcess * ) ),
+ SLOT( slotProcExited( KProcess * )));
+ return startDaemon( daemon );
+ }
+}
+
+void Watcher::unrequireDaemon( const QCString& clientAppId,
+ const QString& daemonKey )
+{
+ unrequireDaemon( m_daemons.find( daemonKey ), clientAppId );
+}
+
+void Watcher::unrequireDaemon( DaemonData *daemon,
+ const QCString& clientAppId )
+{
+ if ( daemon )
+ {
+ daemon->apps.remove( clientAppId );
+ if ( daemon->apps.isEmpty() )
+ {
+ if ( !daemon->timer )
+ {
+ daemon->timer = new QTimer();
+ connect( daemon->timer, SIGNAL( timeout() ),
+ SLOT( slotTimeout() ));
+ }
+ daemon->timer->start( daemon->timeout * 1000, true );
+ }
+ }
+ else
+ kdWarning() << "Watcher::unrequireDaemon: daemon unknown. client: "
+ << clientAppId << endl;
+}
+
+QStringList Watcher::runningDaemons() const
+{
+ QStringList result;
+ QDictIterator<DaemonData> it( m_daemons );
+ for ( ; it.current(); ++it )
+ result.append( it.current()->commandline );
+
+ return result;
+}
+
+void Watcher::slotProcExited( KProcess *proc )
+{
+ DaemonData *daemon = findDaemonFromProcess( proc );
+
+ if ( proc->normalExit() )
+ {
+ emitExited( daemon );
+ return;
+ }
+
+ if ( daemon )
+ {
+ if ( --daemon->restartOnFailure <= 0 )
+ {
+ if ( KMessageBox::questionYesNo( 0L,
+ i18n("<qt>The server with the command line"
+ "<br>%1<br>"
+ "is not available anymore. Do you want to "
+ "restart it?" ).arg( daemon->commandline ),
+ i18n("Service Failure"), i18n("Restart Server"), i18n("Do Not Restart") )
+ == KMessageBox::Yes )
+ {
+ daemon->restartOnFailure = 1;
+ }
+ }
+
+ if ( daemon->restartOnFailure > 0 )
+ {
+ startDaemon( daemon );
+ return;
+ }
+ }
+
+ emitFailure( daemon );
+}
+
+bool Watcher::startDaemon( DaemonData *daemon )
+{
+ if ( daemon->process->start( KProcess::NotifyOnExit ) )
+ return true;
+
+ else
+ {
+ if ( KMessageBox::questionYesNo( 0L,
+ i18n("Unable to start the server with the "
+ "command line"
+ "<br>%1<br>"
+ "Try again?").arg( daemon->commandline ),
+ i18n("Service Failure"), i18n("Try Again"), i18n("Do Not Try") )
+ == KMessageBox::Yes )
+ {
+ return startDaemon( daemon );
+ }
+ }
+
+ return false;
+}
+
+void Watcher::slotTimeout()
+{
+ QTimer *timer = static_cast<QTimer*>( const_cast<QObject *>( sender() ) );
+ DaemonData *daemon = findDaemonFromTimer( timer );
+ if ( daemon )
+ {
+ if ( daemon->apps.isEmpty() )
+ {
+ // the daemon and KProcess might get deleted by killing the
+ // KProcess (through slotProcExited()), so don't dereference
+ // daemon after proc->kill()
+ QString key = daemon->daemonKey;
+
+ // noone registered during the timeout, so kill the daemon
+ if ( !daemon->process->kill() )
+ daemon->process->kill( SIGKILL );
+
+ m_daemons.remove( key );
+ }
+ }
+}
+
+DaemonData * Watcher::findDaemonFromProcess( KProcess *proc )
+{
+ DaemonData *daemon;
+ QDictIterator<DaemonData> it( m_daemons );
+ for ( ; (daemon = it.current()); ++it )
+ {
+ if ( daemon->process == proc )
+ return daemon;
+ }
+
+ return 0L;
+}
+
+DaemonData * Watcher::findDaemonFromTimer( QTimer *timer )
+{
+ DaemonData *daemon;
+ QDictIterator<DaemonData> it( m_daemons );
+ for ( ; (daemon = it.current()); ++it )
+ {
+ if ( daemon->timer == timer )
+ return daemon;
+ }
+
+ return 0L;
+}
+
+void Watcher::slotAppUnregistered( const QCString& appId )
+{
+ if ( m_daemons.isEmpty() )
+ return;
+
+ DaemonData *daemon;
+ QDictIterator<DaemonData> it( m_daemons );
+ for ( ; (daemon = it.current()); ++it )
+ {
+ if ( daemon->apps.find( appId ) != -1 )
+ unrequireDaemon( daemon, appId );
+ }
+}
+
+void Watcher::emitExited( DaemonData *daemon )
+{
+ if ( daemon )
+ {
+ daemonExited( daemon->daemonKey,
+ daemon->process->pid(),
+ daemon->process->exitStatus() );
+
+ m_daemons.remove( daemon->daemonKey );
+ }
+}
+
+void Watcher::emitFailure( DaemonData *daemon )
+{
+ if ( daemon )
+ {
+ daemonDied( daemon->daemonKey, daemon->process->pid() );
+ m_daemons.remove( daemon->daemonKey ); // deletes daemon + KProcess
+ }
+}
+
+extern "C" {
+ KDE_EXPORT KDEDModule *create_daemonwatcher(const QCString & obj )
+ {
+ return new Watcher( obj );
+ }
+}
+
+
+#include "watcher.moc"
diff --git a/kmrml/kmrml/server/watcher.h b/kmrml/kmrml/server/watcher.h
new file mode 100644
index 00000000..67d9b5e1
--- /dev/null
+++ b/kmrml/kmrml/server/watcher.h
@@ -0,0 +1,107 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef LAUNCHER_H
+#define LAUNCHER_H
+
+#include <qdict.h>
+#include <qmap.h>
+#include <qstrlist.h>
+#include <qstringlist.h>
+#include <qtimer.h>
+
+#include <kdedmodule.h>
+#include <kprocess.h>
+
+namespace KMrml
+{
+ class DaemonData
+ {
+ public:
+ DaemonData( const QString& key, const QString& cmd,
+ uint time, int numRestarts )
+ : daemonKey( key ),
+ commandline( cmd ),
+ timeout( time ),
+ apps( true ), // deep copies
+ restartOnFailure( numRestarts ),
+ process( 0L ),
+ timer( 0L )
+ {
+ }
+ ~DaemonData()
+ {
+ delete process;
+ delete timer;
+ }
+ QString daemonKey;
+ QString commandline;
+ uint timeout;
+ QStrList apps;
+ int restartOnFailure;
+ KProcess *process;
+ QTimer *timer;
+ };
+
+ class Watcher : public KDEDModule
+ {
+ Q_OBJECT
+ K_DCOP
+
+ public:
+ Watcher( const QCString& name = "daemonwatcher" );
+ ~Watcher();
+
+ k_dcop:
+ virtual bool requireDaemon( const QCString& clientAppId,
+ const QString& daemonKey,
+ const QString& commandline,
+ uint timeout = 60 /* seconds */,
+ int numRestarts = 5 );
+ virtual void unrequireDaemon( const QCString& clientAppId,
+ const QString& daemonKey );
+ virtual QStringList runningDaemons() const;
+
+ k_dcop_signals:
+ void daemonExited(const QString& daemonKey, pid_t pid, int exitStatus);
+ void daemonDied( const QString& daemonKey, pid_t pid );
+
+ protected:
+ bool startDaemon( DaemonData *daemon );
+
+ protected slots:
+ virtual void slotTimeout();
+
+ private:
+ void unrequireDaemon( DaemonData *daemon, const QCString& clientAppId);
+ DaemonData *findDaemonFromProcess( KProcess *proc );
+ DaemonData *findDaemonFromTimer( QTimer *timer );
+
+ void emitExited( DaemonData *daemon );
+ void emitFailure( DaemonData *daemon );
+
+ private slots:
+ void slotProcExited( KProcess *proc );
+ void slotAppUnregistered( const QCString& appId );
+
+ QDict<DaemonData> m_daemons;
+ };
+
+}
+
+#endif // LAUNCHER_H