summaryrefslogtreecommitdiffstats
path: root/kicker/kicker/plugins/beaglesearch.h
blob: e192f6af372616a2534fb24284d5bdb4a8bfa2e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
/*****************************************************************

   Copyright (c) 2006 Debajyoti Bera <dbera.web@gmail.com>

   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 BEAGLESEARCH_H
#define BEAGLESEARCH_H

#include <tqdict.h>
#include <tqptrlist.h>
#include <tqthread.h>
#include <tqevent.h>
#include <tqmutex.h>

#include <kdebug.h>
#include <kurl.h>

extern "C" {
#include <glib.h>
#include <beagle/beagle.h>
}

// BeagleSearchClient sends 3 types of events
// when results are to be sent as they arrive,
//  - RESULTFOUND : when result is found
//  - SEARCHOVER :  when search is over
//  - KILLME : just before thread finishes - used to cleanup the thread object
// when results are to be sent after receiving all of them
//  - RESULTFOUND : when all results are obtained
//  - KILLME : just before thread finishes - used to cleanup the thread object
#define RESULTFOUND (TQEvent::Type)1001 /* TQEvent::User + 1 */
#define SEARCHOVER  (TQEvent::Type)1002 /* TQEvent::User + 2 */
#define KILLME      (TQEvent::Type)1003 /* TQEvent::User + 3 */

class TQStringList;

// IMPORTANT: Call this before any beagle calls
void beagle_init ();

class Hit {
public:
    Hit (BeagleHit *_hit);
    ~Hit ();
    
    // convenience wrappers
    // remember that the hit values are utf8 strings
    const KURL getUri () const { return KURL (TQString::fromUtf8 (beagle_hit_get_uri (hit)));}
    const TQString getType () const { return TQString::fromUtf8 (beagle_hit_get_type (hit));}
    const TQString getMimeType () const { return TQString::fromUtf8 (beagle_hit_get_mime_type (hit));}
    const TQString getSource () const { return TQString::fromUtf8 (beagle_hit_get_source (hit));}
    const KURL getParentUri () const { return KURL (TQString::fromUtf8 (beagle_hit_get_parent_uri (hit)));}
    const TQDict<TQStringList>& getAllProperties ()
    {
	if (! processed)
	    processProperties ();
	return property_map;
    }
    const TQStringList* getProperties (TQString prop_name)
    {
	if (! processed)
	    processProperties ();
	return property_map [prop_name];
    }
    const TQString operator[] (TQString prop_name);

private:
    BeagleHit *hit;
    TQDict<TQStringList> property_map;
    // not every hit may be used. so, do a lazy processing of property_map
    bool processed;
    void processProperties ();
};

class BeagleSearchResult{
public:
    BeagleSearchResult(int client_id);
    ~BeagleSearchResult();
    void addHit (BeagleHit *hit);
    TQString getHitCategory (Hit *hit);

    // id of the bsclient
    int client_id;
    // time taken to finish query
    int query_msec;
    // total number of results in this query
    int total;

    const TQPtrList<Hit> *getHits () const;

private:
    // lists of hits
    TQPtrList<Hit> *hitlist;
};

// caller should delete bsclient->result and bsclient
class BeagleSearchClient : public TQThread {
public:
    // passing NULL for client makes bsclient create client itself and
    // delete it later
    BeagleSearchClient (int id,
                        TQObject *y,
                        BeagleClient *client,
                        BeagleQuery *query,
                        bool collate_results)
    : id (id), kill_me (false), object (y), client (client),
      query (query), destroy_client (false), collate_results (collate_results)
    {
        if (client == NULL) {
	    client = beagle_client_new (NULL);
            destroy_client = true;
        }
	
//        if (client == NULL)
//            throw -1;

        main_loop = g_main_loop_new (NULL, FALSE);
        if (collate_results)
            result = new BeagleSearchResult (id);

	client_mutex = new TQMutex ();
    }

    // It is never safe to delete BeagleSearchClient directly, the thread might still be running
    ~BeagleSearchClient ()
    {
	if (! finished ()) {
	    kdDebug () << "Thread " << id << " still running. Waiting.........." << endl;
	    wait ();
	}

        if (destroy_client)
            g_object_unref (client);
        g_main_loop_unref (main_loop);
        g_object_unref (query);
        kdDebug() << "Deleting client ..." << id << endl;
	delete client_mutex;
    }

private:
    static void hitsAddedSlot (BeagleQuery *query,
                               BeagleHitsAddedResponse *response,
                               BeagleSearchClient *bsclient);

    static void finishedSlot (BeagleQuery  *query,
                              BeagleFinishedResponse *response,
                              BeagleSearchClient *bsclient);

public:
    // run() starts the query and sends the result as follows:
    // - either wait till get back all results and send it as RESULTFOUND
    // - or, send results as it gets them as RESULTFOUND and 
    //       send SEARCHOVER when finished
    // collate_results controls the behaviour
    virtual void run ( );
    
    // after stopClient() is called, application can safely go and remove previous menu entries
    // - i.e. after stopClient is called, app doesnt except the eventhandler to receive any results
    // - use client_id to determine which is the current client, set it right after stopclient
    // - Eventhandler checks client id, if it is current, it adds stuff to the menu
    //   else, it discards everything
    // Once eventhandler is being processed, doQuery() wont be called and vice versa
    //   so no need to serialize eventhandler and doquery
    //
    // stopClient needs to make sure that once it is called, the thread is finished asap. Use a mutex
    // to serialize actions. callbacks need to use mutex too.
    // stopclient has to remove signal handlers to prevent further signal calls, set kill_me flag
    //   and quite main loop
    // stopClient can be called at the following times:
    // - Waiting for the first result:
    //   nothing extra
    // - in hitsAddedSlot, processing results
    //   in callback, before processing, if killme is set, just return.
    // - in hitsAddedSlot, after sending results
    //   before sending, if killme is set, dont send results
    //   (doing it twice in hitsAdded because forming BeagleSearchResult can take time)
    // - Waiting for more results
    //   nothing extra
    // - in finishedSlot, before sending finishedMsg
    //   if killme is set, just return
    // - in finishedSlot, after sending finishedMsg
    //   if killme is set, just return
    //  in Run(), when return from mainloop, if killme is set, dont do anything more but call delete this
    void stopClient ();

    // id of the client
    // this is required in case applications fires many clients in rapid succession
    int id;
    
    GMainLoop * main_loop;
    BeagleSearchResult *result;
    
    // this is set if the client is obsolete now i.e.
    // the application doesnt need the results from the client anymore
    bool kill_me;
private:
    // the application; need this to send events to the application
    TQObject *object;
    // mutex to control setting the kill_me shared variable
    TQMutex *client_mutex;
    BeagleClient *client;
    BeagleQuery *query;
    // should the client be destroyed by the client
    // if the client created it, then most probably it should
    bool destroy_client;
    bool collate_results;
};

class BeagleUtil {
public:

    static BeagleQuery *createQueryFromString (TQString query_str,
					       TQStringList &sources,
                                               TQStringList &types,
					       int max_hits_per_source = 100);
    static BeagleTimestamp *timestringToBeagleTimestamp (TQString timestring);
};

#endif