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

« back to all changes in this revision

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