~ubuntu-branches/ubuntu/trusty/kvirc/trusty

« back to all changes in this revision

Viewing changes to src/kvirc/kvs/kvi_kvs_object.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Kai Wasserbäch, Kai Wasserbäch, Raúl Sánchez Siles
  • Date: 2011-02-12 10:40:21 UTC
  • mfrom: (14.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110212104021-5mh4f75jlku20mnt
The combined "Twisted Experiment" and "Nocturnal Raid" release.

[ Kai Wasserbäch ]
* Synced to upstream's SVN revision 5467.
* debian/rules:
  - Added .PHONY line.
  - Resurrect -DMANUAL_REVISION, got lost somewhere and we build SVN
    revisions again.
  - Replace "-DWITH_NO_EMBEDDED_CODE=YES" with "-DWANT_CRYPTOPP=YES".
  - Change the remaining -DWITH/-DWITHOUT to the new -DWANT syntax.
* debian/control:
  - Removed DMUA, I'm a DD now.
  - Changed my e-mail address.
  - Removed unneeded relationships (no upgrades over two releases are
    supported).
  - Fix Suggests for kvirc-dbg.
  - kvirc-data: Make the "Suggests: kvirc" a Recommends, doesn't make much
    sense to install the -data package without the program.
* debian/source/local-options: Added with "unapply-patches".
* debian/kvirc.lintian-overrides: Updated to work for 4.1.1.
* debian/patches/21_make_shared-mime-info_B-D_superfluous.patch: Updated.
* debian/kvirc-data.install: Added .notifyrc.

[ Raúl Sánchez Siles ]
* Stating the right version where kvirc-data break and replace should happen.
* Fixing link to license file.
* Added French and Portuguese man pages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//=============================================================================
2
 
//
3
 
//   File : kvi_kvs_object.cpp
4
 
//   Creation date : Wed 08 Oct 2003 02:31:57 by Szymon Stefanek
5
 
//
6
 
//   This file is part of the KVIrc IRC client distribution
7
 
//   Copyright (C) 2003-2008 Szymon Stefanek <pragma at kvirc dot net>
8
 
//
9
 
//   This program is FREE software. You can redistribute it and/or
10
 
//   modify it under the terms of the GNU General Public License
11
 
//   as published by the Free Software Foundation; either version 2
12
 
//   of the License, or (at your opinion) any later version.
13
 
//
14
 
//   This program is distributed in the HOPE that it will be USEFUL,
15
 
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
 
//   See the GNU General Public License for more details.
18
 
//
19
 
//   You should have received a copy of the GNU General Public License
20
 
//   along with this program. If not, write to the Free Software Foundation,
21
 
//   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
 
//
23
 
//=============================================================================
24
 
 
25
 
#include "kvi_kvs_object.h"
26
 
#include "kvi_kvs_hash.h"
27
 
#include "kvi_kvs_kernel.h"
28
 
#include "kvi_window.h"
29
 
#include "kvi_app.h"
30
 
 
31
 
#include "kvi_modulemanager.h"
32
 
#include "kvi_console.h"
33
 
#include "kvi_locale.h"
34
 
#include "kvi_error.h"
35
 
#include "kvi_out.h"
36
 
#include "kvi_mirccntrl.h"
37
 
#include "kvi_iconmanager.h"
38
 
#include "kvi_malloc.h"
39
 
 
40
 
#include "kvi_kvs_object_controller.h"
41
 
#include "kvi_kvs_object_functioncall.h"
42
 
#include "kvi_kvs_object_functionhandlerimpl.h"
43
 
 
44
 
#include <QMetaObject>
45
 
#include <QMetaProperty>
46
 
#include <QTimer>
47
 
#include <QIcon>
48
 
 
49
 
#include <time.h>
50
 
 
51
 
/*
52
 
        @doc: objects
53
 
        @title:
54
 
                Object scripting
55
 
        @short:
56
 
                Object scripting overview
57
 
        @keyterms:
58
 
                objects , object scripting , complex data structures
59
 
        @body:
60
 
                [big]Introduction[/big]
61
 
 
62
 
                The KVIrc scripting language is not object oriented in nature.
63
 
                Anyway , objects are a highlevel abstraction that allow
64
 
                to write complex code in a "clean" way.
65
 
                So I've added at least some pseudo-object support.[br][br]
66
 
 
67
 
                [big]Basic concepts[/big]
68
 
 
69
 
                Objects are arranged in tree structures.
70
 
                Each object that you create is either toplevel object or a children
71
 
                of another object. A toplevel object is a parentless one.
72
 
                Obviously all objects can have children objects.[br][br]
73
 
 
74
 
                When an object is destroyed , all its children are also destroyed.
75
 
                The toplevel objects are automatically destroyed when KVIrc quits.
76
 
                The objects are global to the entire application (this is different
77
 
                from previous KVIrc releases where the objects were local
78
 
                to the current frame window and arranged in a single tree
79
 
                with a builtin root object).[br][br]
80
 
 
81
 
                Each object is an instance of a class that defines its features.
82
 
                Each object has also a name , that is not necessary unique and is assigned
83
 
                by the programmer; the name is just a mnemonic expedient, and
84
 
                you may also not need it.[br][br]
85
 
 
86
 
                Each object is identified by an [b]OPAQUE UNIQUE ID[/b].
87
 
                The ID is assigned by KVIrc and can be held in any variable.
88
 
                You can think the object id as a "handle for the object" or the object's pointer.
89
 
                Any action performed on the object will require its ID.[br][br]
90
 
 
91
 
                [big]Creation and destruction[/big]
92
 
 
93
 
                To create an object you must use the [fnc]$new[/fnc]()
94
 
                function. [fnc]$new[/fnc]() requires three parameters:[br]
95
 
                - The object class (more about object classes later in this document)[br]
96
 
                - The ID of the parent object , (that can be 0 for toplevel objects).[br]
97
 
                - The object name (eventually empty)[br]
98
 
                [example]
99
 
                        %myobject = [fnc]$new[/fnc]([class]object[/class],0,theName)
100
 
                [/example]
101
 
                [fnc]$new[/fnc]() returns the ID of the newly created object, or
102
 
                the STRING "0" if the object creation fails
103
 
                (it is a string because the object id's are generally strings, and 0 is an "invalid object id").
104
 
                In well written scripts it is not common that the object creation fails, anyway
105
 
                you can check if the creation has failed in the following way:[br]
106
 
                [example]
107
 
                        [cmd]if[/cmd](%myobject)[cmd]echo[/cmd] "Object created!"
108
 
                        else [cmd]echo[/cmd] "Object creation failed!"
109
 
                [/example]
110
 
                You can also test the object ID's for equality:[br]
111
 
                [example]
112
 
                        [cmd]if[/cmd](%myobject == %anotherobject)[cmd]echo[/cmd] "This is the same object!";
113
 
                [/example]
114
 
                The parent object id is optional, if not specified it is assumed to be 0.
115
 
                The object name is optional , but it may help you later in finding the object.[br][br]
116
 
 
117
 
                To destroy an object use the [cmd]delete[/cmd] command. (In previous versions
118
 
                this command was named "destroy" and delete is currently aliased to that name too).[br]
119
 
                [example]
120
 
                        [cmd]delete[/cmd] %myobject
121
 
                [/example]
122
 
                If the destroyed object has children objects , these are destroyed too.[br][br]
123
 
 
124
 
                [big]Fields : objects as pseudo-structures[/big]
125
 
 
126
 
                All the objects can contain variable fields.
127
 
                You can set an object's field by using the object scope operator "->":[br]
128
 
                [example]
129
 
                        %myobject-&gt;%fieldVariable = dataString
130
 
                [/example]
131
 
                To unset a field set it with empty data string (just like with a normal variable).
132
 
                To retrieve the field data use the object scope operator in the same way:[br]
133
 
                [example]
134
 
                        [cmd]echo[/cmd] %myobject->%fieldVariable
135
 
                [/example]
136
 
                The '-&gt;' operator has been stolen from the C language.
137
 
                In the KVIrc scripting language it switches from the global namespace
138
 
                to the object's one.[br]
139
 
                So in the above example %fieldVariable is owned by the object.[br]
140
 
                The first character of the variable name has no special meaning in the
141
 
                object namespace (in the global namespace the variables starting
142
 
                with an uppercase letter are global to the application , the other ones are local
143
 
                to the command sequence). The variable names are completely case insensitive.[br][br]
144
 
 
145
 
                Any [doc:operators]operator[/doc] can be used with the object field variables:[br]
146
 
                [example]
147
 
                        %myobject-&gt;%fieldVariable = 0
148
 
                        %myobject-&gt;%fieldVarialbe ++
149
 
                        [cmd]if[/cmd]0(%myobject->%fieldVariable != 1)[cmd]echo[/cmd] KVIrc is drunk , maybe a reboot will help ?
150
 
                [/example]
151
 
                You can simulate C structures "on the fly" by using objects and fields:[br]
152
 
                [example]
153
 
                        # Create an user description on the fly
154
 
                        %myobj = [fnc]$new[/fnc]([class]object[/class],0,userDescription)
155
 
                        # Set the fields
156
 
                        %myobj-&gt;%nickname = Pragma
157
 
                        %myobj-&gt;%username = daemon
158
 
                        %myobj-&gt;%hostname = pippo.pragma.org
159
 
                        %myobj-&gt;%info = Pragma goes always sleep too late
160
 
                        %myobj-&gt;%info [doc:operators]&lt;&lt;[/doc] and wakes up too late too!
161
 
                        # Call an (user defined) alias that stores the data to a file
162
 
                        storetofile %myobj
163
 
                        # Destroy the object
164
 
                        [cmd]delete[/cmd] %myobj
165
 
                [/example]
166
 
                The field variables can be also dictionaries:[br]
167
 
                [example]
168
 
                        %theobj-&gt;%field[key] = something
169
 
                [/example]
170
 
                Unlike in C , there is no need to declare object fields.
171
 
                Any object can have any field variable ; an "unset" field is equivalent to an "empty" field.[br]
172
 
                Note:[br]
173
 
                The KVIrc scripting language is not typed.
174
 
                Any object class (be patient...I'll explain classes in a while) identifier can be stored in any KVIrc variable:
175
 
                it is not possible to find out the object features by "examining" its identifier.
176
 
                This may make the usage of objects a bit "unclear";
177
 
                Howewer , with some experience you will be able to use the objects in a very powerful way.
178
 
                The type-safety can be also simulated by a careful usage of object names;
179
 
                in the above example , the %myobj object was created with the "userDescription" name.
180
 
                The storetofile alias could check the passed object's name and refuse to work
181
 
                if that does not match "userDescription".[br][br]
182
 
 
183
 
                A more complex use of fields will be described later in this document.[br][br]
184
 
 
185
 
                [big]Member functions[/big]
186
 
 
187
 
                Just like in C++ , the objects have member functions.
188
 
                For example , the "object" class (again...read on) objects export the [classfnc:object]$name[/classfnc]()
189
 
                and [classfnc:object]$className[/classfnc]() functions.[br]
190
 
                [example]
191
 
                        %tmp = [fnc]$new[/fnc]([class]object[/class],0,myobject)
192
 
                        [cmd]echo[/cmd] The object's name is %tmp->[classfnc:object]$name[/classfnc]() , the class name is %tmp->[classfnc:object]$className[/classfnc]()
193
 
                        # Destroy the object
194
 
                        [cmd]delete[/cmd] %tmp
195
 
                [/example]
196
 
                Another cool function exported by the [class:object]object[/class] class is the
197
 
                [classfnc:object]$children[/classfnc]() function.
198
 
                It returns a comma separated list of children identifiers.[br]
199
 
                [example]
200
 
                        %tmp = [fnc]$new[/fnc]([class]object[/class],0,myobject)
201
 
                        %tmpchild = [fnc]$new[/fnc]([class]object[/class],%tmp,child1)
202
 
                        %tmpchild = [fnc]$new[/fnc]([class]object[/class],%tmp,child2)
203
 
                        %tmpchild = [fnc]$new[/fnc]([class]object[/class],%tmp,child3)
204
 
                        [cmd]echo[/cmd] The object's children list is : %tmp->[classfnc:object]$children[/classfnc]()
205
 
                        # Destroy the object and the children
206
 
                        [cmd]delete[/cmd] %tmp
207
 
                [/example]
208
 
                There are two special functions for each objects: the "constructor" and the "destructor".
209
 
                You will find more information on constructors and destructors later in this document,
210
 
                for now it's enough that you know that these functions are called automatically by KVirc:
211
 
                the constructor is called when the object is created and the destructor is called when the
212
 
                object is being destroyed with [cmd]delete[/cmd].[br][br]
213
 
 
214
 
                The object functions can be reimplemented on-the-fly
215
 
                by using the [cmd]privateimpl[/cmd] command: you can simply modify the behaviour of the function
216
 
                by writing your own function body.
217
 
                (This is an uncommon feature: unlike many other languages , you can reimplement object
218
 
                functions at run-time, when the object has been already created.)[br][br]
219
 
 
220
 
                A more complex example[br]
221
 
                [example]
222
 
                        %tmp = [fnc]$new[/fnc]([class]object[/class],0,myobject)
223
 
                        [cmd]foreach[/cmd](%i,1,2,3)
224
 
                        {
225
 
                                %tmpchild = [fnc]$new[/fnc]([class]object[/class],%tmp,child%i)
226
 
                                [cmd]privateimpl[/cmd](%tmpchild,destructor){ [cmd]echo[/cmd] Object [fnc]$this[/fnc] ([fnc]$this[/fnc]-&gt;[classfnc:object]$name[/classfnc]()) destroyed; }
227
 
                        }
228
 
                        [cmd]privateimpl[/cmd](%tmp,destructor)
229
 
                        {
230
 
                                %count = 0;
231
 
                                [cmd]foreach[/cmd](%t,[fnc]$this[/fnc]-&gt;[classfnc:object]$children[/classfnc]())
232
 
                                {
233
 
                                        [cmd]echo[/cmd] Children : %t-&gt;[classfnc:object]$name[/classfnc]() with class %t-&gt;[classfnc:object]$class[/classfnc]()
234
 
                                        %count++
235
 
                                }
236
 
                                [cmd]echo[/cmd] Just before destroying my %count children.
237
 
                        }
238
 
                        # Destroy the object and the children
239
 
                        [cmd]delete[/cmd] %tmp
240
 
                [/example]
241
 
 
242
 
                In the example above four objects have been created.
243
 
                A "parent" object named "myobject" , and three children objects.
244
 
                The destructor has been reimplemented for each child object,
245
 
                to make it "say" its name (Please note the usage of [fnc]$this[/fnc]).
246
 
                In the parent destructor the children have been counted and listed.[br]
247
 
                Then the parent object is destroyed causing to:[br]
248
 
                - trigger the parent destructor.[br]
249
 
                - destroy all the children (and conseguently trigger all the "individual" destructors).[br][br]
250
 
 
251
 
                Not all the object functions must return a value:
252
 
                If a function does not return a meaningful value , or you just want to ignore it , you can call it in the following way:[br]
253
 
                [example]
254
 
                        %anyobject-&gt;$functionname()
255
 
                [/example]
256
 
                [br]
257
 
 
258
 
                [big]Classes[/big]
259
 
                As said before , all objects are instances of a specific class.
260
 
                This concept is common to almost all object oriented languages.
261
 
                A class is a collection of methods that define an object's behaviour.
262
 
                Hehe...it is not easy to explain it , so I'll try with an example:[br]
263
 
                [example]
264
 
                class HostAddress
265
 
                {
266
 
                        field hostname
267
 
                        function ipnumber()
268
 
                        function isLocalhost()
269
 
                }
270
 
                [/example]
271
 
                The above class is a rappresentation of a host address.
272
 
                You create an [b]instance of this class[/b] and set the hostname field, for example,
273
 
                to www.kernel.org.
274
 
                The object is now able to give you information about the hostname in a transparent way:
275
 
                You can call the ipnumber() function, and the object will return you the
276
 
                digits and dots rappresentation of www.kernel.org.
277
 
                The isLocalhost() function will return true if the hostname refers to the local machine
278
 
                The object internal job is hidden from the user , but probably it will be a huge job.
279
 
                To obtain the IP number from the hostname , the object will probably have to perform a DNS call (usually a complex task).
280
 
                To check if the hostname references the local machine , the object will have to obtain the local hostname
281
 
                from the system (in some "unspecified" way) and then compare it with the given "hostname" field.[br][br]
282
 
 
283
 
                The internal job of the object is defined by the "implementation of the class".
284
 
                Obviously , the programmer that creates the class has to write that implementation.[br]
285
 
 
286
 
                [example]
287
 
                class HostAddress
288
 
                {
289
 
                        field hostname
290
 
                        function ipnumber()
291
 
                        {
292
 
                                find the nearest DNS server
293
 
                                make the dns call
294
 
                                wait for the response
295
 
                                decode the response
296
 
                        }
297
 
                        function isLocalhost()
298
 
                        {
299
 
                                query the kernel for the local hostname
300
 
                                compare the obtained hostname with the hostname field
301
 
                        }
302
 
                }
303
 
                [/example]
304
 
                In the above example I have "implemented" the two functions by using a "fantastic" language.[br][br]
305
 
 
306
 
                Let's go back to the real world.[br][br]
307
 
 
308
 
                KVirc contains a [doc:classes]set of built-in ready-to-use classes[/doc].
309
 
                The basic class is [class]object[/class]: all the other classes are derived from this (more about
310
 
                object inheritance later in this doc).[br][br]
311
 
 
312
 
                Another available class is [class]socket[/class] that is an interface to the real system sockets.
313
 
                An instance of the [class]socket[/class] class can connect and communicate with other hosts on the net.[br][br]
314
 
 
315
 
                The [b]class definitions are GLOBAL to the entire application[/b]: all server windows share them.[br][br]
316
 
 
317
 
                So now we can say that in KVIrc
318
 
                [b]a CLASS is a collection of features that define the behaviour of an object.
319
 
                The user interface to the class are the member functions and the events.[/b][br][br]
320
 
 
321
 
                [big]Inheritance[/big]
322
 
 
323
 
                Someone asked for derived classes ?[br]
324
 
                Here we go:[br]
325
 
                The [cmd]class[/cmd] command allows you to define new object classes.
326
 
                In KVI++, A new class must be always derived from some other class: the lowest possible
327
 
                level of inheritance is 1: deriving from class [class]object[/class].[br]
328
 
                [example]
329
 
                        [cmd]class[/cmd](helloworld,object)
330
 
                        {
331
 
                                sayhello()
332
 
                                {
333
 
                                        [cmd]echo[/cmd] Hello world!
334
 
                                }
335
 
                        }
336
 
                [/example]
337
 
 
338
 
                The above class is named "helloworld". It inherits the [class]object[/class] class.
339
 
                This means that it acquires all the [class]object[/class] fuunctions: [classfnc:object]$name[/classfnc]() ,
340
 
                [classfnc:object]$class[/class]() , [classfnc:object]$children[/classfnc]()...
341
 
                Additionally , it has the $sayhello() function, that "echoes Hello world" to the console.
342
 
                Now you can create an instance of this class:
343
 
                [example]
344
 
                        %instance = [fnc]$new[/fnc](helloworld)
345
 
                        %instance->$sayhello()
346
 
                [/example]
347
 
                You should see "Hello world" printed in the console.
348
 
                Easy job...let's make the things a bit more complex now:
349
 
                derive another class from helloworld and make it say "hello" in two different languages:[br]
350
 
                [example]
351
 
                [cmd]class[/cmd](localizedhelloworld,helloworld)
352
 
                {
353
 
                        [comment]# define the setlanguage function[/comment]
354
 
                        [comment]# note that <$0 = language> is just a programmer reminder[/comment]
355
 
                        setlanguage(<$0 = language>)
356
 
                        {
357
 
                                [cmd]if[/cmd](($0 == english) || ($0 == italian))
358
 
                                {
359
 
                                        [fnc:$this]$$[/fnc]->%lang = $0
360
 
                                        [cmd]return[/cmd] 1
361
 
                                } else {
362
 
                                        [cmd]echo[/cmd] I don't know that language ($0)
363
 
                                        [cmd]echo[/cmd] defaulting to english
364
 
                                        [fnc:$this]$$[/fnc]->%lang = english
365
 
                                        [cmd]return[/cmd] 0
366
 
                                }
367
 
                        }
368
 
 
369
 
                        sayhello()
370
 
                        {
371
 
                                [cmd]if[/cmd]([fnc:$this]$$[/fnc]->%lang == italian)[cmd]echo[/cmd] Ciao mondo!
372
 
                                else [fnc:$this]$$[/fnc]->$helloworld:sayhello()
373
 
                        }
374
 
                }
375
 
                [/example]
376
 
                Now you can call:[br]
377
 
                [example]
378
 
                %m = [fnc]$new[/fnc](localizedhelloworld)
379
 
                %m->$setLanguage(italian)
380
 
                %m->$sayhello()
381
 
                %m->$setLanguage(english)
382
 
                %m->$sayhello()
383
 
                %m->$setLanguage(turkish)
384
 
                %m->$sayhello()
385
 
                [cmd]delete[/cmd] %myobj
386
 
                [/example]
387
 
                The class defined above is inherited from the previously defined helloworld class:
388
 
                so it inherits the "object" class functions and events and the sayhello function from "helloworld".
389
 
                In addition a setlanguage function is defined that stores in a variable the language name passed
390
 
                as a parameter (after checking its validity). ($0 evaluates to the first parameter passed)
391
 
                If the language is unknown the setlanguage function will return 0 (false).
392
 
                Now we want to be able to say "hello world" in italian and english.
393
 
                So we [b]override[/b] the inherited sayhello function.
394
 
                "To override" means "to reimplement" : if you call %object->$sayhello() and %object
395
 
                contains the ID of an instance of class "localizedhelloworld" , the new implementation of that function willl be called (executed).
396
 
                The inherited sayhello was able to say "hello world" only in english , so we can still use it in the new implementation
397
 
                without rewriting its contents. So if the language set is "not italian" we assume that it is english and
398
 
                call the [b]base class implementation[/b].[br]
399
 
                [example]
400
 
                        [fnc]$this/[fnc]->$helloworld:sayhello()
401
 
                        [comment]# equivalent to $$->$helloworld:sayhello(),[/comment]
402
 
                        [comment]# to $this->$helloworld::sayhello(),[/comment]
403
 
                        [comment]# and to $$->$helloworld::sayhello()[/comment]
404
 
                [/example]
405
 
                otherwise the language is italian and we say "hello" in italian :).
406
 
                So , to call a base class implementation of a function we "prepend" the base class name before the function name in the call.
407
 
                The base class name could be also [class]object[/class] in this case , but the [class]object[/class] class has no "sayhello" function defined
408
 
                so it would result in an error.[br][br]
409
 
                In the above example , all the values of [fnc]$this[/fnc]</a>-&gt;%language
410
 
                that are not equal to "italian" are assumed to be "english".
411
 
                This is not always true , for example , just after the object creation the %language variable field
412
 
                is effectively empty. The above class works correctly in this case , but we might want to have always
413
 
                a coherent state of the field variables , so we need another concept: the class [b]constructor[/b]
414
 
                that will be discussed in the next paragraph.[br][br]
415
 
 
416
 
                Note: multiple inheritance (inheritance from more than one base class) is not implemented , KVIrc is not a compiler :)[br][br]
417
 
 
418
 
                Objects are much more powerful....[br][br]
419
 
 
420
 
                Do a [cmd]clearobjects[/cmd] to cleanup the old class definitions , and read on.[br][br]
421
 
 
422
 
                [big]Constructors and destructors[/big]
423
 
 
424
 
                The class constructor is a [b]function[/b] that is called automatically just after the object
425
 
                has been created internally by KVIrc and just before the [fnc]$new[/fnc]
426
 
                function returns. It should be used to setup the internal object state.[br]
427
 
                Unlike in C++ , in KVIrc , the constructor CAN return a value:[br]
428
 
                If it returns 0 it signals the object creation failure : the object
429
 
                is immediately destroyed and [fnc]$new[/fnc]() returns 0 to the caller.
430
 
                Any other return value is treated as success , so the object is effectively
431
 
                created and [fnc]$new[/fnc]() returns its ID to the caller.[br]
432
 
                All the builtin classes have a constructor defined that will almost never fail (only if we run out of memory),
433
 
                so you can avoid to check the [fnc]$new[/fnc]() return value
434
 
                when creating the instances of the built-in classes.[br][br]
435
 
 
436
 
                In derived classes you can override the constructor to setup your object's state.[br]
437
 
                You should [b]always call the base class constructor[/b] in your overridden one , to setup
438
 
                the base class state , and propagate its return value (eventually modified if the base class
439
 
                constructor is succesfull but your derived class initialization fails).[br]
440
 
                In practice , the builtin class constructors do nothing other than setting the return
441
 
                value to 1 so you can even avoid to call them, but in any other case you must do it.[br][br]
442
 
 
443
 
                This is different from C (for example), where the constructors are called (more or less)
444
 
                automatically.[br][br]
445
 
 
446
 
                [big]Signals and slots[/big]
447
 
 
448
 
                The signals and slots are a powerful mean of inter-object communication.
449
 
                A signal is emitted by an object to notify a change in its state.
450
 
                For example , the [class:button]button class[/class] emits the
451
 
                [classsignal:button]clicked[/classsignal] signal when the user clicks the button.[br][br]
452
 
                A signal is emitted by an object and can be received and handled by any other existing object
453
 
                (including the object that emits the signal).[br]
454
 
                The handler function for a signal is called "slot".[br]
455
 
                It is just a convention : in fact , a slot is a normal object function (and any object function can be a slot).
456
 
                More than one slot can be connected to a single signal , and more signals can be connected to a single slot.[br]
457
 
                In this way , many objects can be notified of a change in a single object , as well as a single object
458
 
                can easily handle state-changes for many objects.[br]
459
 
                The signal / slot behaviour could be easily implemented by a careful usage of object functions.
460
 
                [b]So why signals and slots ?[/b][br]
461
 
                Because signals are much more powerful in many situations.
462
 
                The signals have no equivalent in C/C++...but they have been implemented in many highlevel
463
 
                C/C++ libraries and development kits (including the system-wide signal/handler mechanism implemented
464
 
                by all the modern kernels and used in inter-process communication).[br]
465
 
*/
466
 
 
467
 
 
468
 
 
469
 
 
470
 
///////////////////////////////////////////////////////////////////////////////////////
471
 
 
472
 
/*
473
 
        @doc: object
474
 
        @keyterms:
475
 
                object class, object, class
476
 
        @title:
477
 
                object class
478
 
        @type:
479
 
                class
480
 
        @short:
481
 
                Base class for all the KVIrc objects
482
 
        @inherits:
483
 
                none
484
 
        @description:
485
 
                This is the base class for all the builtin KVirc object classes.
486
 
                It exports the functions to retrieve the object name, to iterate
487
 
                through children objects and to lookup a child object by name or class.
488
 
                Additionally , this class provides the builtin timer functionality.
489
 
                The [classfnc]$constructor[/classfnc] and [classfnc]$destructor[/classfnc]
490
 
                functions are empty implementations that all the other classes inherit.
491
 
        @functions:
492
 
                !fn: $constructor()
493
 
                Constructor for this object class.
494
 
                The default implementation does nothing.
495
 
                !fn: $destructor()
496
 
                Destructor for this object class.
497
 
                The default implementation emits the signal "[classsignal]destroyed[/classsignal]".
498
 
                !fn: $name()
499
 
                Returns the name of this object.
500
 
                !fn: $parent()
501
 
                Returns the parent object of this object or 0 if this object has no parent.
502
 
                !fn: $timerEvent(<timerId>)
503
 
                Handler for the timer events.
504
 
                The default implementation does nothing.
505
 
                See also [classfnc]$startTimer[/classfnc]()
506
 
                and [classfnc]$killTimer[/classfnc]().
507
 
                !fn: $startTimer(<timeout>)
508
 
                Starts a builtin timer for this object and returns its timer id
509
 
                as a string or '-1' if the <timeout> was invalid.
510
 
                The [classfnc]$timerEvent[/classfnc]() handler function
511
 
                will be called at each <timeout>. The <timeout> is in milliseconds.
512
 
                !fn: $killTimer(<timer id>)
513
 
                Stops the timer specified by <timer id>.
514
 
                !fn: $className()
515
 
                Returns the class name of this object instance
516
 
                !fn: $findChild(<class>,<name>)
517
 
                Returns the first child that matches <class> and <name>.
518
 
                If <class> is an empty string, any class matches,
519
 
                if <name> is an empty string, any name matches.
520
 
                This function traverses the entire tree of children
521
 
                but is NOT recursive.
522
 
                !fn: $childCount()
523
 
                Returns the number of children objects
524
 
                !fn: $emit(<signal_name>[,parameters])
525
 
                Emits the signal <signal_name> passing the optional [parameters].
526
 
                See the [doc:objects]objects documentation[/doc] for an overview of signals and slots.
527
 
                !fn: $children()
528
 
                Returns an array of children object identifiers.
529
 
                !fn: $signalSender()
530
 
                Returns the current signal sender when in a slot connected to a signal.
531
 
                In other contexts this function returns an empty string.
532
 
                You can safely use it to test if the current function has been
533
 
                triggered directly or from a signal emission.
534
 
                !fn: $signalName()
535
 
                Returns the name of the signal last signal that has triggered
536
 
                one of this object's slots.
537
 
                This means that in a slot handler it returns the name of the signal
538
 
                that has triggered it.
539
 
                !fn: $property(<Qt property name>[,bNowarning:boolean])
540
 
                This is for really advanced scripting.[br]
541
 
                All KVIrc widgets are based on the Qt library ones.[br]
542
 
                The Qt library allow to set and read special properties.[br]
543
 
                You will have to take a look at the Qt documentation for each widget type
544
 
                to see the available property names.[br]
545
 
                The supported property types are: Rect, Size, Point, Color, String, CString,
546
 
                Int, UInt, Bool and enumeration types.[br]
547
 
                For example, the widget's x coordinate can be retrieved by using the [classfnc]$x[/classfnc]()
548
 
                function or by calling $property(x).[br]
549
 
                There are many properties that are available ony through the [classfnc]$property()[classfnc]" call:[br]
550
 
                For example, you can find out if the widget accepts drops by calling [classfnc]$property(acceptDrops)[classfnc].[br]
551
 
                This function will be mainly useful in the [class]wrapper[/class] class.
552
 
                !fn: $setProperty(<Qt property>,<property value>)
553
 
                Sets a qt property for this widget.[br]
554
 
                This is for advanced scripting, and can control really many features of the Qt widgets.[br]
555
 
                For example, the [class]multilineedit[/class] widgets can be set to
556
 
                the "password" echo mode only by using this function call:[br]
557
 
                [example]
558
 
                        %X=$new(lineedit, 0, a_name)
559
 
                        %X->$show()
560
 
                        %X->$setProperty(echoMode,Password)
561
 
                [/example]
562
 
                The available properties to be set are listed by [classfnc]$listProperties[/classfnc]()[br]
563
 
                and must appear in the list as writeable.[br]
564
 
                This function will be mainly useful in the [class]wrapper[/class] class.
565
 
                !fn: $listProperties([bArray])
566
 
                Lists the properties of this object.[br]
567
 
                If <bArray> is $true then the function returns the properties
568
 
                as an array of descriptive strings, otherwise the properties are dumped to the
569
 
                active window. If <bArray> is not passed then it is assumed to be $false.
570
 
                This function will be mainly useful in the [class]wrapper[/class] class.
571
 
        @signals:
572
 
                !sg: destroyed()
573
 
                Emitted by the default implementation of [classfnc]$destructor[/classfnc].
574
 
                If you reimplement [classfnc]$destructor[/classfnc] in one of the derived
575
 
                classes (or as a private implementation), and still want this signal
576
 
                to be emitted you must emit it by yourself, or (better) call the base class
577
 
                destructor.
578
 
*/
579
 
 
580
 
// we use a char * pointer just to store a number
581
 
// we don't use void * just because incrementing a void pointer doesn't look that good
582
 
static char * g_hNextObjectHandle = (char *)0;
583
 
 
584
 
 
585
 
KviKvsObject::KviKvsObject(KviKvsObjectClass * pClass,KviKvsObject * pParent,const QString &szName)
586
 
: QObject(pParent)
587
 
{
588
 
        if(g_hNextObjectHandle == 0)g_hNextObjectHandle++; // make sure it's never 0
589
 
        m_hObject = (kvs_hobject_t)g_hNextObjectHandle;
590
 
        g_hNextObjectHandle++;
591
 
 
592
 
        m_pObject            = 0;
593
 
        m_bObjectOwner       = true; // true by default
594
 
 
595
 
        m_szName             = szName;
596
 
 
597
 
        m_pClass             = pClass;
598
 
 
599
 
        m_pChildList         = new KviPointerList<KviKvsObject>;
600
 
        m_pChildList->setAutoDelete(false);
601
 
 
602
 
        m_pdataContainer     = new KviKvsHash();
603
 
 
604
 
        m_pFunctionHandlers  = 0; // no local function handlers yet!
605
 
 
606
 
        m_bInDelayedDeath    = false;
607
 
 
608
 
        m_pSignalDict        = 0; // no signals connected to remote slots
609
 
        m_pConnectionList    = 0; // no local slots connected to remote signals
610
 
 
611
 
        if(pParent)pParent->registerChild(this);
612
 
 
613
 
        KviKvsKernel::instance()->objectController()->registerObject(this);
614
 
 
615
 
//      debug("Hello world!");
616
 
//      [root@localhost cvs3]# kvirc
617
 
//      Hello world!
618
 
//      [root@localhost cvs3]# date
619
 
//      Tue Sep  5 21:53:54 CEST 2000
620
 
//      [root@localhost cvs3]#
621
 
 
622
 
//  Ported to KVS on 29.04.2005
623
 
}
624
 
 
625
 
KviKvsObject::~KviKvsObject()
626
 
{
627
 
        m_bInDelayedDeath = true;
628
 
        while(m_pChildList->first())delete m_pChildList->first();
629
 
        delete m_pChildList;
630
 
 
631
 
#if 0
632
 
        // Disconnect all the signals
633
 
        if(m_pSignalDict)
634
 
        {
635
 
                KviPointerHashTableIterator<QString,KviKvsObjectConnectionList> it(*m_pSignalDict);
636
 
 
637
 
                while(it.current())
638
 
                {
639
 
                        KviKvsObjectConnectionListIterator cit(*(it.current()));
640
 
                        while(cit.current())
641
 
                        {
642
 
                                disconnectSignal(it.currentKey(),cit.current());
643
 
                                // ++cit // NO!...we point to the next now!
644
 
                        }
645
 
                        // the iterator should automatically point to the next now
646
 
                        //if(m_pSignalDict)++it;
647
 
                }
648
 
        }
649
 
 
650
 
        // Disconnect all the slots
651
 
        if(m_pConnectionList)
652
 
        {
653
 
                KviKvsObjectConnectionListIterator cit(*m_pConnectionList);
654
 
                while(cit.current())
655
 
                {
656
 
                        QString szSig = cit.current()->szSignal;
657
 
                        cit.current()->pSourceObject->disconnectSignal(szSig,cit.current());
658
 
                        //++cit;// NO!... we point to the next now!
659
 
                }
660
 
        }
661
 
#else
662
 
        // Disconnect all the signals
663
 
        for(;;)
664
 
        {
665
 
                if(!m_pSignalDict)break;
666
 
                KviPointerHashTableEntry<QString,KviKvsObjectConnectionList> * pSignalList = m_pSignalDict->firstEntry();
667
 
                if(!pSignalList)break;
668
 
                KviKvsObjectConnection * pConnection = pSignalList->data()->first();
669
 
                if(!pConnection)break;
670
 
                disconnectSignal(pSignalList->key(),pConnection);
671
 
        }
672
 
 
673
 
        // Disconnect all the slots
674
 
        for(;;)
675
 
        {
676
 
                if(!m_pConnectionList)break;
677
 
                KviKvsObjectConnection * pConnection = m_pConnectionList->first();
678
 
                if(!pConnection)break;
679
 
                QString szSignalCopy = pConnection->szSignal; // we need this since pConnection is deleted inside disconnectSignal() and pConnection->szSignal dies too (but is referenced after the connection delete)
680
 
                pConnection->pSourceObject->disconnectSignal(szSignalCopy,pConnection);
681
 
        }
682
 
#endif
683
 
 
684
 
        KviKvsKernel::instance()->objectController()->unregisterObject(this);
685
 
 
686
 
        if(parentObject())parentObject()->unregisterChild(this);
687
 
 
688
 
        if(m_pObject)
689
 
        {
690
 
                disconnect(m_pObject,SIGNAL(destroyed()),this,SLOT(objectDestroyed()));
691
 
                if(m_bObjectOwner)delete m_pObject;
692
 
        }
693
 
 
694
 
        delete m_pdataContainer;
695
 
        if(m_pFunctionHandlers)delete m_pFunctionHandlers;
696
 
}
697
 
 
698
 
bool KviKvsObject::init(KviKvsRunTimeContext *,KviKvsVariantList *)
699
 
{
700
 
        return true;
701
 
}
702
 
 
703
 
QWidget * KviKvsObject::parentScriptWidget()
704
 
{
705
 
        if(parentObject())
706
 
        {
707
 
                if(parentObject()->object())
708
 
                {
709
 
                        if(parentObject()->object()->isWidgetType())
710
 
                                return (QWidget *)(parentObject()->object());
711
 
                }
712
 
        }
713
 
        return 0;
714
 
}
715
 
 
716
 
void KviKvsObject::unregisterChild(KviKvsObject *pChild)
717
 
{
718
 
        m_pChildList->removeRef(pChild);
719
 
}
720
 
 
721
 
void KviKvsObject::registerChild(KviKvsObject *pChild)
722
 
{
723
 
        m_pChildList->append(pChild);
724
 
}
725
 
 
726
 
// SIGNAL/SLOT stuff
727
 
 
728
 
bool KviKvsObject::connectSignal(const QString &sigName,KviKvsObject * pTarget,const QString &slotName)
729
 
{
730
 
        if(!pTarget->lookupFunctionHandler(slotName))return false; // no such slot
731
 
 
732
 
        if(!m_pSignalDict)
733
 
        {
734
 
                m_pSignalDict = new KviPointerHashTable<QString,KviKvsObjectConnectionList>(7,false);
735
 
                m_pSignalDict->setAutoDelete(true);
736
 
        }
737
 
 
738
 
        KviKvsObjectConnectionList * l = m_pSignalDict->find(sigName);
739
 
        if(!l)
740
 
        {
741
 
                l = new KviKvsObjectConnectionList;
742
 
                l->setAutoDelete(true);
743
 
                m_pSignalDict->insert(sigName,l);
744
 
        }
745
 
 
746
 
        KviKvsObjectConnection * con = new KviKvsObjectConnection;
747
 
 
748
 
        con->pSourceObject = this;
749
 
        con->pTargetObject = pTarget;
750
 
        con->szSignal      = sigName;
751
 
        con->szSlot        = slotName;
752
 
 
753
 
        l->append(con);
754
 
        pTarget->registerConnection(con);
755
 
        return true;
756
 
}
757
 
 
758
 
void KviKvsObject::registerConnection(KviKvsObjectConnection *pConnection)
759
 
{
760
 
        if(!m_pConnectionList)
761
 
        {
762
 
                m_pConnectionList = new KviKvsObjectConnectionList;
763
 
                m_pConnectionList->setAutoDelete(false);
764
 
        }
765
 
        m_pConnectionList->append(pConnection);
766
 
}
767
 
 
768
 
bool KviKvsObject::disconnectSignal(const QString &sigName,KviKvsObject * pTarget,const QString &slotName)
769
 
{
770
 
        if(!m_pSignalDict)return false; //no such signal to disconnect
771
 
 
772
 
        KviKvsObjectConnectionList * l = m_pSignalDict->find(sigName);
773
 
        if(!l)return false;
774
 
 
775
 
        KviKvsObjectConnectionListIterator it(*l);
776
 
 
777
 
        while(KviKvsObjectConnection * sl = it.current())
778
 
        {
779
 
                if(sl->pTargetObject == pTarget)
780
 
                {
781
 
                        if(KviQString::equalCI(sl->szSlot,slotName))
782
 
                        {
783
 
                                pTarget->unregisterConnection(sl);
784
 
                                l->removeRef(sl);
785
 
                                if(l->isEmpty())m_pSignalDict->remove(sigName);
786
 
                                if(m_pSignalDict->isEmpty())
787
 
                                {
788
 
                                        delete m_pSignalDict;
789
 
                                        m_pSignalDict = 0;
790
 
                                }
791
 
                                return true;
792
 
                        }
793
 
                }
794
 
                ++it;
795
 
        }
796
 
        return false;
797
 
}
798
 
 
799
 
bool KviKvsObject::disconnectSignal(const QString &sigName,KviKvsObjectConnection * pConnection)
800
 
{
801
 
        if(!m_pSignalDict)return false;
802
 
        KviKvsObjectConnectionList * l = m_pSignalDict->find(sigName);
803
 
        //__range_valid(l);
804
 
        if(!l)return false;
805
 
        pConnection->pTargetObject->unregisterConnection(pConnection);
806
 
        //__range_valid(l->findRef(pConnection) > -1);
807
 
        l->removeRef(pConnection);
808
 
        if(l->isEmpty())m_pSignalDict->remove(sigName);
809
 
        if(m_pSignalDict->isEmpty())
810
 
        {
811
 
                delete m_pSignalDict;
812
 
                m_pSignalDict = 0;
813
 
        }
814
 
        return true;
815
 
}
816
 
 
817
 
bool KviKvsObject::unregisterConnection(KviKvsObjectConnection * pConnection)
818
 
{
819
 
        if(!m_pConnectionList)return false;
820
 
        bool bOk = m_pConnectionList->removeRef(pConnection); // no auto delete !
821
 
        if(!bOk)return false;
822
 
        if(m_pConnectionList->isEmpty())
823
 
        {
824
 
                delete m_pConnectionList;
825
 
                m_pConnectionList = 0;
826
 
        }
827
 
        return true;
828
 
}
829
 
 
830
 
int KviKvsObject::emitSignal(const QString &sigName,KviKvsObjectFunctionCall * pOuterCall,KviKvsVariantList * pParams)
831
 
{
832
 
        if(!m_pSignalDict)return 0;
833
 
 
834
 
        KviKvsObjectConnectionList * l = m_pSignalDict->find(sigName);
835
 
        if(!l)return 0; // no slots registered
836
 
 
837
 
        KviKvsVariant retVal;
838
 
 
839
 
        // The objects we're going to disconnect
840
 
        KviPointerList<KviKvsObjectConnection> * pDis = 0;
841
 
 
842
 
        kvs_int_t emitted = 0;
843
 
 
844
 
        KviKvsObjectConnectionListIterator it(*l);
845
 
 
846
 
        while(KviKvsObjectConnection * s = it.current())
847
 
        {
848
 
                // save it , since s may be destroyed in the call!
849
 
                KviKvsObject * pTarget = s->pTargetObject;
850
 
 
851
 
                emitted++;
852
 
 
853
 
                kvs_hobject_t hTarget = pTarget->handle();
854
 
                kvs_hobject_t hOld = pTarget->signalSender();
855
 
 
856
 
                pTarget->setSignalSender(m_hObject);
857
 
                pTarget->setSignalName(sigName);
858
 
 
859
 
                if(!pTarget->callFunction(this,s->szSlot,QString(),pOuterCall->context(),&retVal,pParams))
860
 
                {
861
 
                        if(KviKvsKernel::instance()->objectController()->lookupObject(hTarget) && it.current())
862
 
                        {
863
 
                                pOuterCall->warning(
864
 
                                        __tr2qs_ctx("Broken slot '%Q' in target object '%Q::%Q' while emitting signal '%Q' from object '%Q::%Q': disconnecting","kvs"),
865
 
                                        &(s->szSlot),
866
 
                                        &(s->pTargetObject->getClass()->name()),
867
 
                                        &(s->pTargetObject->getName()),
868
 
                                        &(sigName),
869
 
                                        &(getClass()->name()),
870
 
                                        &m_szName);
871
 
 
872
 
                                if(!pDis)
873
 
                                {
874
 
                                        pDis = new KviPointerList<KviKvsObjectConnection>;
875
 
                                        pDis->setAutoDelete(false);
876
 
                                }
877
 
                                pDis->append(s);
878
 
                        } else {
879
 
                                // else destroyed in the call! (already disconnected)
880
 
 
881
 
                                pOuterCall->warning(
882
 
                                        __tr2qs_ctx("Slot target object destroyed while emitting signal '%Q' from object '%Q::%Q'","kvs"),
883
 
                                        &(sigName),
884
 
                                        &(getClass()->name()),
885
 
                                        &m_szName);
886
 
                        }
887
 
                }
888
 
 
889
 
                if(KviKvsKernel::instance()->objectController()->lookupObject(hTarget))
890
 
                {
891
 
                        pTarget->setSignalSender(hOld);
892
 
                }
893
 
 
894
 
                ++it;
895
 
        }
896
 
 
897
 
        if(pDis)
898
 
        {
899
 
                // we have some signals to disconnect (because they're broken)
900
 
                for(KviKvsObjectConnection * con = pDis->first();con;con = pDis->next())
901
 
                        disconnectSignal(sigName,con);
902
 
                delete pDis;
903
 
        }
904
 
 
905
 
        return emitted;
906
 
}
907
 
 
908
 
bool KviKvsObject::function_name(KviKvsObjectFunctionCall * c)
909
 
{
910
 
        c->returnValue()->setString(getName());
911
 
        return true;
912
 
}
913
 
 
914
 
bool KviKvsObject::function_parent(KviKvsObjectFunctionCall * c)
915
 
{
916
 
        KviKvsObject * o = parentObject();
917
 
        c->returnValue()->setHObject(o ? o->handle() : (kvs_hobject_t)0);
918
 
        return true;
919
 
}
920
 
 
921
 
bool KviKvsObject::function_className(KviKvsObjectFunctionCall * c)
922
 
{
923
 
        c->returnValue()->setString(getClass()->name());
924
 
        return true;
925
 
}
926
 
 
927
 
bool KviKvsObject::function_childCount(KviKvsObjectFunctionCall * c)
928
 
{
929
 
        c->returnValue()->setInteger((kvs_int_t)(m_pChildList->count()));
930
 
        return true;
931
 
}
932
 
 
933
 
bool KviKvsObject::function_signalSender(KviKvsObjectFunctionCall * c)
934
 
{
935
 
        c->returnValue()->setHObject(m_hSignalSender);
936
 
        return true;
937
 
}
938
 
 
939
 
bool KviKvsObject::function_signalName(KviKvsObjectFunctionCall * c)
940
 
{
941
 
        c->returnValue()->setString(m_szSignalName);
942
 
        return true;
943
 
}
944
 
 
945
 
bool KviKvsObject::function_destructor(KviKvsObjectFunctionCall * c)
946
 
{
947
 
        emitSignal("destroyed",c);
948
 
        return true;
949
 
}
950
 
 
951
 
bool KviKvsObject::function_children(KviKvsObjectFunctionCall * c)
952
 
{
953
 
        KviKvsArray * a = new KviKvsArray();
954
 
        int id=0;
955
 
        for(KviKvsObject * o = m_pChildList->first();o;o = m_pChildList->next())
956
 
        {
957
 
                a->set(id,new KviKvsVariant(o->handle()));
958
 
                id++;
959
 
        }
960
 
        c->returnValue()->setArray(a);
961
 
        return true;
962
 
}
963
 
 
964
 
bool KviKvsObject::function_findChild(KviKvsObjectFunctionCall * c)
965
 
{
966
 
        QString szClass,szName;
967
 
        KVSO_PARAMETERS_BEGIN(c)
968
 
                KVSO_PARAMETER("className",KVS_PT_STRING,KVS_PF_OPTIONAL,szClass)
969
 
                KVSO_PARAMETER("objectName",KVS_PT_STRING,KVS_PF_OPTIONAL,szName)
970
 
        KVSO_PARAMETERS_END(c)
971
 
 
972
 
        KviKvsObject * o = findChild(szClass,szName);
973
 
        c->returnValue()->setHObject(o ? o->handle() : (kvs_hobject_t)0);
974
 
 
975
 
        return true;
976
 
}
977
 
 
978
 
bool KviKvsObject::function_emit(KviKvsObjectFunctionCall * c)
979
 
{
980
 
        QString szSignal;
981
 
        KviKvsVariantList vList;
982
 
        KVSO_PARAMETERS_BEGIN(c)
983
 
                KVSO_PARAMETER("signal",KVS_PT_NONEMPTYSTRING,0,szSignal)
984
 
                KVSO_PARAMETER("params",KVS_PT_VARIANTLIST,KVS_PF_OPTIONAL,vList)
985
 
        KVSO_PARAMETERS_END(c)
986
 
 
987
 
        emitSignal(szSignal,c,&vList);
988
 
        return true;
989
 
}
990
 
 
991
 
bool KviKvsObject::function_startTimer(KviKvsObjectFunctionCall * c)
992
 
{
993
 
        kvs_uint_t timeout;
994
 
        KVSO_PARAMETERS_BEGIN(c)
995
 
                KVSO_PARAMETER("timeout",KVS_PT_UINT,0,timeout)
996
 
        KVSO_PARAMETERS_END(c)
997
 
 
998
 
        c->returnValue()->setInteger((kvs_int_t)(startTimer(timeout)));
999
 
        return true;
1000
 
}
1001
 
 
1002
 
bool KviKvsObject::function_killTimer(KviKvsObjectFunctionCall * c)
1003
 
{
1004
 
        kvs_int_t id;
1005
 
        KVSO_PARAMETERS_BEGIN(c)
1006
 
                KVSO_PARAMETER("timerId",KVS_PT_INT,0,id)
1007
 
        KVSO_PARAMETERS_END(c)
1008
 
        killTimer(id);
1009
 
        return true;
1010
 
}
1011
 
 
1012
 
bool KviKvsObject::function_listProperties(KviKvsObjectFunctionCall * c)
1013
 
{
1014
 
        bool bArray;
1015
 
        KVSO_PARAMETERS_BEGIN(c)
1016
 
                KVSO_PARAMETER("bArray",KVS_PT_BOOL,KVS_PF_OPTIONAL,bArray)
1017
 
        KVSO_PARAMETERS_END(c)
1018
 
 
1019
 
        c->returnValue()->setNothing();
1020
 
 
1021
 
        KviKvsArray * a = bArray ? new KviKvsArray() : 0;
1022
 
 
1023
 
        KviWindow * w = c->context()->window();
1024
 
 
1025
 
        if(!bArray)
1026
 
                w->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs_ctx("Listing Qt properties for object named '%Q' of KVS class %Q","kvs"),&m_szName,&(m_pClass->name()));
1027
 
        kvs_int_t cnt = 0;
1028
 
        if(m_pObject)
1029
 
        {
1030
 
                const QMetaObject *o = m_pObject->metaObject();
1031
 
                if(!bArray)
1032
 
                        w->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs_ctx("Properties for Qt class %s","kvs"),o->className());
1033
 
                        kvs_int_t idx = 0;
1034
 
                        QMetaProperty prop = o->property(idx);
1035
 
                        const QMetaProperty *p = &prop;
1036
 
                        while(p)
1037
 
                        {
1038
 
                                QString szOut;
1039
 
                                QString szName = p->name();
1040
 
                                QString szType = p->typeName();
1041
 
                                if(bArray)
1042
 
                                        KviQString::sprintf(szOut,"%Q, %Q",&szName,&szType);
1043
 
                                else {
1044
 
                                        KviQString::sprintf(szOut,__tr2qs_ctx("Property: %c%Q%c, type %Q","kvs"),KVI_TEXT_BOLD,&szName,KVI_TEXT_BOLD,&szType);
1045
 
                                        szOut.prepend(" ");
1046
 
                                }
1047
 
 
1048
 
                                if(p->isEnumType())
1049
 
                                {
1050
 
                                        szOut += ", enum(";
1051
 
                                        szOut += ")";
1052
 
                                }
1053
 
 
1054
 
 
1055
 
                                // FIXME: QT4 Need to read better the docs and check the changes: there seem to be too many
1056
 
                                //        for me to fix now. Actually I need to get the whole executable working...
1057
 
                                if(p->isWritable())szOut += ", writable";
1058
 
                                if(bArray)
1059
 
                                        a->set(cnt,new KviKvsVariant(szOut));
1060
 
                                else
1061
 
                                        w->outputNoFmt(KVI_OUT_SYSTEMMESSAGE,szOut);
1062
 
                                idx++;
1063
 
                                if (idx<o->propertyCount()){
1064
 
                                        prop = o->property(idx);
1065
 
                                        p = &prop;
1066
 
                                }
1067
 
                                else p=0;
1068
 
                                cnt++;
1069
 
                        }
1070
 
 
1071
 
        }
1072
 
 
1073
 
        if(bArray)
1074
 
                c->returnValue()->setArray(a);
1075
 
        else
1076
 
                w->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs_ctx("%d properties listed","kvs"),cnt);
1077
 
        return true;
1078
 
}
1079
 
 
1080
 
bool KviKvsObject::function_setProperty(KviKvsObjectFunctionCall * c)
1081
 
{
1082
 
        QString szName;
1083
 
        KviKvsVariant * v;
1084
 
        KVSO_PARAMETERS_BEGIN(c)
1085
 
                KVSO_PARAMETER("propertyName",KVS_PT_NONEMPTYSTRING,0,szName)
1086
 
                KVSO_PARAMETER("propertyValue",KVS_PT_VARIANT,0,v)
1087
 
        KVSO_PARAMETERS_END(c)
1088
 
 
1089
 
        c->returnValue()->setNothing();
1090
 
 
1091
 
        if(!m_pObject)
1092
 
        {
1093
 
                // there are no Qt properties at all
1094
 
                c->warning(__tr2qs_ctx("The object named '%Q' of class '%Q' has no Qt properties","kvs"),&m_szName,&(m_pClass->name()));
1095
 
                return true;
1096
 
        }
1097
 
 
1098
 
        int idx = m_pObject->metaObject()->indexOfProperty(szName.toUtf8().data());
1099
 
        if(idx < 0)
1100
 
        {
1101
 
                c->warning(__tr2qs_ctx("No Qt property named '%Q' for object named '%Q' of class '%Q'","kvs"),&szName,&m_szName,&(m_pClass->name()));
1102
 
                return true;
1103
 
        }
1104
 
        QMetaProperty prop = m_pObject->metaObject()->property(idx);
1105
 
        const QMetaProperty * p = &prop;
1106
 
        if(!p)
1107
 
        {
1108
 
                c->warning(__tr2qs_ctx("Can't find property named '%Q' for object named '%Q' of class '%Q': the property is indexed but it doesn't really exist","kvs"),&szName,&m_szName,&(m_pClass->name()));
1109
 
                return true;
1110
 
        }
1111
 
 
1112
 
        QVariant vv = m_pObject->property(szName.toUtf8().data());
1113
 
        if(!vv.isValid())
1114
 
        {
1115
 
                c->warning(__tr2qs_ctx("Can't find property named '%Q' for object named '%Q'of class '%Q': the property is indexed and defined but the returned variant is not valid","kvs"),&szName,&m_szName,&(m_pClass->name()));
1116
 
                return true;
1117
 
        }
1118
 
 
1119
 
        if(p->isEnumType())
1120
 
        {
1121
 
                QString szKey;
1122
 
                v->asString(szKey);
1123
 
                int val = p->enumerator().keyToValue(szKey.toUtf8().data());
1124
 
                QVariant var(val);
1125
 
                m_pObject->setProperty(szName.toUtf8().data(),var);
1126
 
                return true;
1127
 
        }
1128
 
 
1129
 
#define WRONG_TYPE(__therighttype) \
1130
 
        { \
1131
 
                c->warning(__tr2qs_ctx("The property is of type %s but the supplied argument can't be converted to that type (expecting '%s')","kvs"),p->type(),__therighttype); \
1132
 
                return true; \
1133
 
        }
1134
 
 
1135
 
        switch(vv.type())
1136
 
        {
1137
 
                case QVariant::Int:
1138
 
                {
1139
 
                        kvs_int_t i;
1140
 
                        if(!v->asInteger(i))WRONG_TYPE("integer")
1141
 
                        m_pObject->setProperty(szName.toUtf8().data(),QVariant((int)i));
1142
 
                }
1143
 
                break;
1144
 
                case QVariant::UInt:
1145
 
                {
1146
 
                        kvs_int_t i;
1147
 
                        if(!v->asInteger(i))WRONG_TYPE("unsigned integer")
1148
 
                        if(i < 0)WRONG_TYPE("unsigned integer")
1149
 
                        m_pObject->setProperty(szName.toUtf8().data(),QVariant((unsigned int)i));
1150
 
                }
1151
 
                case QVariant::Double:
1152
 
                {
1153
 
                        kvs_real_t i;
1154
 
                        if(!v->asReal(i))WRONG_TYPE("real")
1155
 
                        m_pObject->setProperty(szName.toUtf8().data(),QVariant((double)i));
1156
 
                }
1157
 
                break;
1158
 
                case QVariant::Bool:
1159
 
                        m_pObject->setProperty(szName.toUtf8().data(),QVariant(v->asBoolean()));
1160
 
                break;
1161
 
                case QVariant::String:
1162
 
                {
1163
 
                        QString s;
1164
 
                        v->asString(s);
1165
 
                        m_pObject->setProperty(szName.toUtf8().data(),QVariant(s));
1166
 
                }
1167
 
                break;
1168
 
                case QVariant::ByteArray:
1169
 
                {
1170
 
                        QString s;
1171
 
                        v->asString(s);
1172
 
                        m_pObject->setProperty(szName.toUtf8().data(),QVariant(s.toUtf8()));
1173
 
                }
1174
 
                break;
1175
 
                case QVariant::Point:
1176
 
                {
1177
 
                        if(!v->isArray())WRONG_TYPE("array(integer,integer)")
1178
 
                        KviKvsArray * a = v->array();
1179
 
                        KviKvsVariant * x = a->at(0);
1180
 
                        KviKvsVariant * y = a->at(1);
1181
 
                        if(!x || !y)WRONG_TYPE("array(integer,integer)")
1182
 
                        kvs_int_t iX,iY;
1183
 
                        if(!x->asInteger(iX) || !y->asInteger(iY))WRONG_TYPE("array(integer,integer)")
1184
 
                        m_pObject->setProperty(szName.toUtf8().data(),QVariant(QPoint(iX,iY)));
1185
 
                }
1186
 
                break;
1187
 
                case QVariant::Size:
1188
 
                {
1189
 
                        if(!v->isArray())WRONG_TYPE("array(integer,integer)")
1190
 
                        KviKvsArray * a = v->array();
1191
 
                        KviKvsVariant * w = a->at(0);
1192
 
                        KviKvsVariant * h = a->at(1);
1193
 
                        if(!w || !h)WRONG_TYPE("array(integer,integer)")
1194
 
                        kvs_int_t iW,iH;
1195
 
                        if(!w->asInteger(iW) || !h->asInteger(iH))WRONG_TYPE("array(integer,integer)")
1196
 
                        m_pObject->setProperty(szName.toUtf8().data(),QVariant(QSize(iW,iH)));
1197
 
                }
1198
 
                break;
1199
 
                case QVariant::Rect:
1200
 
                {
1201
 
                        if(!v->isArray())WRONG_TYPE("array(integer,integer,integer,integer)")
1202
 
                        KviKvsArray * a = v->array();
1203
 
                        KviKvsVariant * x = a->at(0);
1204
 
                        KviKvsVariant * y = a->at(1);
1205
 
                        KviKvsVariant * w = a->at(2);
1206
 
                        KviKvsVariant * h = a->at(3);
1207
 
                        if(!x || !y || !w || !h)WRONG_TYPE("array(integer,integer,integer,integer)")
1208
 
                        kvs_int_t iX,iY,iW,iH;
1209
 
                        if(!x->asInteger(iX) || !y->asInteger(iY) || !w->asInteger(iW) || !h->asInteger(iH))WRONG_TYPE("array(integer,integer,integer,integer)")
1210
 
                        m_pObject->setProperty(szName.toUtf8().data(),QVariant(QRect(iX,iY,iW,iH)));
1211
 
                }
1212
 
                break;
1213
 
 
1214
 
                case QVariant::Color:
1215
 
                {
1216
 
                        if(!v->isArray())WRONG_TYPE("array(integer,integer,integer)")
1217
 
                        KviKvsArray * a = v->array();
1218
 
                        KviKvsVariant * r = a->at(0);
1219
 
                        KviKvsVariant * g = a->at(1);
1220
 
                        KviKvsVariant * b = a->at(3);
1221
 
                        if(!r || !g || !b)WRONG_TYPE("array(integer,integer,integer)")
1222
 
                        kvs_int_t iR,iG,iB;
1223
 
                        if(!r->asInteger(iR) || !g->asInteger(iG) || !b->asInteger(iB))WRONG_TYPE("array(integer,integer,integer)")
1224
 
                        m_pObject->setProperty(szName.toUtf8().data(),QVariant(QColor(iR,iG,iB)));
1225
 
                }
1226
 
                break;
1227
 
                case QVariant::Font:
1228
 
                {
1229
 
                        if(!v->isArray())WRONG_TYPE("array(string,integer,string)")
1230
 
                        KviKvsArray * a = v->array();
1231
 
                        KviKvsVariant * ff = a->at(0);
1232
 
                        KviKvsVariant * ps = a->at(1);
1233
 
                        KviKvsVariant * fl = a->at(3);
1234
 
                        if(!ff || !ps)WRONG_TYPE("array(string,integer,string)")
1235
 
                        kvs_int_t iPs;
1236
 
                        if(!ps->asInteger(iPs))WRONG_TYPE("array(string,integer,string)")
1237
 
                        QString szFf,szFl;
1238
 
                        ff->asString(szFf);
1239
 
                        if(fl)fl->asString(szFl);
1240
 
                        QFont fnt;
1241
 
                        fnt.setFamily(szFf);
1242
 
                        fnt.setPointSize(iPs);
1243
 
                        if(szFl.indexOf('b',Qt::CaseInsensitive) != -1)fnt.setBold(true);
1244
 
                        if(szFl.indexOf('i',Qt::CaseInsensitive) != -1)fnt.setItalic(true);
1245
 
                        if(szFl.indexOf('u',Qt::CaseInsensitive) != -1)fnt.setUnderline(true);
1246
 
                        if(szFl.indexOf('o',Qt::CaseInsensitive) != -1)fnt.setOverline(true);
1247
 
                        if(szFl.indexOf('f',Qt::CaseInsensitive) != -1)fnt.setFixedPitch(true);
1248
 
                        if(szFl.indexOf('s',Qt::CaseInsensitive) != -1)fnt.setStrikeOut(true);
1249
 
                        m_pObject->setProperty(szName.toUtf8().data(),QVariant(fnt));
1250
 
                }
1251
 
                break;
1252
 
                case QVariant::Pixmap:
1253
 
                        {
1254
 
                        if(v->isHObject())
1255
 
                        {
1256
 
                                if(v->hobject() == (kvs_hobject_t)0)
1257
 
                                {
1258
 
                                        // null pixmap
1259
 
                                        if(vv.type() == QVariant::Pixmap)
1260
 
                                                m_pObject->setProperty(szName.toUtf8().data(),QVariant(QPixmap()));
1261
 
                                        else
1262
 
                                                m_pObject->setProperty(szName.toUtf8().data(),QVariant(QIcon()));
1263
 
                                } else {
1264
 
                                        KviKvsObject * pix = KviKvsKernel::instance()->objectController()->lookupObject(v->hobject());
1265
 
                                        if(!pix->inherits("KviScriptPixmapObject"))
1266
 
                                                c->warning(__tr2qs_ctx("A pixmap object, an image_id or an image file path is required for this property","kvs"));
1267
 
                                        else {
1268
 
                                                QVariant pixv = pix->property("pixmap");
1269
 
                                                if(vv.type() == QVariant::Pixmap)
1270
 
                                                        m_pObject->setProperty(szName.toUtf8().data(),QVariant(pixv.value<QPixmap>()));
1271
 
                                                else
1272
 
                                                        m_pObject->setProperty(szName.toUtf8().data(),QVariant(QIcon(pixv.value<QPixmap>())));
1273
 
                                        }
1274
 
                                }
1275
 
                        } else {
1276
 
                                QString szStr;
1277
 
                                v->asString(szStr);
1278
 
                                QPixmap * pPix = g_pIconManager->getImage(szStr);
1279
 
                                if(pPix)
1280
 
                                {
1281
 
                                        if(vv.type() == QVariant::Pixmap)
1282
 
                                                m_pObject->setProperty(szName.toUtf8().data(),QVariant(*pPix));
1283
 
                                        else
1284
 
                                                m_pObject->setProperty(szName.toUtf8().data(),QVariant(QIcon(*pPix)));
1285
 
                                }
1286
 
                                else
1287
 
                                        c->warning(__tr2qs_ctx("Can't find the requested image","kvs"));
1288
 
                        }
1289
 
                }
1290
 
 
1291
 
                break;
1292
 
 
1293
 
                default:
1294
 
                        c->warning(__tr2qs_ctx("Property '%Q' for object named '%Q' of class '%Q' has an unsupported data type","kvs"),&szName,&m_szName,&(m_pClass->name()));
1295
 
                        c->returnValue()->setNothing();
1296
 
                break;
1297
 
        }
1298
 
        return true;
1299
 
}
1300
 
 
1301
 
bool KviKvsObject::function_property(KviKvsObjectFunctionCall * c)
1302
 
{
1303
 
        QString szName;
1304
 
        bool bNoerror;
1305
 
        KVSO_PARAMETERS_BEGIN(c)
1306
 
                KVSO_PARAMETER("propertyName",KVS_PT_NONEMPTYSTRING,0,szName)
1307
 
                KVSO_PARAMETER("bNowarning",KVS_PT_BOOL,KVS_PF_OPTIONAL,bNoerror)
1308
 
        KVSO_PARAMETERS_END(c)
1309
 
 
1310
 
        if(!m_pObject)
1311
 
        {
1312
 
                // there are no Qt properties at all
1313
 
                if (bNoerror) c->returnValue()->setString("No Qt properties");
1314
 
                else
1315
 
                {
1316
 
                        c->warning(__tr2qs_ctx("The object named '%Q' of class '%Q' has no Qt properties","kvs"),&m_szName,&(m_pClass->name()));
1317
 
                        c->returnValue()->setNothing();
1318
 
                }
1319
 
                return true;
1320
 
        }
1321
 
 
1322
 
        int idx = m_pObject->metaObject()->indexOfProperty(szName.toUtf8().data());
1323
 
        if(idx < 0)
1324
 
        {
1325
 
                if(bNoerror)
1326
 
                        c->returnValue()->setString("No Qt properties");
1327
 
                else
1328
 
                {
1329
 
                        c->warning(__tr2qs_ctx("No Qt property named '%Q' for object named '%Q' of class '%Q'","kvs"),&szName,&m_szName,&(m_pClass->name()));
1330
 
                        c->returnValue()->setNothing();
1331
 
                }
1332
 
                return true;
1333
 
        }
1334
 
        QMetaProperty prop = m_pObject->metaObject()->property(idx);
1335
 
        const QMetaProperty * p = &prop;
1336
 
        if(!p)
1337
 
        {
1338
 
                c->warning(__tr2qs_ctx("Can't find property named '%Q' for object named '%Q' of class '%Q': the property is indexed but it doesn't really exist","kvs"),&szName,&m_szName,&(m_pClass->name()));
1339
 
                c->returnValue()->setNothing();
1340
 
                return true;
1341
 
        }
1342
 
 
1343
 
        QVariant v = m_pObject->property(szName.toUtf8().data());
1344
 
        if(!v.isValid())
1345
 
        {
1346
 
                c->warning(__tr2qs_ctx("Can't find property named '%Q' for object named '%Q' of class '%Q': the property is indexed and defined but the returned variant is not valid","kvs"),&szName,&m_szName,&(m_pClass->name()));
1347
 
                c->returnValue()->setNothing();
1348
 
                return true;
1349
 
        }
1350
 
 
1351
 
        if(p->isEnumType())
1352
 
        {
1353
 
                c->returnValue()->setString(p->enumerator().valueToKey(v.toInt()));
1354
 
                return true;
1355
 
        }
1356
 
 
1357
 
        switch(v.type())
1358
 
        {
1359
 
                case QVariant::Int:
1360
 
                        c->returnValue()->setInteger((kvs_int_t)v.toInt());
1361
 
                break;
1362
 
                case QVariant::Double:
1363
 
                        c->returnValue()->setReal((kvs_int_t)v.toDouble());
1364
 
                break;
1365
 
                case QVariant::UInt:
1366
 
                        c->returnValue()->setInteger((kvs_int_t)v.toUInt());
1367
 
                break;
1368
 
                case QVariant::Bool:
1369
 
                        c->returnValue()->setBoolean(v.toBool());
1370
 
                break;
1371
 
                case QVariant::String:
1372
 
                        c->returnValue()->setString(v.toString());
1373
 
                break;
1374
 
                case QVariant::ByteArray:
1375
 
                        c->returnValue()->setString(QString::fromUtf8(v.toByteArray().data()));
1376
 
                break;
1377
 
                case QVariant::Point:
1378
 
                {
1379
 
                        QPoint p = v.toPoint();
1380
 
                        KviKvsArray * a = new KviKvsArray();
1381
 
                        a->set(0,new KviKvsVariant((kvs_int_t)p.x()));
1382
 
                        a->set(1,new KviKvsVariant((kvs_int_t)p.y()));
1383
 
                        c->returnValue()->setArray(a);
1384
 
                }
1385
 
                break;
1386
 
                case QVariant::Size:
1387
 
                {
1388
 
                        QSize p = v.toSize();
1389
 
                        KviKvsArray * a = new KviKvsArray();
1390
 
                        a->set(0,new KviKvsVariant((kvs_int_t)p.width()));
1391
 
                        a->set(1,new KviKvsVariant((kvs_int_t)p.height()));
1392
 
                        c->returnValue()->setArray(a);
1393
 
                }
1394
 
                break;
1395
 
                case QVariant::Rect:
1396
 
                {
1397
 
                        QRect p = v.toRect();
1398
 
                        KviKvsArray * a = new KviKvsArray();
1399
 
                        a->set(0,new KviKvsVariant((kvs_int_t)p.x()));
1400
 
                        a->set(1,new KviKvsVariant((kvs_int_t)p.y()));
1401
 
                        a->set(2,new KviKvsVariant((kvs_int_t)p.width()));
1402
 
                        a->set(3,new KviKvsVariant((kvs_int_t)p.height()));
1403
 
                        c->returnValue()->setArray(a);
1404
 
                }
1405
 
                break;
1406
 
                case QVariant::Color:
1407
 
                {
1408
 
                        QColor clr = v.value<QColor>();
1409
 
                        KviKvsArray * a = new KviKvsArray();
1410
 
                        a->set(0,new KviKvsVariant((kvs_int_t)clr.red()));
1411
 
                        a->set(1,new KviKvsVariant((kvs_int_t)clr.green()));
1412
 
                        a->set(2,new KviKvsVariant((kvs_int_t)clr.blue()));
1413
 
                        c->returnValue()->setArray(a);
1414
 
                }
1415
 
                break;
1416
 
                case QVariant::Font:
1417
 
                {
1418
 
                        QFont f = v.value<QFont>();
1419
 
                        KviKvsArray * a = new KviKvsArray();
1420
 
                        a->set(0,new KviKvsVariant(f.family()));
1421
 
                        a->set(1,new KviKvsVariant((kvs_int_t)f.pointSize()));
1422
 
                        QString szFlags;
1423
 
                        if(f.bold())szFlags += "b";
1424
 
                        if(f.underline())szFlags += "u";
1425
 
                        if(f.overline())szFlags += "o";
1426
 
                        if(f.strikeOut())szFlags += "s";
1427
 
                        if(f.fixedPitch())szFlags += "f";
1428
 
                        if(f.italic())szFlags += "i";
1429
 
                        a->set(2,new KviKvsVariant(szFlags));
1430
 
                        c->returnValue()->setString(szFlags);
1431
 
                }
1432
 
                break;
1433
 
                default:
1434
 
                        if (bNoerror) c->returnValue()->setString("Unsupported_data_type");
1435
 
                        else
1436
 
                        {
1437
 
                                c->warning(__tr2qs_ctx("Property '%Q' for object named '%Q' of class '%Q' has an unsupported data type","kvs"),&szName,&m_szName,&(m_pClass->name()));
1438
 
                                c->returnValue()->setNothing();
1439
 
                        }
1440
 
                break;
1441
 
        }
1442
 
        return true;
1443
 
}
1444
 
 
1445
 
void KviKvsObject::killAllChildrenWithClass(KviKvsObjectClass *cl)
1446
 
{
1447
 
        KviPointerList<KviKvsObject> l;
1448
 
        l.setAutoDelete(true);
1449
 
        for(KviKvsObject * o=m_pChildList->first();o;o=m_pChildList->next())
1450
 
        {
1451
 
                if(o->getClass() == cl)
1452
 
                {
1453
 
                        l.append(o);
1454
 
                } else o->killAllChildrenWithClass(cl);
1455
 
        }
1456
 
}
1457
 
bool KviKvsObject::inheritsClass(const QString &szClass)
1458
 
{
1459
 
        KviKvsObjectClass * pClass = KviKvsKernel::instance()->objectController()->lookupClass(szClass);
1460
 
        if (pClass) return inheritsClass(pClass);
1461
 
        else return false;
1462
 
}
1463
 
bool KviKvsObject::inheritsClass(KviKvsObjectClass * pClass)
1464
 
{
1465
 
        if(pClass == m_pClass)return true;
1466
 
        KviKvsObjectClass * cl = m_pClass->m_pParentClass;
1467
 
        while(cl)
1468
 
        {
1469
 
                if(cl == pClass)return true;
1470
 
                else cl = cl->m_pParentClass;
1471
 
        }
1472
 
        return false;
1473
 
}
1474
 
 
1475
 
KviKvsObjectClass * KviKvsObject::getClass(const QString & classOverride)
1476
 
{
1477
 
        if(classOverride.isEmpty())return m_pClass;
1478
 
        KviKvsObjectClass * cl = m_pClass; // class override can be also THIS class
1479
 
        // if object->$function() is a local override, class::object->$function()
1480
 
        // is the class member function (not the local override)
1481
 
        while(cl)
1482
 
        {
1483
 
                if(KviQString::equalCI(cl->name(),classOverride))break;
1484
 
                else cl = cl->m_pParentClass;
1485
 
        }
1486
 
        return cl;
1487
 
}
1488
 
 
1489
 
KviKvsObjectFunctionHandler * KviKvsObject::lookupFunctionHandler(const QString & funcName,const QString & classOverride)
1490
 
{
1491
 
        KviKvsObjectFunctionHandler * h = 0;
1492
 
 
1493
 
        if(classOverride.isEmpty() && m_pFunctionHandlers)
1494
 
        {
1495
 
                // lookup the local overrides
1496
 
                h = m_pFunctionHandlers->find(funcName);
1497
 
        }
1498
 
 
1499
 
        if(!h)
1500
 
        {
1501
 
                // not a local override function... lookup in the class
1502
 
                KviKvsObjectClass * cl = getClass(classOverride);
1503
 
                if(cl)return cl->lookupFunctionHandler(funcName);
1504
 
        }
1505
 
 
1506
 
        return h;
1507
 
}
1508
 
 
1509
 
 
1510
 
bool KviKvsObject::die()
1511
 
{
1512
 
        if(m_bInDelayedDeath)return false;
1513
 
        m_bInDelayedDeath = true;
1514
 
        QTimer::singleShot(0,this,SLOT(delayedDie()));
1515
 
        return true;
1516
 
}
1517
 
 
1518
 
bool KviKvsObject::dieNow()
1519
 
{
1520
 
        if(m_bInDelayedDeath)return false;
1521
 
        m_bInDelayedDeath = true;
1522
 
        delete this;
1523
 
        return true;
1524
 
}
1525
 
 
1526
 
void KviKvsObject::delayedDie()
1527
 
{
1528
 
        delete this; // byez!
1529
 
}
1530
 
 
1531
 
void KviKvsObject::setObject(QObject * o,bool bIsOwned)
1532
 
{
1533
 
        //__range_invalid(m_pObject);
1534
 
        m_bObjectOwner = bIsOwned;
1535
 
        m_pObject = o;
1536
 
        o->installEventFilter(this);
1537
 
        connect(m_pObject,SIGNAL(destroyed()),this,SLOT(objectDestroyed()));
1538
 
}
1539
 
 
1540
 
void KviKvsObject::objectDestroyed()
1541
 
{
1542
 
        m_pObject = 0;
1543
 
        die();
1544
 
}
1545
 
 
1546
 
bool KviKvsObject::eventFilter(QObject *,QEvent *)
1547
 
{
1548
 
        return false; // do not stop
1549
 
}
1550
 
 
1551
 
void KviKvsObject::timerEvent(QTimerEvent *e)
1552
 
{
1553
 
        KviKvsVariant * v = new KviKvsVariant();
1554
 
        v->setInteger(e->timerId());
1555
 
        KviKvsVariantList parms(v);
1556
 
 
1557
 
        callFunction(this,"timerEvent",&parms);
1558
 
}
1559
 
 
1560
 
bool KviKvsObject::callFunction(KviKvsObject * pCaller,const QString &fncName,KviKvsVariant * pRetVal,KviKvsVariantList * pParams)
1561
 
{
1562
 
        KviKvsVariant rv;
1563
 
        if(!pRetVal)pRetVal = &rv;
1564
 
        KviKvsRunTimeContext ctx(0,g_pApp->activeConsole(),KviKvsKernel::instance()->emptyParameterList(),pRetVal,0);
1565
 
        if(!pParams)pParams = KviKvsKernel::instance()->emptyParameterList();
1566
 
        return callFunction(pCaller,fncName,QString(),&ctx,pRetVal,pParams);
1567
 
}
1568
 
 
1569
 
bool KviKvsObject::callFunction(KviKvsObject * pCaller,const QString &fncName,KviKvsVariantList * pParams)
1570
 
{
1571
 
        KviKvsVariant fakeRetVal;
1572
 
        return callFunction(pCaller,fncName,&fakeRetVal,pParams);
1573
 
}
1574
 
 
1575
 
bool KviKvsObject::callFunction(
1576
 
        KviKvsObject * pCaller,
1577
 
        const QString & fncName,
1578
 
        const QString & classOverride,
1579
 
        KviKvsRunTimeContext * pContext,
1580
 
        KviKvsVariant * pRetVal,
1581
 
        KviKvsVariantList * pParams)
1582
 
{
1583
 
        KviKvsObjectFunctionHandler * h = lookupFunctionHandler(fncName,classOverride);
1584
 
 
1585
 
        if(!h)
1586
 
        {
1587
 
                if(classOverride.isEmpty())
1588
 
                        pContext->error(__tr2qs_ctx("Cannot find object function $%Q for object named '%Q' of class '%Q'","kvs"),&fncName,&m_szName,&(getClass()->name()));
1589
 
                else
1590
 
                        pContext->error(__tr2qs_ctx("Cannot find object function $%Q::%Q for object named '%Q' of class '%Q'","kvs"),&classOverride,&fncName,&m_szName,&(getClass()->name()));
1591
 
                return false;
1592
 
        }
1593
 
 
1594
 
        if(h->flags() & KviKvsObjectFunctionHandler::Internal)
1595
 
        {
1596
 
                if(pCaller != this)
1597
 
                {
1598
 
                        pContext->error(__tr2qs_ctx("Cannot call internal object function $%Q (for object named '%Q' of class '%Q') from this context","kvs"),&fncName,&m_szName,&(getClass()->name()));
1599
 
                        return false;
1600
 
                }
1601
 
        }
1602
 
 
1603
 
        KviKvsObjectFunctionCall fc(pContext,pParams,pRetVal);
1604
 
 
1605
 
        return h->call(this,&fc);
1606
 
 
1607
 
        // Not only gcc spits out compiler errors:
1608
 
        // 25.09.2001 , at this point in file
1609
 
 
1610
 
        // c:\programmi\microsoft visual studio\myprojects\kvirc3\src\kvirc\uparser\kvi_scriptobject.cpp(1234) : fatal error C1001: INTERNAL COMPILER ERROR
1611
 
        //    (compiler file 'E:\8168\vc98\p2\src\P2\main.c', line 494)
1612
 
        //    Please choose the Technical Support command on the Visual C++
1613
 
        //    Help menu, or open the Technical Support help file for more information
1614
 
}
1615
 
 
1616
 
void KviKvsObject::registerPrivateImplementation(const QString &szFunctionName,const QString &szCode)
1617
 
{
1618
 
        if(szCode.isEmpty())
1619
 
        {
1620
 
                if(m_pFunctionHandlers)
1621
 
                {
1622
 
                        m_pFunctionHandlers->remove(szFunctionName);
1623
 
                        if(m_pFunctionHandlers->isEmpty())
1624
 
                        {
1625
 
                                delete m_pFunctionHandlers;
1626
 
                                m_pFunctionHandlers = 0;
1627
 
                        }
1628
 
                }
1629
 
        } else {
1630
 
                if(!m_pFunctionHandlers)
1631
 
                {
1632
 
                        m_pFunctionHandlers = new KviPointerHashTable<QString,KviKvsObjectFunctionHandler>(7,false);
1633
 
                        m_pFunctionHandlers->setAutoDelete(true);
1634
 
                }
1635
 
 
1636
 
                QString szContext = m_pClass->name();
1637
 
                szContext += "[privateimpl]::";
1638
 
                szContext += szFunctionName;
1639
 
 
1640
 
                m_pFunctionHandlers->replace(szFunctionName,new KviKvsObjectScriptFunctionHandler(szContext,szCode));
1641
 
        }
1642
 
}
1643
 
 
1644
 
KviKvsObject * KviKvsObject::findChild(const QString &szClass,const QString &szName)
1645
 
{
1646
 
        for(KviKvsObject * o = m_pChildList->first();o;o= m_pChildList->next())
1647
 
        {
1648
 
                if(szClass.isEmpty())
1649
 
                {
1650
 
                        // any class matches
1651
 
                        if(szName.isEmpty())return o; // any name matches
1652
 
                        // name must match
1653
 
                        if(KviQString::equalCI(szName,o->objectName()))return o;
1654
 
                } else {
1655
 
                        if(KviQString::equalCI(szClass,o->getClass()->name()))
1656
 
                        {
1657
 
                                if(szName.isEmpty())return o; // any name matches
1658
 
                                // name must match
1659
 
                                if(KviQString::equalCI(szName,o->objectName()))return o;
1660
 
                        }
1661
 
                }
1662
 
                KviKvsObject * c = o->findChild(szClass,szName);
1663
 
                if(c)return c;
1664
 
        }
1665
 
        return 0;
1666
 
}