1
//=============================================================================
3
// File : kvi_kvs_object.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-2008 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
//=============================================================================
25
#include "kvi_kvs_object.h"
26
#include "kvi_kvs_hash.h"
27
#include "kvi_kvs_kernel.h"
28
#include "kvi_window.h"
31
#include "kvi_modulemanager.h"
32
#include "kvi_console.h"
33
#include "kvi_locale.h"
34
#include "kvi_error.h"
36
#include "kvi_mirccntrl.h"
37
#include "kvi_iconmanager.h"
38
#include "kvi_malloc.h"
40
#include "kvi_kvs_object_controller.h"
41
#include "kvi_kvs_object_functioncall.h"
42
#include "kvi_kvs_object_functionhandlerimpl.h"
44
#include <QMetaObject>
45
#include <QMetaProperty>
56
Object scripting overview
58
objects , object scripting , complex data structures
60
[big]Introduction[/big]
62
The KVIrc scripting language is not object oriented in nature.
63
Anyway , objects are a highlevel abstraction that allow
64
to write complex code in a "clean" way.
65
So I've added at least some pseudo-object support.[br][br]
67
[big]Basic concepts[/big]
69
Objects are arranged in tree structures.
70
Each object that you create is either toplevel object or a children
71
of another object. A toplevel object is a parentless one.
72
Obviously all objects can have children objects.[br][br]
74
When an object is destroyed , all its children are also destroyed.
75
The toplevel objects are automatically destroyed when KVIrc quits.
76
The objects are global to the entire application (this is different
77
from previous KVIrc releases where the objects were local
78
to the current frame window and arranged in a single tree
79
with a builtin root object).[br][br]
81
Each object is an instance of a class that defines its features.
82
Each object has also a name , that is not necessary unique and is assigned
83
by the programmer; the name is just a mnemonic expedient, and
84
you may also not need it.[br][br]
86
Each object is identified by an [b]OPAQUE UNIQUE ID[/b].
87
The ID is assigned by KVIrc and can be held in any variable.
88
You can think the object id as a "handle for the object" or the object's pointer.
89
Any action performed on the object will require its ID.[br][br]
91
[big]Creation and destruction[/big]
93
To create an object you must use the [fnc]$new[/fnc]()
94
function. [fnc]$new[/fnc]() requires three parameters:[br]
95
- The object class (more about object classes later in this document)[br]
96
- The ID of the parent object , (that can be 0 for toplevel objects).[br]
97
- The object name (eventually empty)[br]
99
%myobject = [fnc]$new[/fnc]([class]object[/class],0,theName)
101
[fnc]$new[/fnc]() returns the ID of the newly created object, or
102
the STRING "0" if the object creation fails
103
(it is a string because the object id's are generally strings, and 0 is an "invalid object id").
104
In well written scripts it is not common that the object creation fails, anyway
105
you can check if the creation has failed in the following way:[br]
107
[cmd]if[/cmd](%myobject)[cmd]echo[/cmd] "Object created!"
108
else [cmd]echo[/cmd] "Object creation failed!"
110
You can also test the object ID's for equality:[br]
112
[cmd]if[/cmd](%myobject == %anotherobject)[cmd]echo[/cmd] "This is the same object!";
114
The parent object id is optional, if not specified it is assumed to be 0.
115
The object name is optional , but it may help you later in finding the object.[br][br]
117
To destroy an object use the [cmd]delete[/cmd] command. (In previous versions
118
this command was named "destroy" and delete is currently aliased to that name too).[br]
120
[cmd]delete[/cmd] %myobject
122
If the destroyed object has children objects , these are destroyed too.[br][br]
124
[big]Fields : objects as pseudo-structures[/big]
126
All the objects can contain variable fields.
127
You can set an object's field by using the object scope operator "->":[br]
129
%myobject->%fieldVariable = dataString
131
To unset a field set it with empty data string (just like with a normal variable).
132
To retrieve the field data use the object scope operator in the same way:[br]
134
[cmd]echo[/cmd] %myobject->%fieldVariable
136
The '->' operator has been stolen from the C language.
137
In the KVIrc scripting language it switches from the global namespace
138
to the object's one.[br]
139
So in the above example %fieldVariable is owned by the object.[br]
140
The first character of the variable name has no special meaning in the
141
object namespace (in the global namespace the variables starting
142
with an uppercase letter are global to the application , the other ones are local
143
to the command sequence). The variable names are completely case insensitive.[br][br]
145
Any [doc:operators]operator[/doc] can be used with the object field variables:[br]
147
%myobject->%fieldVariable = 0
148
%myobject->%fieldVarialbe ++
149
[cmd]if[/cmd]0(%myobject->%fieldVariable != 1)[cmd]echo[/cmd] KVIrc is drunk , maybe a reboot will help ?
151
You can simulate C structures "on the fly" by using objects and fields:[br]
153
# Create an user description on the fly
154
%myobj = [fnc]$new[/fnc]([class]object[/class],0,userDescription)
156
%myobj->%nickname = Pragma
157
%myobj->%username = daemon
158
%myobj->%hostname = pippo.pragma.org
159
%myobj->%info = Pragma goes always sleep too late
160
%myobj->%info [doc:operators]<<[/doc] and wakes up too late too!
161
# Call an (user defined) alias that stores the data to a file
164
[cmd]delete[/cmd] %myobj
166
The field variables can be also dictionaries:[br]
168
%theobj->%field[key] = something
170
Unlike in C , there is no need to declare object fields.
171
Any object can have any field variable ; an "unset" field is equivalent to an "empty" field.[br]
173
The KVIrc scripting language is not typed.
174
Any object class (be patient...I'll explain classes in a while) identifier can be stored in any KVIrc variable:
175
it is not possible to find out the object features by "examining" its identifier.
176
This may make the usage of objects a bit "unclear";
177
Howewer , with some experience you will be able to use the objects in a very powerful way.
178
The type-safety can be also simulated by a careful usage of object names;
179
in the above example , the %myobj object was created with the "userDescription" name.
180
The storetofile alias could check the passed object's name and refuse to work
181
if that does not match "userDescription".[br][br]
183
A more complex use of fields will be described later in this document.[br][br]
185
[big]Member functions[/big]
187
Just like in C++ , the objects have member functions.
188
For example , the "object" class (again...read on) objects export the [classfnc:object]$name[/classfnc]()
189
and [classfnc:object]$className[/classfnc]() functions.[br]
191
%tmp = [fnc]$new[/fnc]([class]object[/class],0,myobject)
192
[cmd]echo[/cmd] The object's name is %tmp->[classfnc:object]$name[/classfnc]() , the class name is %tmp->[classfnc:object]$className[/classfnc]()
194
[cmd]delete[/cmd] %tmp
196
Another cool function exported by the [class:object]object[/class] class is the
197
[classfnc:object]$children[/classfnc]() function.
198
It returns a comma separated list of children identifiers.[br]
200
%tmp = [fnc]$new[/fnc]([class]object[/class],0,myobject)
201
%tmpchild = [fnc]$new[/fnc]([class]object[/class],%tmp,child1)
202
%tmpchild = [fnc]$new[/fnc]([class]object[/class],%tmp,child2)
203
%tmpchild = [fnc]$new[/fnc]([class]object[/class],%tmp,child3)
204
[cmd]echo[/cmd] The object's children list is : %tmp->[classfnc:object]$children[/classfnc]()
205
# Destroy the object and the children
206
[cmd]delete[/cmd] %tmp
208
There are two special functions for each objects: the "constructor" and the "destructor".
209
You will find more information on constructors and destructors later in this document,
210
for now it's enough that you know that these functions are called automatically by KVirc:
211
the constructor is called when the object is created and the destructor is called when the
212
object is being destroyed with [cmd]delete[/cmd].[br][br]
214
The object functions can be reimplemented on-the-fly
215
by using the [cmd]privateimpl[/cmd] command: you can simply modify the behaviour of the function
216
by writing your own function body.
217
(This is an uncommon feature: unlike many other languages , you can reimplement object
218
functions at run-time, when the object has been already created.)[br][br]
220
A more complex example[br]
222
%tmp = [fnc]$new[/fnc]([class]object[/class],0,myobject)
223
[cmd]foreach[/cmd](%i,1,2,3)
225
%tmpchild = [fnc]$new[/fnc]([class]object[/class],%tmp,child%i)
226
[cmd]privateimpl[/cmd](%tmpchild,destructor){ [cmd]echo[/cmd] Object [fnc]$this[/fnc] ([fnc]$this[/fnc]->[classfnc:object]$name[/classfnc]()) destroyed; }
228
[cmd]privateimpl[/cmd](%tmp,destructor)
231
[cmd]foreach[/cmd](%t,[fnc]$this[/fnc]->[classfnc:object]$children[/classfnc]())
233
[cmd]echo[/cmd] Children : %t->[classfnc:object]$name[/classfnc]() with class %t->[classfnc:object]$class[/classfnc]()
236
[cmd]echo[/cmd] Just before destroying my %count children.
238
# Destroy the object and the children
239
[cmd]delete[/cmd] %tmp
242
In the example above four objects have been created.
243
A "parent" object named "myobject" , and three children objects.
244
The destructor has been reimplemented for each child object,
245
to make it "say" its name (Please note the usage of [fnc]$this[/fnc]).
246
In the parent destructor the children have been counted and listed.[br]
247
Then the parent object is destroyed causing to:[br]
248
- trigger the parent destructor.[br]
249
- destroy all the children (and conseguently trigger all the "individual" destructors).[br][br]
251
Not all the object functions must return a value:
252
If a function does not return a meaningful value , or you just want to ignore it , you can call it in the following way:[br]
254
%anyobject->$functionname()
259
As said before , all objects are instances of a specific class.
260
This concept is common to almost all object oriented languages.
261
A class is a collection of methods that define an object's behaviour.
262
Hehe...it is not easy to explain it , so I'll try with an example:[br]
268
function isLocalhost()
271
The above class is a rappresentation of a host address.
272
You create an [b]instance of this class[/b] and set the hostname field, for example,
274
The object is now able to give you information about the hostname in a transparent way:
275
You can call the ipnumber() function, and the object will return you the
276
digits and dots rappresentation of www.kernel.org.
277
The isLocalhost() function will return true if the hostname refers to the local machine
278
The object internal job is hidden from the user , but probably it will be a huge job.
279
To obtain the IP number from the hostname , the object will probably have to perform a DNS call (usually a complex task).
280
To check if the hostname references the local machine , the object will have to obtain the local hostname
281
from the system (in some "unspecified" way) and then compare it with the given "hostname" field.[br][br]
283
The internal job of the object is defined by the "implementation of the class".
284
Obviously , the programmer that creates the class has to write that implementation.[br]
292
find the nearest DNS server
294
wait for the response
297
function isLocalhost()
299
query the kernel for the local hostname
300
compare the obtained hostname with the hostname field
304
In the above example I have "implemented" the two functions by using a "fantastic" language.[br][br]
306
Let's go back to the real world.[br][br]
308
KVirc contains a [doc:classes]set of built-in ready-to-use classes[/doc].
309
The basic class is [class]object[/class]: all the other classes are derived from this (more about
310
object inheritance later in this doc).[br][br]
312
Another available class is [class]socket[/class] that is an interface to the real system sockets.
313
An instance of the [class]socket[/class] class can connect and communicate with other hosts on the net.[br][br]
315
The [b]class definitions are GLOBAL to the entire application[/b]: all server windows share them.[br][br]
317
So now we can say that in KVIrc
318
[b]a CLASS is a collection of features that define the behaviour of an object.
319
The user interface to the class are the member functions and the events.[/b][br][br]
321
[big]Inheritance[/big]
323
Someone asked for derived classes ?[br]
325
The [cmd]class[/cmd] command allows you to define new object classes.
326
In KVI++, A new class must be always derived from some other class: the lowest possible
327
level of inheritance is 1: deriving from class [class]object[/class].[br]
329
[cmd]class[/cmd](helloworld,object)
333
[cmd]echo[/cmd] Hello world!
338
The above class is named "helloworld". It inherits the [class]object[/class] class.
339
This means that it acquires all the [class]object[/class] fuunctions: [classfnc:object]$name[/classfnc]() ,
340
[classfnc:object]$class[/class]() , [classfnc:object]$children[/classfnc]()...
341
Additionally , it has the $sayhello() function, that "echoes Hello world" to the console.
342
Now you can create an instance of this class:
344
%instance = [fnc]$new[/fnc](helloworld)
345
%instance->$sayhello()
347
You should see "Hello world" printed in the console.
348
Easy job...let's make the things a bit more complex now:
349
derive another class from helloworld and make it say "hello" in two different languages:[br]
351
[cmd]class[/cmd](localizedhelloworld,helloworld)
353
[comment]# define the setlanguage function[/comment]
354
[comment]# note that <$0 = language> is just a programmer reminder[/comment]
355
setlanguage(<$0 = language>)
357
[cmd]if[/cmd](($0 == english) || ($0 == italian))
359
[fnc:$this]$$[/fnc]->%lang = $0
362
[cmd]echo[/cmd] I don't know that language ($0)
363
[cmd]echo[/cmd] defaulting to english
364
[fnc:$this]$$[/fnc]->%lang = english
371
[cmd]if[/cmd]([fnc:$this]$$[/fnc]->%lang == italian)[cmd]echo[/cmd] Ciao mondo!
372
else [fnc:$this]$$[/fnc]->$helloworld:sayhello()
376
Now you can call:[br]
378
%m = [fnc]$new[/fnc](localizedhelloworld)
379
%m->$setLanguage(italian)
381
%m->$setLanguage(english)
383
%m->$setLanguage(turkish)
385
[cmd]delete[/cmd] %myobj
387
The class defined above is inherited from the previously defined helloworld class:
388
so it inherits the "object" class functions and events and the sayhello function from "helloworld".
389
In addition a setlanguage function is defined that stores in a variable the language name passed
390
as a parameter (after checking its validity). ($0 evaluates to the first parameter passed)
391
If the language is unknown the setlanguage function will return 0 (false).
392
Now we want to be able to say "hello world" in italian and english.
393
So we [b]override[/b] the inherited sayhello function.
394
"To override" means "to reimplement" : if you call %object->$sayhello() and %object
395
contains the ID of an instance of class "localizedhelloworld" , the new implementation of that function willl be called (executed).
396
The inherited sayhello was able to say "hello world" only in english , so we can still use it in the new implementation
397
without rewriting its contents. So if the language set is "not italian" we assume that it is english and
398
call the [b]base class implementation[/b].[br]
400
[fnc]$this/[fnc]->$helloworld:sayhello()
401
[comment]# equivalent to $$->$helloworld:sayhello(),[/comment]
402
[comment]# to $this->$helloworld::sayhello(),[/comment]
403
[comment]# and to $$->$helloworld::sayhello()[/comment]
405
otherwise the language is italian and we say "hello" in italian :).
406
So , to call a base class implementation of a function we "prepend" the base class name before the function name in the call.
407
The base class name could be also [class]object[/class] in this case , but the [class]object[/class] class has no "sayhello" function defined
408
so it would result in an error.[br][br]
409
In the above example , all the values of [fnc]$this[/fnc]</a>->%language
410
that are not equal to "italian" are assumed to be "english".
411
This is not always true , for example , just after the object creation the %language variable field
412
is effectively empty. The above class works correctly in this case , but we might want to have always
413
a coherent state of the field variables , so we need another concept: the class [b]constructor[/b]
414
that will be discussed in the next paragraph.[br][br]
416
Note: multiple inheritance (inheritance from more than one base class) is not implemented , KVIrc is not a compiler :)[br][br]
418
Objects are much more powerful....[br][br]
420
Do a [cmd]clearobjects[/cmd] to cleanup the old class definitions , and read on.[br][br]
422
[big]Constructors and destructors[/big]
424
The class constructor is a [b]function[/b] that is called automatically just after the object
425
has been created internally by KVIrc and just before the [fnc]$new[/fnc]
426
function returns. It should be used to setup the internal object state.[br]
427
Unlike in C++ , in KVIrc , the constructor CAN return a value:[br]
428
If it returns 0 it signals the object creation failure : the object
429
is immediately destroyed and [fnc]$new[/fnc]() returns 0 to the caller.
430
Any other return value is treated as success , so the object is effectively
431
created and [fnc]$new[/fnc]() returns its ID to the caller.[br]
432
All the builtin classes have a constructor defined that will almost never fail (only if we run out of memory),
433
so you can avoid to check the [fnc]$new[/fnc]() return value
434
when creating the instances of the built-in classes.[br][br]
436
In derived classes you can override the constructor to setup your object's state.[br]
437
You should [b]always call the base class constructor[/b] in your overridden one , to setup
438
the base class state , and propagate its return value (eventually modified if the base class
439
constructor is succesfull but your derived class initialization fails).[br]
440
In practice , the builtin class constructors do nothing other than setting the return
441
value to 1 so you can even avoid to call them, but in any other case you must do it.[br][br]
443
This is different from C (for example), where the constructors are called (more or less)
444
automatically.[br][br]
446
[big]Signals and slots[/big]
448
The signals and slots are a powerful mean of inter-object communication.
449
A signal is emitted by an object to notify a change in its state.
450
For example , the [class:button]button class[/class] emits the
451
[classsignal:button]clicked[/classsignal] signal when the user clicks the button.[br][br]
452
A signal is emitted by an object and can be received and handled by any other existing object
453
(including the object that emits the signal).[br]
454
The handler function for a signal is called "slot".[br]
455
It is just a convention : in fact , a slot is a normal object function (and any object function can be a slot).
456
More than one slot can be connected to a single signal , and more signals can be connected to a single slot.[br]
457
In this way , many objects can be notified of a change in a single object , as well as a single object
458
can easily handle state-changes for many objects.[br]
459
The signal / slot behaviour could be easily implemented by a careful usage of object functions.
460
[b]So why signals and slots ?[/b][br]
461
Because signals are much more powerful in many situations.
462
The signals have no equivalent in C/C++...but they have been implemented in many highlevel
463
C/C++ libraries and development kits (including the system-wide signal/handler mechanism implemented
464
by all the modern kernels and used in inter-process communication).[br]
470
///////////////////////////////////////////////////////////////////////////////////////
475
object class, object, class
481
Base class for all the KVIrc objects
485
This is the base class for all the builtin KVirc object classes.
486
It exports the functions to retrieve the object name, to iterate
487
through children objects and to lookup a child object by name or class.
488
Additionally , this class provides the builtin timer functionality.
489
The [classfnc]$constructor[/classfnc] and [classfnc]$destructor[/classfnc]
490
functions are empty implementations that all the other classes inherit.
493
Constructor for this object class.
494
The default implementation does nothing.
496
Destructor for this object class.
497
The default implementation emits the signal "[classsignal]destroyed[/classsignal]".
499
Returns the name of this object.
501
Returns the parent object of this object or 0 if this object has no parent.
502
!fn: $timerEvent(<timerId>)
503
Handler for the timer events.
504
The default implementation does nothing.
505
See also [classfnc]$startTimer[/classfnc]()
506
and [classfnc]$killTimer[/classfnc]().
507
!fn: $startTimer(<timeout>)
508
Starts a builtin timer for this object and returns its timer id
509
as a string or '-1' if the <timeout> was invalid.
510
The [classfnc]$timerEvent[/classfnc]() handler function
511
will be called at each <timeout>. The <timeout> is in milliseconds.
512
!fn: $killTimer(<timer id>)
513
Stops the timer specified by <timer id>.
515
Returns the class name of this object instance
516
!fn: $findChild(<class>,<name>)
517
Returns the first child that matches <class> and <name>.
518
If <class> is an empty string, any class matches,
519
if <name> is an empty string, any name matches.
520
This function traverses the entire tree of children
521
but is NOT recursive.
523
Returns the number of children objects
524
!fn: $emit(<signal_name>[,parameters])
525
Emits the signal <signal_name> passing the optional [parameters].
526
See the [doc:objects]objects documentation[/doc] for an overview of signals and slots.
528
Returns an array of children object identifiers.
530
Returns the current signal sender when in a slot connected to a signal.
531
In other contexts this function returns an empty string.
532
You can safely use it to test if the current function has been
533
triggered directly or from a signal emission.
535
Returns the name of the signal last signal that has triggered
536
one of this object's slots.
537
This means that in a slot handler it returns the name of the signal
538
that has triggered it.
539
!fn: $property(<Qt property name>[,bNowarning:boolean])
540
This is for really advanced scripting.[br]
541
All KVIrc widgets are based on the Qt library ones.[br]
542
The Qt library allow to set and read special properties.[br]
543
You will have to take a look at the Qt documentation for each widget type
544
to see the available property names.[br]
545
The supported property types are: Rect, Size, Point, Color, String, CString,
546
Int, UInt, Bool and enumeration types.[br]
547
For example, the widget's x coordinate can be retrieved by using the [classfnc]$x[/classfnc]()
548
function or by calling $property(x).[br]
549
There are many properties that are available ony through the [classfnc]$property()[classfnc]" call:[br]
550
For example, you can find out if the widget accepts drops by calling [classfnc]$property(acceptDrops)[classfnc].[br]
551
This function will be mainly useful in the [class]wrapper[/class] class.
552
!fn: $setProperty(<Qt property>,<property value>)
553
Sets a qt property for this widget.[br]
554
This is for advanced scripting, and can control really many features of the Qt widgets.[br]
555
For example, the [class]multilineedit[/class] widgets can be set to
556
the "password" echo mode only by using this function call:[br]
558
%X=$new(lineedit, 0, a_name)
560
%X->$setProperty(echoMode,Password)
562
The available properties to be set are listed by [classfnc]$listProperties[/classfnc]()[br]
563
and must appear in the list as writeable.[br]
564
This function will be mainly useful in the [class]wrapper[/class] class.
565
!fn: $listProperties([bArray])
566
Lists the properties of this object.[br]
567
If <bArray> is $true then the function returns the properties
568
as an array of descriptive strings, otherwise the properties are dumped to the
569
active window. If <bArray> is not passed then it is assumed to be $false.
570
This function will be mainly useful in the [class]wrapper[/class] class.
573
Emitted by the default implementation of [classfnc]$destructor[/classfnc].
574
If you reimplement [classfnc]$destructor[/classfnc] in one of the derived
575
classes (or as a private implementation), and still want this signal
576
to be emitted you must emit it by yourself, or (better) call the base class
580
// we use a char * pointer just to store a number
581
// we don't use void * just because incrementing a void pointer doesn't look that good
582
static char * g_hNextObjectHandle = (char *)0;
585
KviKvsObject::KviKvsObject(KviKvsObjectClass * pClass,KviKvsObject * pParent,const QString &szName)
588
if(g_hNextObjectHandle == 0)g_hNextObjectHandle++; // make sure it's never 0
589
m_hObject = (kvs_hobject_t)g_hNextObjectHandle;
590
g_hNextObjectHandle++;
593
m_bObjectOwner = true; // true by default
599
m_pChildList = new KviPointerList<KviKvsObject>;
600
m_pChildList->setAutoDelete(false);
602
m_pdataContainer = new KviKvsHash();
604
m_pFunctionHandlers = 0; // no local function handlers yet!
606
m_bInDelayedDeath = false;
608
m_pSignalDict = 0; // no signals connected to remote slots
609
m_pConnectionList = 0; // no local slots connected to remote signals
611
if(pParent)pParent->registerChild(this);
613
KviKvsKernel::instance()->objectController()->registerObject(this);
615
// debug("Hello world!");
616
// [root@localhost cvs3]# kvirc
618
// [root@localhost cvs3]# date
619
// Tue Sep 5 21:53:54 CEST 2000
620
// [root@localhost cvs3]#
622
// Ported to KVS on 29.04.2005
625
KviKvsObject::~KviKvsObject()
627
m_bInDelayedDeath = true;
628
while(m_pChildList->first())delete m_pChildList->first();
632
// Disconnect all the signals
635
KviPointerHashTableIterator<QString,KviKvsObjectConnectionList> it(*m_pSignalDict);
639
KviKvsObjectConnectionListIterator cit(*(it.current()));
642
disconnectSignal(it.currentKey(),cit.current());
643
// ++cit // NO!...we point to the next now!
645
// the iterator should automatically point to the next now
646
//if(m_pSignalDict)++it;
650
// Disconnect all the slots
651
if(m_pConnectionList)
653
KviKvsObjectConnectionListIterator cit(*m_pConnectionList);
656
QString szSig = cit.current()->szSignal;
657
cit.current()->pSourceObject->disconnectSignal(szSig,cit.current());
658
//++cit;// NO!... we point to the next now!
662
// Disconnect all the signals
665
if(!m_pSignalDict)break;
666
KviPointerHashTableEntry<QString,KviKvsObjectConnectionList> * pSignalList = m_pSignalDict->firstEntry();
667
if(!pSignalList)break;
668
KviKvsObjectConnection * pConnection = pSignalList->data()->first();
669
if(!pConnection)break;
670
disconnectSignal(pSignalList->key(),pConnection);
673
// Disconnect all the slots
676
if(!m_pConnectionList)break;
677
KviKvsObjectConnection * pConnection = m_pConnectionList->first();
678
if(!pConnection)break;
679
QString szSignalCopy = pConnection->szSignal; // we need this since pConnection is deleted inside disconnectSignal() and pConnection->szSignal dies too (but is referenced after the connection delete)
680
pConnection->pSourceObject->disconnectSignal(szSignalCopy,pConnection);
684
KviKvsKernel::instance()->objectController()->unregisterObject(this);
686
if(parentObject())parentObject()->unregisterChild(this);
690
disconnect(m_pObject,SIGNAL(destroyed()),this,SLOT(objectDestroyed()));
691
if(m_bObjectOwner)delete m_pObject;
694
delete m_pdataContainer;
695
if(m_pFunctionHandlers)delete m_pFunctionHandlers;
698
bool KviKvsObject::init(KviKvsRunTimeContext *,KviKvsVariantList *)
703
QWidget * KviKvsObject::parentScriptWidget()
707
if(parentObject()->object())
709
if(parentObject()->object()->isWidgetType())
710
return (QWidget *)(parentObject()->object());
716
void KviKvsObject::unregisterChild(KviKvsObject *pChild)
718
m_pChildList->removeRef(pChild);
721
void KviKvsObject::registerChild(KviKvsObject *pChild)
723
m_pChildList->append(pChild);
728
bool KviKvsObject::connectSignal(const QString &sigName,KviKvsObject * pTarget,const QString &slotName)
730
if(!pTarget->lookupFunctionHandler(slotName))return false; // no such slot
734
m_pSignalDict = new KviPointerHashTable<QString,KviKvsObjectConnectionList>(7,false);
735
m_pSignalDict->setAutoDelete(true);
738
KviKvsObjectConnectionList * l = m_pSignalDict->find(sigName);
741
l = new KviKvsObjectConnectionList;
742
l->setAutoDelete(true);
743
m_pSignalDict->insert(sigName,l);
746
KviKvsObjectConnection * con = new KviKvsObjectConnection;
748
con->pSourceObject = this;
749
con->pTargetObject = pTarget;
750
con->szSignal = sigName;
751
con->szSlot = slotName;
754
pTarget->registerConnection(con);
758
void KviKvsObject::registerConnection(KviKvsObjectConnection *pConnection)
760
if(!m_pConnectionList)
762
m_pConnectionList = new KviKvsObjectConnectionList;
763
m_pConnectionList->setAutoDelete(false);
765
m_pConnectionList->append(pConnection);
768
bool KviKvsObject::disconnectSignal(const QString &sigName,KviKvsObject * pTarget,const QString &slotName)
770
if(!m_pSignalDict)return false; //no such signal to disconnect
772
KviKvsObjectConnectionList * l = m_pSignalDict->find(sigName);
775
KviKvsObjectConnectionListIterator it(*l);
777
while(KviKvsObjectConnection * sl = it.current())
779
if(sl->pTargetObject == pTarget)
781
if(KviQString::equalCI(sl->szSlot,slotName))
783
pTarget->unregisterConnection(sl);
785
if(l->isEmpty())m_pSignalDict->remove(sigName);
786
if(m_pSignalDict->isEmpty())
788
delete m_pSignalDict;
799
bool KviKvsObject::disconnectSignal(const QString &sigName,KviKvsObjectConnection * pConnection)
801
if(!m_pSignalDict)return false;
802
KviKvsObjectConnectionList * l = m_pSignalDict->find(sigName);
805
pConnection->pTargetObject->unregisterConnection(pConnection);
806
//__range_valid(l->findRef(pConnection) > -1);
807
l->removeRef(pConnection);
808
if(l->isEmpty())m_pSignalDict->remove(sigName);
809
if(m_pSignalDict->isEmpty())
811
delete m_pSignalDict;
817
bool KviKvsObject::unregisterConnection(KviKvsObjectConnection * pConnection)
819
if(!m_pConnectionList)return false;
820
bool bOk = m_pConnectionList->removeRef(pConnection); // no auto delete !
821
if(!bOk)return false;
822
if(m_pConnectionList->isEmpty())
824
delete m_pConnectionList;
825
m_pConnectionList = 0;
830
int KviKvsObject::emitSignal(const QString &sigName,KviKvsObjectFunctionCall * pOuterCall,KviKvsVariantList * pParams)
832
if(!m_pSignalDict)return 0;
834
KviKvsObjectConnectionList * l = m_pSignalDict->find(sigName);
835
if(!l)return 0; // no slots registered
837
KviKvsVariant retVal;
839
// The objects we're going to disconnect
840
KviPointerList<KviKvsObjectConnection> * pDis = 0;
842
kvs_int_t emitted = 0;
844
KviKvsObjectConnectionListIterator it(*l);
846
while(KviKvsObjectConnection * s = it.current())
848
// save it , since s may be destroyed in the call!
849
KviKvsObject * pTarget = s->pTargetObject;
853
kvs_hobject_t hTarget = pTarget->handle();
854
kvs_hobject_t hOld = pTarget->signalSender();
856
pTarget->setSignalSender(m_hObject);
857
pTarget->setSignalName(sigName);
859
if(!pTarget->callFunction(this,s->szSlot,QString(),pOuterCall->context(),&retVal,pParams))
861
if(KviKvsKernel::instance()->objectController()->lookupObject(hTarget) && it.current())
864
__tr2qs_ctx("Broken slot '%Q' in target object '%Q::%Q' while emitting signal '%Q' from object '%Q::%Q': disconnecting","kvs"),
866
&(s->pTargetObject->getClass()->name()),
867
&(s->pTargetObject->getName()),
869
&(getClass()->name()),
874
pDis = new KviPointerList<KviKvsObjectConnection>;
875
pDis->setAutoDelete(false);
879
// else destroyed in the call! (already disconnected)
882
__tr2qs_ctx("Slot target object destroyed while emitting signal '%Q' from object '%Q::%Q'","kvs"),
884
&(getClass()->name()),
889
if(KviKvsKernel::instance()->objectController()->lookupObject(hTarget))
891
pTarget->setSignalSender(hOld);
899
// we have some signals to disconnect (because they're broken)
900
for(KviKvsObjectConnection * con = pDis->first();con;con = pDis->next())
901
disconnectSignal(sigName,con);
908
bool KviKvsObject::function_name(KviKvsObjectFunctionCall * c)
910
c->returnValue()->setString(getName());
914
bool KviKvsObject::function_parent(KviKvsObjectFunctionCall * c)
916
KviKvsObject * o = parentObject();
917
c->returnValue()->setHObject(o ? o->handle() : (kvs_hobject_t)0);
921
bool KviKvsObject::function_className(KviKvsObjectFunctionCall * c)
923
c->returnValue()->setString(getClass()->name());
927
bool KviKvsObject::function_childCount(KviKvsObjectFunctionCall * c)
929
c->returnValue()->setInteger((kvs_int_t)(m_pChildList->count()));
933
bool KviKvsObject::function_signalSender(KviKvsObjectFunctionCall * c)
935
c->returnValue()->setHObject(m_hSignalSender);
939
bool KviKvsObject::function_signalName(KviKvsObjectFunctionCall * c)
941
c->returnValue()->setString(m_szSignalName);
945
bool KviKvsObject::function_destructor(KviKvsObjectFunctionCall * c)
947
emitSignal("destroyed",c);
951
bool KviKvsObject::function_children(KviKvsObjectFunctionCall * c)
953
KviKvsArray * a = new KviKvsArray();
955
for(KviKvsObject * o = m_pChildList->first();o;o = m_pChildList->next())
957
a->set(id,new KviKvsVariant(o->handle()));
960
c->returnValue()->setArray(a);
964
bool KviKvsObject::function_findChild(KviKvsObjectFunctionCall * c)
966
QString szClass,szName;
967
KVSO_PARAMETERS_BEGIN(c)
968
KVSO_PARAMETER("className",KVS_PT_STRING,KVS_PF_OPTIONAL,szClass)
969
KVSO_PARAMETER("objectName",KVS_PT_STRING,KVS_PF_OPTIONAL,szName)
970
KVSO_PARAMETERS_END(c)
972
KviKvsObject * o = findChild(szClass,szName);
973
c->returnValue()->setHObject(o ? o->handle() : (kvs_hobject_t)0);
978
bool KviKvsObject::function_emit(KviKvsObjectFunctionCall * c)
981
KviKvsVariantList vList;
982
KVSO_PARAMETERS_BEGIN(c)
983
KVSO_PARAMETER("signal",KVS_PT_NONEMPTYSTRING,0,szSignal)
984
KVSO_PARAMETER("params",KVS_PT_VARIANTLIST,KVS_PF_OPTIONAL,vList)
985
KVSO_PARAMETERS_END(c)
987
emitSignal(szSignal,c,&vList);
991
bool KviKvsObject::function_startTimer(KviKvsObjectFunctionCall * c)
994
KVSO_PARAMETERS_BEGIN(c)
995
KVSO_PARAMETER("timeout",KVS_PT_UINT,0,timeout)
996
KVSO_PARAMETERS_END(c)
998
c->returnValue()->setInteger((kvs_int_t)(startTimer(timeout)));
1002
bool KviKvsObject::function_killTimer(KviKvsObjectFunctionCall * c)
1005
KVSO_PARAMETERS_BEGIN(c)
1006
KVSO_PARAMETER("timerId",KVS_PT_INT,0,id)
1007
KVSO_PARAMETERS_END(c)
1012
bool KviKvsObject::function_listProperties(KviKvsObjectFunctionCall * c)
1015
KVSO_PARAMETERS_BEGIN(c)
1016
KVSO_PARAMETER("bArray",KVS_PT_BOOL,KVS_PF_OPTIONAL,bArray)
1017
KVSO_PARAMETERS_END(c)
1019
c->returnValue()->setNothing();
1021
KviKvsArray * a = bArray ? new KviKvsArray() : 0;
1023
KviWindow * w = c->context()->window();
1026
w->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs_ctx("Listing Qt properties for object named '%Q' of KVS class %Q","kvs"),&m_szName,&(m_pClass->name()));
1030
const QMetaObject *o = m_pObject->metaObject();
1032
w->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs_ctx("Properties for Qt class %s","kvs"),o->className());
1034
QMetaProperty prop = o->property(idx);
1035
const QMetaProperty *p = ∝
1039
QString szName = p->name();
1040
QString szType = p->typeName();
1042
KviQString::sprintf(szOut,"%Q, %Q",&szName,&szType);
1044
KviQString::sprintf(szOut,__tr2qs_ctx("Property: %c%Q%c, type %Q","kvs"),KVI_TEXT_BOLD,&szName,KVI_TEXT_BOLD,&szType);
1055
// FIXME: QT4 Need to read better the docs and check the changes: there seem to be too many
1056
// for me to fix now. Actually I need to get the whole executable working...
1057
if(p->isWritable())szOut += ", writable";
1059
a->set(cnt,new KviKvsVariant(szOut));
1061
w->outputNoFmt(KVI_OUT_SYSTEMMESSAGE,szOut);
1063
if (idx<o->propertyCount()){
1064
prop = o->property(idx);
1074
c->returnValue()->setArray(a);
1076
w->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs_ctx("%d properties listed","kvs"),cnt);
1080
bool KviKvsObject::function_setProperty(KviKvsObjectFunctionCall * c)
1084
KVSO_PARAMETERS_BEGIN(c)
1085
KVSO_PARAMETER("propertyName",KVS_PT_NONEMPTYSTRING,0,szName)
1086
KVSO_PARAMETER("propertyValue",KVS_PT_VARIANT,0,v)
1087
KVSO_PARAMETERS_END(c)
1089
c->returnValue()->setNothing();
1093
// there are no Qt properties at all
1094
c->warning(__tr2qs_ctx("The object named '%Q' of class '%Q' has no Qt properties","kvs"),&m_szName,&(m_pClass->name()));
1098
int idx = m_pObject->metaObject()->indexOfProperty(szName.toUtf8().data());
1101
c->warning(__tr2qs_ctx("No Qt property named '%Q' for object named '%Q' of class '%Q'","kvs"),&szName,&m_szName,&(m_pClass->name()));
1104
QMetaProperty prop = m_pObject->metaObject()->property(idx);
1105
const QMetaProperty * p = ∝
1108
c->warning(__tr2qs_ctx("Can't find property named '%Q' for object named '%Q' of class '%Q': the property is indexed but it doesn't really exist","kvs"),&szName,&m_szName,&(m_pClass->name()));
1112
QVariant vv = m_pObject->property(szName.toUtf8().data());
1115
c->warning(__tr2qs_ctx("Can't find property named '%Q' for object named '%Q'of class '%Q': the property is indexed and defined but the returned variant is not valid","kvs"),&szName,&m_szName,&(m_pClass->name()));
1123
int val = p->enumerator().keyToValue(szKey.toUtf8().data());
1125
m_pObject->setProperty(szName.toUtf8().data(),var);
1129
#define WRONG_TYPE(__therighttype) \
1131
c->warning(__tr2qs_ctx("The property is of type %s but the supplied argument can't be converted to that type (expecting '%s')","kvs"),p->type(),__therighttype); \
1140
if(!v->asInteger(i))WRONG_TYPE("integer")
1141
m_pObject->setProperty(szName.toUtf8().data(),QVariant((int)i));
1144
case QVariant::UInt:
1147
if(!v->asInteger(i))WRONG_TYPE("unsigned integer")
1148
if(i < 0)WRONG_TYPE("unsigned integer")
1149
m_pObject->setProperty(szName.toUtf8().data(),QVariant((unsigned int)i));
1151
case QVariant::Double:
1154
if(!v->asReal(i))WRONG_TYPE("real")
1155
m_pObject->setProperty(szName.toUtf8().data(),QVariant((double)i));
1158
case QVariant::Bool:
1159
m_pObject->setProperty(szName.toUtf8().data(),QVariant(v->asBoolean()));
1161
case QVariant::String:
1165
m_pObject->setProperty(szName.toUtf8().data(),QVariant(s));
1168
case QVariant::ByteArray:
1172
m_pObject->setProperty(szName.toUtf8().data(),QVariant(s.toUtf8()));
1175
case QVariant::Point:
1177
if(!v->isArray())WRONG_TYPE("array(integer,integer)")
1178
KviKvsArray * a = v->array();
1179
KviKvsVariant * x = a->at(0);
1180
KviKvsVariant * y = a->at(1);
1181
if(!x || !y)WRONG_TYPE("array(integer,integer)")
1183
if(!x->asInteger(iX) || !y->asInteger(iY))WRONG_TYPE("array(integer,integer)")
1184
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QPoint(iX,iY)));
1187
case QVariant::Size:
1189
if(!v->isArray())WRONG_TYPE("array(integer,integer)")
1190
KviKvsArray * a = v->array();
1191
KviKvsVariant * w = a->at(0);
1192
KviKvsVariant * h = a->at(1);
1193
if(!w || !h)WRONG_TYPE("array(integer,integer)")
1195
if(!w->asInteger(iW) || !h->asInteger(iH))WRONG_TYPE("array(integer,integer)")
1196
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QSize(iW,iH)));
1199
case QVariant::Rect:
1201
if(!v->isArray())WRONG_TYPE("array(integer,integer,integer,integer)")
1202
KviKvsArray * a = v->array();
1203
KviKvsVariant * x = a->at(0);
1204
KviKvsVariant * y = a->at(1);
1205
KviKvsVariant * w = a->at(2);
1206
KviKvsVariant * h = a->at(3);
1207
if(!x || !y || !w || !h)WRONG_TYPE("array(integer,integer,integer,integer)")
1208
kvs_int_t iX,iY,iW,iH;
1209
if(!x->asInteger(iX) || !y->asInteger(iY) || !w->asInteger(iW) || !h->asInteger(iH))WRONG_TYPE("array(integer,integer,integer,integer)")
1210
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QRect(iX,iY,iW,iH)));
1214
case QVariant::Color:
1216
if(!v->isArray())WRONG_TYPE("array(integer,integer,integer)")
1217
KviKvsArray * a = v->array();
1218
KviKvsVariant * r = a->at(0);
1219
KviKvsVariant * g = a->at(1);
1220
KviKvsVariant * b = a->at(3);
1221
if(!r || !g || !b)WRONG_TYPE("array(integer,integer,integer)")
1223
if(!r->asInteger(iR) || !g->asInteger(iG) || !b->asInteger(iB))WRONG_TYPE("array(integer,integer,integer)")
1224
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QColor(iR,iG,iB)));
1227
case QVariant::Font:
1229
if(!v->isArray())WRONG_TYPE("array(string,integer,string)")
1230
KviKvsArray * a = v->array();
1231
KviKvsVariant * ff = a->at(0);
1232
KviKvsVariant * ps = a->at(1);
1233
KviKvsVariant * fl = a->at(3);
1234
if(!ff || !ps)WRONG_TYPE("array(string,integer,string)")
1236
if(!ps->asInteger(iPs))WRONG_TYPE("array(string,integer,string)")
1239
if(fl)fl->asString(szFl);
1241
fnt.setFamily(szFf);
1242
fnt.setPointSize(iPs);
1243
if(szFl.indexOf('b',Qt::CaseInsensitive) != -1)fnt.setBold(true);
1244
if(szFl.indexOf('i',Qt::CaseInsensitive) != -1)fnt.setItalic(true);
1245
if(szFl.indexOf('u',Qt::CaseInsensitive) != -1)fnt.setUnderline(true);
1246
if(szFl.indexOf('o',Qt::CaseInsensitive) != -1)fnt.setOverline(true);
1247
if(szFl.indexOf('f',Qt::CaseInsensitive) != -1)fnt.setFixedPitch(true);
1248
if(szFl.indexOf('s',Qt::CaseInsensitive) != -1)fnt.setStrikeOut(true);
1249
m_pObject->setProperty(szName.toUtf8().data(),QVariant(fnt));
1252
case QVariant::Pixmap:
1256
if(v->hobject() == (kvs_hobject_t)0)
1259
if(vv.type() == QVariant::Pixmap)
1260
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QPixmap()));
1262
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QIcon()));
1264
KviKvsObject * pix = KviKvsKernel::instance()->objectController()->lookupObject(v->hobject());
1265
if(!pix->inherits("KviScriptPixmapObject"))
1266
c->warning(__tr2qs_ctx("A pixmap object, an image_id or an image file path is required for this property","kvs"));
1268
QVariant pixv = pix->property("pixmap");
1269
if(vv.type() == QVariant::Pixmap)
1270
m_pObject->setProperty(szName.toUtf8().data(),QVariant(pixv.value<QPixmap>()));
1272
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QIcon(pixv.value<QPixmap>())));
1278
QPixmap * pPix = g_pIconManager->getImage(szStr);
1281
if(vv.type() == QVariant::Pixmap)
1282
m_pObject->setProperty(szName.toUtf8().data(),QVariant(*pPix));
1284
m_pObject->setProperty(szName.toUtf8().data(),QVariant(QIcon(*pPix)));
1287
c->warning(__tr2qs_ctx("Can't find the requested image","kvs"));
1294
c->warning(__tr2qs_ctx("Property '%Q' for object named '%Q' of class '%Q' has an unsupported data type","kvs"),&szName,&m_szName,&(m_pClass->name()));
1295
c->returnValue()->setNothing();
1301
bool KviKvsObject::function_property(KviKvsObjectFunctionCall * c)
1305
KVSO_PARAMETERS_BEGIN(c)
1306
KVSO_PARAMETER("propertyName",KVS_PT_NONEMPTYSTRING,0,szName)
1307
KVSO_PARAMETER("bNowarning",KVS_PT_BOOL,KVS_PF_OPTIONAL,bNoerror)
1308
KVSO_PARAMETERS_END(c)
1312
// there are no Qt properties at all
1313
if (bNoerror) c->returnValue()->setString("No Qt properties");
1316
c->warning(__tr2qs_ctx("The object named '%Q' of class '%Q' has no Qt properties","kvs"),&m_szName,&(m_pClass->name()));
1317
c->returnValue()->setNothing();
1322
int idx = m_pObject->metaObject()->indexOfProperty(szName.toUtf8().data());
1326
c->returnValue()->setString("No Qt properties");
1329
c->warning(__tr2qs_ctx("No Qt property named '%Q' for object named '%Q' of class '%Q'","kvs"),&szName,&m_szName,&(m_pClass->name()));
1330
c->returnValue()->setNothing();
1334
QMetaProperty prop = m_pObject->metaObject()->property(idx);
1335
const QMetaProperty * p = ∝
1338
c->warning(__tr2qs_ctx("Can't find property named '%Q' for object named '%Q' of class '%Q': the property is indexed but it doesn't really exist","kvs"),&szName,&m_szName,&(m_pClass->name()));
1339
c->returnValue()->setNothing();
1343
QVariant v = m_pObject->property(szName.toUtf8().data());
1346
c->warning(__tr2qs_ctx("Can't find property named '%Q' for object named '%Q' of class '%Q': the property is indexed and defined but the returned variant is not valid","kvs"),&szName,&m_szName,&(m_pClass->name()));
1347
c->returnValue()->setNothing();
1353
c->returnValue()->setString(p->enumerator().valueToKey(v.toInt()));
1360
c->returnValue()->setInteger((kvs_int_t)v.toInt());
1362
case QVariant::Double:
1363
c->returnValue()->setReal((kvs_int_t)v.toDouble());
1365
case QVariant::UInt:
1366
c->returnValue()->setInteger((kvs_int_t)v.toUInt());
1368
case QVariant::Bool:
1369
c->returnValue()->setBoolean(v.toBool());
1371
case QVariant::String:
1372
c->returnValue()->setString(v.toString());
1374
case QVariant::ByteArray:
1375
c->returnValue()->setString(QString::fromUtf8(v.toByteArray().data()));
1377
case QVariant::Point:
1379
QPoint p = v.toPoint();
1380
KviKvsArray * a = new KviKvsArray();
1381
a->set(0,new KviKvsVariant((kvs_int_t)p.x()));
1382
a->set(1,new KviKvsVariant((kvs_int_t)p.y()));
1383
c->returnValue()->setArray(a);
1386
case QVariant::Size:
1388
QSize p = v.toSize();
1389
KviKvsArray * a = new KviKvsArray();
1390
a->set(0,new KviKvsVariant((kvs_int_t)p.width()));
1391
a->set(1,new KviKvsVariant((kvs_int_t)p.height()));
1392
c->returnValue()->setArray(a);
1395
case QVariant::Rect:
1397
QRect p = v.toRect();
1398
KviKvsArray * a = new KviKvsArray();
1399
a->set(0,new KviKvsVariant((kvs_int_t)p.x()));
1400
a->set(1,new KviKvsVariant((kvs_int_t)p.y()));
1401
a->set(2,new KviKvsVariant((kvs_int_t)p.width()));
1402
a->set(3,new KviKvsVariant((kvs_int_t)p.height()));
1403
c->returnValue()->setArray(a);
1406
case QVariant::Color:
1408
QColor clr = v.value<QColor>();
1409
KviKvsArray * a = new KviKvsArray();
1410
a->set(0,new KviKvsVariant((kvs_int_t)clr.red()));
1411
a->set(1,new KviKvsVariant((kvs_int_t)clr.green()));
1412
a->set(2,new KviKvsVariant((kvs_int_t)clr.blue()));
1413
c->returnValue()->setArray(a);
1416
case QVariant::Font:
1418
QFont f = v.value<QFont>();
1419
KviKvsArray * a = new KviKvsArray();
1420
a->set(0,new KviKvsVariant(f.family()));
1421
a->set(1,new KviKvsVariant((kvs_int_t)f.pointSize()));
1423
if(f.bold())szFlags += "b";
1424
if(f.underline())szFlags += "u";
1425
if(f.overline())szFlags += "o";
1426
if(f.strikeOut())szFlags += "s";
1427
if(f.fixedPitch())szFlags += "f";
1428
if(f.italic())szFlags += "i";
1429
a->set(2,new KviKvsVariant(szFlags));
1430
c->returnValue()->setString(szFlags);
1434
if (bNoerror) c->returnValue()->setString("Unsupported_data_type");
1437
c->warning(__tr2qs_ctx("Property '%Q' for object named '%Q' of class '%Q' has an unsupported data type","kvs"),&szName,&m_szName,&(m_pClass->name()));
1438
c->returnValue()->setNothing();
1445
void KviKvsObject::killAllChildrenWithClass(KviKvsObjectClass *cl)
1447
KviPointerList<KviKvsObject> l;
1448
l.setAutoDelete(true);
1449
for(KviKvsObject * o=m_pChildList->first();o;o=m_pChildList->next())
1451
if(o->getClass() == cl)
1454
} else o->killAllChildrenWithClass(cl);
1457
bool KviKvsObject::inheritsClass(const QString &szClass)
1459
KviKvsObjectClass * pClass = KviKvsKernel::instance()->objectController()->lookupClass(szClass);
1460
if (pClass) return inheritsClass(pClass);
1463
bool KviKvsObject::inheritsClass(KviKvsObjectClass * pClass)
1465
if(pClass == m_pClass)return true;
1466
KviKvsObjectClass * cl = m_pClass->m_pParentClass;
1469
if(cl == pClass)return true;
1470
else cl = cl->m_pParentClass;
1475
KviKvsObjectClass * KviKvsObject::getClass(const QString & classOverride)
1477
if(classOverride.isEmpty())return m_pClass;
1478
KviKvsObjectClass * cl = m_pClass; // class override can be also THIS class
1479
// if object->$function() is a local override, class::object->$function()
1480
// is the class member function (not the local override)
1483
if(KviQString::equalCI(cl->name(),classOverride))break;
1484
else cl = cl->m_pParentClass;
1489
KviKvsObjectFunctionHandler * KviKvsObject::lookupFunctionHandler(const QString & funcName,const QString & classOverride)
1491
KviKvsObjectFunctionHandler * h = 0;
1493
if(classOverride.isEmpty() && m_pFunctionHandlers)
1495
// lookup the local overrides
1496
h = m_pFunctionHandlers->find(funcName);
1501
// not a local override function... lookup in the class
1502
KviKvsObjectClass * cl = getClass(classOverride);
1503
if(cl)return cl->lookupFunctionHandler(funcName);
1510
bool KviKvsObject::die()
1512
if(m_bInDelayedDeath)return false;
1513
m_bInDelayedDeath = true;
1514
QTimer::singleShot(0,this,SLOT(delayedDie()));
1518
bool KviKvsObject::dieNow()
1520
if(m_bInDelayedDeath)return false;
1521
m_bInDelayedDeath = true;
1526
void KviKvsObject::delayedDie()
1528
delete this; // byez!
1531
void KviKvsObject::setObject(QObject * o,bool bIsOwned)
1533
//__range_invalid(m_pObject);
1534
m_bObjectOwner = bIsOwned;
1536
o->installEventFilter(this);
1537
connect(m_pObject,SIGNAL(destroyed()),this,SLOT(objectDestroyed()));
1540
void KviKvsObject::objectDestroyed()
1546
bool KviKvsObject::eventFilter(QObject *,QEvent *)
1548
return false; // do not stop
1551
void KviKvsObject::timerEvent(QTimerEvent *e)
1553
KviKvsVariant * v = new KviKvsVariant();
1554
v->setInteger(e->timerId());
1555
KviKvsVariantList parms(v);
1557
callFunction(this,"timerEvent",&parms);
1560
bool KviKvsObject::callFunction(KviKvsObject * pCaller,const QString &fncName,KviKvsVariant * pRetVal,KviKvsVariantList * pParams)
1563
if(!pRetVal)pRetVal = &rv;
1564
KviKvsRunTimeContext ctx(0,g_pApp->activeConsole(),KviKvsKernel::instance()->emptyParameterList(),pRetVal,0);
1565
if(!pParams)pParams = KviKvsKernel::instance()->emptyParameterList();
1566
return callFunction(pCaller,fncName,QString(),&ctx,pRetVal,pParams);
1569
bool KviKvsObject::callFunction(KviKvsObject * pCaller,const QString &fncName,KviKvsVariantList * pParams)
1571
KviKvsVariant fakeRetVal;
1572
return callFunction(pCaller,fncName,&fakeRetVal,pParams);
1575
bool KviKvsObject::callFunction(
1576
KviKvsObject * pCaller,
1577
const QString & fncName,
1578
const QString & classOverride,
1579
KviKvsRunTimeContext * pContext,
1580
KviKvsVariant * pRetVal,
1581
KviKvsVariantList * pParams)
1583
KviKvsObjectFunctionHandler * h = lookupFunctionHandler(fncName,classOverride);
1587
if(classOverride.isEmpty())
1588
pContext->error(__tr2qs_ctx("Cannot find object function $%Q for object named '%Q' of class '%Q'","kvs"),&fncName,&m_szName,&(getClass()->name()));
1590
pContext->error(__tr2qs_ctx("Cannot find object function $%Q::%Q for object named '%Q' of class '%Q'","kvs"),&classOverride,&fncName,&m_szName,&(getClass()->name()));
1594
if(h->flags() & KviKvsObjectFunctionHandler::Internal)
1598
pContext->error(__tr2qs_ctx("Cannot call internal object function $%Q (for object named '%Q' of class '%Q') from this context","kvs"),&fncName,&m_szName,&(getClass()->name()));
1603
KviKvsObjectFunctionCall fc(pContext,pParams,pRetVal);
1605
return h->call(this,&fc);
1607
// Not only gcc spits out compiler errors:
1608
// 25.09.2001 , at this point in file
1610
// c:\programmi\microsoft visual studio\myprojects\kvirc3\src\kvirc\uparser\kvi_scriptobject.cpp(1234) : fatal error C1001: INTERNAL COMPILER ERROR
1611
// (compiler file 'E:\8168\vc98\p2\src\P2\main.c', line 494)
1612
// Please choose the Technical Support command on the Visual C++
1613
// Help menu, or open the Technical Support help file for more information
1616
void KviKvsObject::registerPrivateImplementation(const QString &szFunctionName,const QString &szCode)
1618
if(szCode.isEmpty())
1620
if(m_pFunctionHandlers)
1622
m_pFunctionHandlers->remove(szFunctionName);
1623
if(m_pFunctionHandlers->isEmpty())
1625
delete m_pFunctionHandlers;
1626
m_pFunctionHandlers = 0;
1630
if(!m_pFunctionHandlers)
1632
m_pFunctionHandlers = new KviPointerHashTable<QString,KviKvsObjectFunctionHandler>(7,false);
1633
m_pFunctionHandlers->setAutoDelete(true);
1636
QString szContext = m_pClass->name();
1637
szContext += "[privateimpl]::";
1638
szContext += szFunctionName;
1640
m_pFunctionHandlers->replace(szFunctionName,new KviKvsObjectScriptFunctionHandler(szContext,szCode));
1644
KviKvsObject * KviKvsObject::findChild(const QString &szClass,const QString &szName)
1646
for(KviKvsObject * o = m_pChildList->first();o;o= m_pChildList->next())
1648
if(szClass.isEmpty())
1650
// any class matches
1651
if(szName.isEmpty())return o; // any name matches
1653
if(KviQString::equalCI(szName,o->objectName()))return o;
1655
if(KviQString::equalCI(szClass,o->getClass()->name()))
1657
if(szName.isEmpty())return o; // any name matches
1659
if(KviQString::equalCI(szName,o->objectName()))return o;
1662
KviKvsObject * c = o->findChild(szClass,szName);