1
//=============================================================================
3
// File : KviKvsObject.cpp
4
// Creation date : Wed 08 Oct 2003 02:31:57 by Szymon Stefanek
6
// This file is part of the KVIrc IRC client distribution
7
// Copyright (C) 2003-2010 Szymon Stefanek <pragma at kvirc dot net>
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.
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.
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.
23
//=============================================================================
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"
35
#include "KviControlCodes.h"
36
#include "KviIconManager.h"
37
#include "KviMemory.h"
38
#include "KviKvsObjectController.h"
39
#include "KviKvsObjectFunctionCall.h"
40
#include "KviKvsObjectFunctionHandlerImpl.h"
42
#include <QMetaObject>
43
#include <QMetaProperty>
55
Object scripting overview
57
objects, object scripting, complex data structures
59
[big]Introduction[/big]
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]
66
[big]Basic concepts[/big]
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]
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]
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]
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]
90
[big]Creation and destruction[/big]
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]
98
%myobject = [fnc]$new[/fnc]([class]object[/class],0,theName)
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]
106
[cmd]if[/cmd](%myobject)[cmd]echo[/cmd] "Object created!"
107
else [cmd]echo[/cmd] "Object creation failed!"
109
You can also test the object ID's for equality:[br]
111
[cmd]if[/cmd](%myobject == %anotherobject)[cmd]echo[/cmd] "This is the same object!";
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]
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]
119
[cmd]delete[/cmd] %myobject
121
If the destroyed object has children objects, these are destroyed too.[br][br]
123
[big]Fields: objects as pseudo-structures[/big]
125
All the objects can contain variable fields.
126
You can set an object's field by using the object scope operator "->":[br]
128
%myobject->%fieldVariable = dataString
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]
133
[cmd]echo[/cmd] %myobject->%fieldVariable
135
The '->' 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]
144
Any [doc:operators]operator[/doc] can be used with the object field variables:[br]
146
%myobject->%fieldVariable = 0
147
%myobject->%fieldVarialbe ++
148
[cmd]if[/cmd]0(%myobject->%fieldVariable != 1)[cmd]echo[/cmd] KVIrc is drunk, maybe a reboot will help?
150
You can simulate C structures "on the fly" by using objects and fields:[br]
152
# Create an user description on the fly
153
%myobj = [fnc]$new[/fnc]([class]object[/class],0,userDescription)
155
%myobj->%nickname = Pragma
156
%myobj->%username = daemon
157
%myobj->%hostname = pippo.pragma.org
158
%myobj->%info = Pragma goes always sleep too late
159
%myobj->%info [doc:operators]<<[/doc] and wakes up too late too!
160
# Call an (user defined) alias that stores the data to a file
163
[cmd]delete[/cmd] %myobj
165
The field variables can be also dictionaries:[br]
167
%theobj->%field[key] = something
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
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]
177
[cmd]class[/cmd](test,[class]object[/class])
181
%test = "will this persist?"
185
[cmd]echo[/cmd] "var: %test"
189
%myObject = [fnc]$new[/fnc](test,0)
190
%myObject->$test()
191
[comment]# Behold! This will only print "var: "![/comment]
192
%myObject->$anotherfunc()
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
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
205
Any object can have any field variable; an "unset" field is equivalent to an "empty" field.[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]
217
A more complex use of fields will be described later in this document.[br][br]
219
[big]Member functions[/big]
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]
225
%tmp = [fnc]$new[/fnc]([class]object[/class],0,myobject)
226
[cmd]echo[/cmd] The object's name is %tmp->[classfnc:object]$name[/classfnc](), the class name is %tmp->[classfnc:object]$className[/classfnc]()
228
[cmd]delete[/cmd] %tmp
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]
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->[classfnc:object]$children[/classfnc]()
239
# Destroy the object and the children
240
[cmd]delete[/cmd] %tmp
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]
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]
254
A more complex example[br]
256
%tmp = [fnc]$new[/fnc]([class]object[/class],0,myobject)
257
[cmd]foreach[/cmd](%i,1,2,3)
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]->[classfnc:object]$name[/classfnc]()) destroyed; }
262
[cmd]privateimpl[/cmd](%tmp,destructor)
265
[cmd]foreach[/cmd](%t,[fnc]$this[/fnc]->[classfnc:object]$children[/classfnc]())
267
[cmd]echo[/cmd] Children : %t->[classfnc:object]$name[/classfnc]() with class %t->[classfnc:object]$class[/classfnc]()
270
[cmd]echo[/cmd] Just before destroying my %count children.
272
# Destroy the object and the children
273
[cmd]delete[/cmd] %tmp
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]
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]
288
%anyobject->$functionname()
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]
304
function isLocalhost()
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,
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]
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]
328
find the nearest DNS server
330
wait for the response
333
function isLocalhost()
335
query the kernel for the local hostname
336
compare the obtained hostname with the hostname field
340
In the above example I have "implemented" the two functions in pseudo code.[br][br]
342
Let's go back to the real world.[br][br]
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]
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]
351
The [b]class definitions are GLOBAL to the entire application[/b]: all server windows share them.[br][br]
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]
357
[big]Inheritance[/big]
359
Someone asked for derived classes?[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]
365
[cmd]class[/cmd](helloworld,[class]object[/class])
369
[cmd]echo[/cmd] Hello world!
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:
380
%instance = [fnc]$new[/fnc](helloworld)
381
%instance->$sayhello()
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]
387
[cmd]class[/cmd](localizedhelloworld,helloworld)
389
[comment]# define the setlanguage function[/comment]
390
[comment]# note that <$0 = language> is just a programmer reminder[/comment]
391
setlanguage(<$0 = language>)
393
[cmd]if[/cmd](($0 == english) || ($0 == italian))
395
[fnc:$this]$$[/fnc]->%lang = $0
398
[cmd]echo[/cmd] I don't know that language ($0)
399
[cmd]echo[/cmd] defaulting to english
400
[fnc:$this]$$[/fnc]->%lang = english
407
[cmd]if[/cmd]([fnc:$this]$$[/fnc]->%lang == italian)[cmd]echo[/cmd] Ciao mondo!
408
else [fnc:$this]$$[/fnc]->$helloworld:sayhello()
412
Now you can call:[br]
414
%m = [fnc]$new[/fnc](localizedhelloworld)
415
%m->$setLanguage(italian)
417
%m->$setLanguage(english)
419
%m->$setLanguage(turkish)
421
[cmd]delete[/cmd] %myobj
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->$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]
436
[fnc]$this[/fnc]->$helloworld:sayhello()
437
[comment]# equivalent to $$->$helloworld:sayhello(),[/comment]
438
[comment]# to $this->$helloworld::sayhello(),[/comment]
439
[comment]# and to $$->$helloworld::sayhello()[/comment]
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]->%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]
452
Note: multiple inheritance (inheritance from more than one base class) is not implemented, KVIrc is not a compiler. :)[br][br]
454
Objects are much more powerful...[br][br]
456
Do a [cmd]clearobjects[/cmd] to cleanup the old class definitions and read on.[br][br]
458
[big]Constructors and destructors[/big]
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]
465
[cmd]class[/cmd](myObject,[class]object[/class])
469
[fnc]$this[/fnc]->%test = "This is a sample object field."
473
%myObject = [fnc]$new[/fnc](myObject,[class]object[/class])
474
[cmd]echo[/cmd] %myObject->%test
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
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]
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
497
[cmd]class[/cmd](baseObject,[class]object[/class])
501
[cmd]echo[/cmd] "baseObject or derived object created."
505
[cmd]class[/cmd](derivedObject,baseObject)
509
[cmd]echo[/cmd] "derivedObject object created."
510
[fnc]$this[/fnc]->$baseObject::constructor()
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]
517
This is different from C (for example), where the constructors are called (more or less)
518
automatically.[br][br]
520
[big]Signals and slots[/big]
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]
544
///////////////////////////////////////////////////////////////////////////////////////
549
object class, object, class
555
Base class for all the KVIrc objects
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.
567
Constructor for this object class.
568
The default implementation does nothing.
570
Destructor for this object class.
571
The default implementation emits the signal "[classsignal]destroyed[/classsignal]".
573
Returns the name of this object.
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>.
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.
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.
602
Returns an array of child object identifiers.
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.
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]
630
%X=$new(lineedit, 0, a_name)[br]
632
%X->$setProperty(echoMode,Password)[br]
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.
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
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;
657
KviKvsObject::KviKvsObject(KviKvsObjectClass * pClass,KviKvsObject * pParent,const QString &szName)
660
setObjectName(szName);
662
if(g_hNextObjectHandle == 0)g_hNextObjectHandle++; // make sure it's never 0
663
m_hObject = (kvs_hobject_t)g_hNextObjectHandle;
664
g_hNextObjectHandle++;
667
m_bObjectOwner = true; // true by default
673
m_pChildList = new KviPointerList<KviKvsObject>;
674
m_pChildList->setAutoDelete(false);
676
m_pDataContainer = new KviKvsHash();
678
m_pFunctionHandlers = 0; // no local function handlers yet!
680
m_bInDelayedDeath = false;
681
m_bDestructorCalled = false;
682
m_bAboutToDie = false;
684
m_pSignalDict = 0; // no signals connected to remote slots
685
m_pConnectionList = 0; // no local slots connected to remote signals
688
pParent->registerChild(this);
690
KviKvsKernel::instance()->objectController()->registerObject(this);
692
// qDebug("Hello world!");
693
// [root@localhost cvs3]# kvirc
695
// [root@localhost cvs3]# date
696
// Tue Sep 5 21:53:54 CEST 2000
697
// [root@localhost cvs3]#
699
// Ported to KVS on 29.04.2005
702
KviKvsObject::~KviKvsObject()
704
//KVI_TRACE_FUNCTION;
705
//KVI_TRACE("Destroying kvs object %x, child of %x",this,parentObject());
707
if(!m_bDestructorCalled)
709
// Destructor not called yet.. something is wrong.
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.
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");
721
// If we pass the assert in some kind of build go ahead nicely
722
m_bAboutToDie = true; // don't attempt to die twice
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.
728
// Well... need to call the destructor.
731
// Destructor already called.
732
m_bAboutToDie = true; // don't attempt to die twice
735
// Kill any child not deleted by the user
736
while(m_pChildList->first())
737
m_pChildList->first()->dieNow();
739
// Ok, from this point we shouldn't be touched by any one via KVS
740
// so we can start really deleting stuff...
743
// Disconnect all the signals
748
KviPointerHashTableEntry<QString,KviKvsObjectConnectionList> * pSignalList = m_pSignalDict->firstEntry();
751
KviKvsObjectConnection * pConnection = pSignalList->data()->first();
754
disconnectSignal(pSignalList->key(),pConnection);
757
// Disconnect all the slots
760
if(!m_pConnectionList)
762
KviKvsObjectConnection * pConnection = m_pConnectionList->first();
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);
771
// Detach from the kvs kernel
772
KviKvsKernel::instance()->objectController()->unregisterObject(this);
774
// Detach from the parent object
776
parentObject()->unregisterChild(this);
778
// If we wrap a Qt object then detach and eventually delete
782
disconnect(m_pObject,SIGNAL(destroyed()),this,SLOT(objectDestroyed()));
783
// delete if we own it
788
// Kill member variables
789
delete m_pDataContainer;
790
// Kill function container
791
if(m_pFunctionHandlers)
792
delete m_pFunctionHandlers;
797
void KviKvsObject::callDestructor()
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
802
m_bDestructorCalled = true;
804
// Note that children are still alive: the user can clean them up manually
805
callFunction(this,"destructor");
808
bool KviKvsObject::init(KviKvsRunTimeContext *,KviKvsVariantList *)
813
QWidget * KviKvsObject::parentScriptWidget()
817
if(parentObject()->object())
819
if(parentObject()->object()->isWidgetType())
820
return (QWidget *)(parentObject()->object());
826
void KviKvsObject::unregisterChild(KviKvsObject *pChild)
828
m_pChildList->removeRef(pChild);
831
void KviKvsObject::registerChild(KviKvsObject *pChild)
833
m_pChildList->append(pChild);
838
bool KviKvsObject::connectSignal(const QString &sigName,KviKvsObject * pTarget,const QString &slotName)
840
if(!pTarget->lookupFunctionHandler(slotName))return false; // no such slot
844
m_pSignalDict = new KviPointerHashTable<QString,KviKvsObjectConnectionList>(7,false);
845
m_pSignalDict->setAutoDelete(true);
848
KviKvsObjectConnectionList * l = m_pSignalDict->find(sigName);
851
l = new KviKvsObjectConnectionList;
852
l->setAutoDelete(true);
853
m_pSignalDict->insert(sigName,l);
856
KviKvsObjectConnection * con = new KviKvsObjectConnection;
858
con->pSourceObject = this;
859
con->pTargetObject = pTarget;
860
con->szSignal = sigName;
861
con->szSlot = slotName;
864
pTarget->registerConnection(con);
868
void KviKvsObject::registerConnection(KviKvsObjectConnection *pConnection)
870
if(!m_pConnectionList)
872
m_pConnectionList = new KviKvsObjectConnectionList;
873
m_pConnectionList->setAutoDelete(false);
875
m_pConnectionList->append(pConnection);
878
bool KviKvsObject::disconnectSignal(const QString &sigName,KviKvsObject * pTarget,const QString &slotName)
880
if(!m_pSignalDict)return false; //no such signal to disconnect
882
KviKvsObjectConnectionList * l = m_pSignalDict->find(sigName);
885
KviKvsObjectConnectionListIterator it(*l);
887
while(KviKvsObjectConnection * sl = it.current())
889
if(sl->pTargetObject == pTarget)
891
if(KviQString::equalCI(sl->szSlot,slotName))
893
pTarget->unregisterConnection(sl);
895
if(l->isEmpty())m_pSignalDict->remove(sigName);
896
if(m_pSignalDict->isEmpty())
898
delete m_pSignalDict;
909
bool KviKvsObject::disconnectSignal(const QString &sigName,KviKvsObjectConnection * pConnection)
911
if(!m_pSignalDict)return false;
912
KviKvsObjectConnectionList * l = m_pSignalDict->find(sigName);
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())
921
delete m_pSignalDict;
927
bool KviKvsObject::unregisterConnection(KviKvsObjectConnection * pConnection)
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())
934
delete m_pConnectionList;
935
m_pConnectionList = 0;
940
int KviKvsObject::emitSignal(const QString &sigName,KviKvsObjectFunctionCall * pOuterCall,KviKvsVariantList * pParams)
942
if(!m_pSignalDict)return 0;
944
KviKvsObjectConnectionList * l = m_pSignalDict->find(sigName);
945
if(!l)return 0; // no slots registered
947
KviKvsVariant retVal;
949
// The objects we're going to disconnect
950
KviPointerList<KviKvsObjectConnection> * pDis = 0;
952
kvs_int_t emitted = 0;
954
KviKvsObjectConnectionListIterator it(*l);
956
while(KviKvsObjectConnection * s = it.current())
958
// save it, since s may be destroyed in the call!
959
KviKvsObject * pTarget = s->pTargetObject;
963
kvs_hobject_t hTarget = pTarget->handle();
964
kvs_hobject_t hOld = pTarget->signalSender();
966
pTarget->setSignalSender(m_hObject);
967
pTarget->setSignalName(sigName);
969
if(!pTarget->callFunction(this,s->szSlot,QString(),pOuterCall->context(),&retVal,pParams))
971
if(KviKvsKernel::instance()->objectController()->lookupObject(hTarget) && it.current())
974
__tr2qs_ctx("Broken slot '%Q' in target object '%Q::%Q' while emitting signal '%Q' from object '%Q::%Q': disconnecting","kvs"),
976
&(s->pTargetObject->getClass()->name()),
977
&(s->pTargetObject->getName()),
979
&(getClass()->name()),
984
pDis = new KviPointerList<KviKvsObjectConnection>;
985
pDis->setAutoDelete(false);
989
// else destroyed in the call! (already disconnected)
992
__tr2qs_ctx("Slot target object destroyed while emitting signal '%Q' from object '%Q::%Q'","kvs"),
994
&(getClass()->name()),
999
if(KviKvsKernel::instance()->objectController()->lookupObject(hTarget))
1001
pTarget->setSignalSender(hOld);
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);
1018
bool KviKvsObject::function_name(KviKvsObjectFunctionCall * c)
1020
c->returnValue()->setString(getName());
1024
bool KviKvsObject::function_parent(KviKvsObjectFunctionCall * c)
1026
KviKvsObject * o = parentObject();
1027
c->returnValue()->setHObject(o ? o->handle() : (kvs_hobject_t)0);
1031
bool KviKvsObject::function_className(KviKvsObjectFunctionCall * c)
1033
c->returnValue()->setString(getClass()->name());
1037
bool KviKvsObject::function_childCount(KviKvsObjectFunctionCall * c)
1039
c->returnValue()->setInteger((kvs_int_t)(m_pChildList->count()));
1043
bool KviKvsObject::function_signalSender(KviKvsObjectFunctionCall * c)
1045
c->returnValue()->setHObject(m_hSignalSender);
1049
bool KviKvsObject::function_signalName(KviKvsObjectFunctionCall * c)
1051
c->returnValue()->setString(m_szSignalName);
1055
bool KviKvsObject::function_destructor(KviKvsObjectFunctionCall * c)
1057
emitSignal("destroyed",c);
1061
bool KviKvsObject::function_children(KviKvsObjectFunctionCall * c)
1063
KviKvsArray * a = new KviKvsArray();
1065
for(KviKvsObject * o = m_pChildList->first();o;o = m_pChildList->next())
1067
a->set(id,new KviKvsVariant(o->handle()));
1070
c->returnValue()->setArray(a);
1074
bool KviKvsObject::function_findChild(KviKvsObjectFunctionCall * c)
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)
1082
KviKvsObject * o = findChild(szClass,szName);
1083
c->returnValue()->setHObject(o ? o->handle() : (kvs_hobject_t)0);
1088
bool KviKvsObject::function_emit(KviKvsObjectFunctionCall * c)
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)
1097
emitSignal(szSignal,c,&vList);
1101
bool KviKvsObject::function_startTimer(KviKvsObjectFunctionCall * c)
1104
KVSO_PARAMETERS_BEGIN(c)
1105
KVSO_PARAMETER("timeout",KVS_PT_UINT,0,timeout)
1106
KVSO_PARAMETERS_END(c)
1108
c->returnValue()->setInteger((kvs_int_t)(startTimer(timeout)));
1112
bool KviKvsObject::function_killTimer(KviKvsObjectFunctionCall * c)
1115
KVSO_PARAMETERS_BEGIN(c)
1116
KVSO_PARAMETER("timerId",KVS_PT_INT,0,id)
1117
KVSO_PARAMETERS_END(c)
1122
bool KviKvsObject::function_listProperties(KviKvsObjectFunctionCall * c)
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)
1129
c->returnValue()->setNothing();
1131
KviKvsArray * a = bArray ? new KviKvsArray() : 0;
1133
KviWindow * w = c->context()->window();
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()));
1140
const QMetaObject *o = m_pObject->metaObject();
1142
w->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs_ctx("Properties for Qt class %s","kvs"),o->className());
1144
QMetaProperty prop = o->property(idx);
1145
const QMetaProperty *p = ∝
1149
QString szName = p->name();
1150
QString szType = p->typeName();
1152
szOut = QString("%1, %2").arg(szName,szType);
1154
szOut = QString(__tr2qs_ctx("Property: %1%2%3, type %4","kvs")).arg(KviControlCodes::Bold).arg(szName).arg(KviControlCodes::Bold).arg(szType);
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";
1169
a->set(cnt,new KviKvsVariant(szOut));
1171
w->outputNoFmt(KVI_OUT_SYSTEMMESSAGE,szOut);
1173
if (idx<o->propertyCount()){
1174
prop = o->property(idx);
1184
c->returnValue()->setArray(a);
1186
w->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs_ctx("%d properties listed","kvs"),cnt);
1190
bool KviKvsObject::function_setProperty(KviKvsObjectFunctionCall * c)
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)
1199
c->returnValue()->setNothing();
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()));
1208
int idx = m_pObject->metaObject()->indexOfProperty(szName.toUtf8().data());
1211
c->warning(__tr2qs_ctx("No Qt property named '%Q' for object named '%Q' of class '%Q'","kvs"),&szName,&m_szName,&(m_pClass->name()));
1214
QMetaProperty prop = m_pObject->metaObject()->property(idx);
1215
const QMetaProperty * p = ∝
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()));
1222
QVariant vv = m_pObject->property(szName.toUtf8().data());
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()));
1233
int val = p->enumerator().keyToValue(szKey.toUtf8().data());
1235
m_pObject->setProperty(szName.toUtf8().data(),var);
1239
#define WRONG_TYPE(__therighttype) \
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); \
1250
if(!v->asInteger(i))WRONG_TYPE("integer")
1251
m_pObject->setProperty(szName.toUtf8().data(),QVariant((int)i));
1254
case QVariant::UInt:
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));
1261
case QVariant::Double:
1264
if(!v->asReal(i))WRONG_TYPE("real")
1265
m_pObject->setProperty(szName.toUtf8().data(),QVariant((double)i));
1268
case QVariant::Bool:
1269
m_pObject->setProperty(szName.toUtf8().data(),QVariant(v->asBoolean()));
1271
case QVariant::String:
1275
m_pObject->setProperty(szName.toUtf8().data(),QVariant(s));
1278
case QVariant::ByteArray:
1282
m_pObject->setProperty(szName.toUtf8().data(),QVariant(s.toUtf8()));
1285
case QVariant::Point:
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)")
1293
if(!x->asInteger(iX) || !y->asInteger(iY))WRONG_TYPE("array(integer,integer)")
1294
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QPoint(iX,iY)));
1297
case QVariant::Size:
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)")
1305
if(!w->asInteger(iW) || !h->asInteger(iH))WRONG_TYPE("array(integer,integer)")
1306
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QSize(iW,iH)));
1309
case QVariant::Rect:
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)));
1324
case QVariant::Color:
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)")
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)));
1337
case QVariant::Font:
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)")
1346
if(!ps->asInteger(iPs))WRONG_TYPE("array(string,integer,string)")
1349
if(fl)fl->asString(szFl);
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));
1362
case QVariant::Pixmap|QVariant::Icon:
1366
if(v->hobject() == (kvs_hobject_t)0)
1369
if(vv.type() == QVariant::Pixmap)
1370
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QPixmap()));
1372
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QIcon()));
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"));
1378
QVariant pixv = pix->property("pixmap");
1379
if(vv.type() == QVariant::Pixmap)
1380
m_pObject->setProperty(szName.toUtf8().data(),QVariant(pixv.value<QPixmap>()));
1382
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QIcon(pixv.value<QPixmap>())));
1388
QPixmap * pPix = g_pIconManager->getImage(szStr);
1391
if(vv.type() == QVariant::Pixmap)
1392
m_pObject->setProperty(szName.toUtf8().data(),QVariant(*pPix));
1394
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QIcon(*pPix)));
1397
c->warning(__tr2qs_ctx("Can't find the requested image","kvs"));
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();
1411
bool KviKvsObject::function_property(KviKvsObjectFunctionCall * c)
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)
1422
// there are no Qt properties at all
1423
if (bNoerror) c->returnValue()->setString("No Qt properties");
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();
1432
int idx = m_pObject->metaObject()->indexOfProperty(szName.toUtf8().data());
1436
c->returnValue()->setString("No Qt properties");
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();
1444
QMetaProperty prop = m_pObject->metaObject()->property(idx);
1445
const QMetaProperty * p = ∝
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();
1453
QVariant v = m_pObject->property(szName.toUtf8().data());
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();
1463
c->returnValue()->setString(p->enumerator().valueToKey(v.toInt()));
1470
c->returnValue()->setInteger((kvs_int_t)v.toInt());
1472
case QVariant::Double:
1473
c->returnValue()->setReal((kvs_int_t)v.toDouble());
1475
case QVariant::UInt:
1476
c->returnValue()->setInteger((kvs_int_t)v.toUInt());
1478
case QVariant::Bool:
1479
c->returnValue()->setBoolean(v.toBool());
1481
case QVariant::String:
1482
c->returnValue()->setString(v.toString());
1484
case QVariant::ByteArray:
1485
c->returnValue()->setString(QString::fromUtf8(v.toByteArray().data()));
1487
case QVariant::Point:
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);
1496
case QVariant::Size:
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);
1505
case QVariant::Rect:
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);
1516
case QVariant::Color:
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);
1526
case QVariant::Font:
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()));
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);
1544
if (bNoerror) c->returnValue()->setString("Unsupported_data_type");
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();
1555
void KviKvsObject::killAllChildrenWithClass(KviKvsObjectClass *cl)
1557
KviPointerList< QPointer<KviKvsObject> > lDying;
1558
lDying.setAutoDelete(true);
1560
KviKvsObject * pObject;
1562
QPointer<KviKvsObject> guard(this);
1564
for(pObject = m_pChildList->first();pObject;pObject = m_pChildList->next())
1566
if(pObject->getClass() == cl)
1568
lDying.append(new QPointer<KviKvsObject>(pObject));
1570
pObject->killAllChildrenWithClass(cl);
1572
break; // argh.. circular delete
1576
for(QPointer<KviKvsObject> * pObject = lDying.first();pObject;pObject = lDying.next())
1578
if(pObject->isNull())
1579
continue; // already dead ?
1580
(*pObject)->dieNow();
1584
bool KviKvsObject::inheritsClass(const QString &szClass)
1586
KviKvsObjectClass * pClass = KviKvsKernel::instance()->objectController()->lookupClass(szClass);
1587
if (pClass) return inheritsClass(pClass);
1590
bool KviKvsObject::inheritsClass(KviKvsObjectClass * pClass)
1592
if(pClass == m_pClass)return true;
1593
KviKvsObjectClass * cl = m_pClass->m_pParentClass;
1596
if(cl == pClass)return true;
1597
else cl = cl->m_pParentClass;
1602
KviKvsObjectClass * KviKvsObject::getClass(const QString & classOverride)
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)
1610
if(KviQString::equalCI(cl->name(),classOverride))break;
1611
else cl = cl->m_pParentClass;
1616
KviKvsObjectFunctionHandler * KviKvsObject::lookupFunctionHandler(const QString & funcName,const QString & classOverride)
1618
KviKvsObjectFunctionHandler * h = 0;
1620
if(classOverride.isEmpty() && m_pFunctionHandlers)
1622
// lookup the local overrides
1623
h = m_pFunctionHandlers->find(funcName);
1628
// not a local override function... lookup in the class
1629
KviKvsObjectClass * cl = getClass(classOverride);
1630
if(cl)return cl->lookupFunctionHandler(funcName);
1637
bool KviKvsObject::die()
1640
return false; // hum.. recursive death attempt :D
1642
if(m_bInDelayedDeath)
1643
return false; // we're alreadyi dying soon, dude, no need to repeat it over and over again...
1645
m_bInDelayedDeath = true;
1647
QTimer::singleShot(0,this,SLOT(delayedDie()));
1651
bool KviKvsObject::dieNow()
1654
return false; // hum.. recursive death attempt :D
1656
m_bAboutToDie = true;
1658
KVI_ASSERT(!m_bDestructorCalled);
1665
void KviKvsObject::delayedDie()
1667
KVI_ASSERT(m_bInDelayedDeath); // must be true: never call it directly
1668
KVI_ASSERT(!m_bAboutToDie); // if this is true something is wrong...
1670
m_bAboutToDie = true;
1672
KVI_ASSERT(!m_bDestructorCalled);
1674
delete this; // byez!
1677
void KviKvsObject::setObject(QObject * o,bool bIsOwned)
1679
//__range_invalid(m_pObject);
1680
m_bObjectOwner = bIsOwned;
1682
o->installEventFilter(this);
1683
connect(m_pObject,SIGNAL(destroyed()),this,SLOT(objectDestroyed()));
1686
void KviKvsObject::objectDestroyed()
1692
bool KviKvsObject::eventFilter(QObject *,QEvent *)
1694
return false; // do not stop
1697
void KviKvsObject::timerEvent(QTimerEvent *e)
1699
KviKvsVariant * v = new KviKvsVariant();
1700
v->setInteger(e->timerId());
1701
KviKvsVariantList parms(v);
1703
callFunction(this,"timerEvent",&parms);
1706
bool KviKvsObject::callFunction(KviKvsObject * pCaller,const QString &fncName,KviKvsVariant * pRetVal,KviKvsVariantList * pParams)
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);
1715
bool KviKvsObject::callFunction(KviKvsObject * pCaller,const QString &fncName,KviKvsVariantList * pParams)
1717
KviKvsVariant fakeRetVal;
1718
return callFunction(pCaller,fncName,&fakeRetVal,pParams);
1721
bool KviKvsObject::callFunction(
1722
KviKvsObject * pCaller,
1723
const QString & fncName,
1724
const QString & classOverride,
1725
KviKvsRunTimeContext * pContext,
1726
KviKvsVariant * pRetVal,
1727
KviKvsVariantList * pParams)
1729
KviKvsObjectFunctionHandler * h = lookupFunctionHandler(fncName,classOverride);
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()));
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()));
1740
if(h->flags() & KviKvsObjectFunctionHandler::Internal)
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()));
1749
KviKvsObjectFunctionCall fc(pContext,pParams,pRetVal);
1751
return h->call(this,&fc);
1753
// Not only gcc spits out compiler errors:
1754
// 25.09.2001, at this point in file
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
1762
void KviKvsObject::registerPrivateImplementation(const QString &szFunctionName,const QString &szCode)
1764
if(szCode.isEmpty())
1766
if(m_pFunctionHandlers)
1768
m_pFunctionHandlers->remove(szFunctionName);
1769
if(m_pFunctionHandlers->isEmpty())
1771
delete m_pFunctionHandlers;
1772
m_pFunctionHandlers = 0;
1776
if(!m_pFunctionHandlers)
1778
m_pFunctionHandlers = new KviPointerHashTable<QString,KviKvsObjectFunctionHandler>(7,false);
1779
m_pFunctionHandlers->setAutoDelete(true);
1782
QString szContext = m_pClass->name();
1783
szContext += "[privateimpl]::";
1784
szContext += szFunctionName;
1786
m_pFunctionHandlers->replace(szFunctionName,new KviKvsObjectScriptFunctionHandler(szContext,szCode,QString("")));
1790
KviKvsObject * KviKvsObject::findChild(const QString &szClass,const QString &szName)
1792
for(KviKvsObject * o = m_pChildList->first();o;o= m_pChildList->next())
1794
if(szClass.isEmpty())
1796
// any class matches
1797
if(szName.isEmpty())return o; // any name matches
1799
if(KviQString::equalCI(szName,o->objectName()))return o;
1801
if(KviQString::equalCI(szClass,o->getClass()->name()))
1803
if(szName.isEmpty())return o; // any name matches
1805
if(KviQString::equalCI(szName,o->objectName()))return o;
1808
KviKvsObject * c = o->findChild(szClass,szName);