summaryrefslogtreecommitdiffstats
path: root/qtruby
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit90825e2392b2d70e43c7a25b8a3752299a933894 (patch)
treee33aa27f02b74604afbfd0ea4f1cfca8833d882a /qtruby
downloadtdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.tar.gz
tdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebindings@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'qtruby')
-rw-r--r--qtruby/AUTHORS54
-rw-r--r--qtruby/COPYING297
-rw-r--r--qtruby/ChangeLog1640
-rw-r--r--qtruby/INSTALL144
-rw-r--r--qtruby/Makefile.am3
-rw-r--r--qtruby/README259
-rw-r--r--qtruby/README.1st17
-rw-r--r--qtruby/TODO13
-rw-r--r--qtruby/bin/Makefile.am9
-rw-r--r--qtruby/bin/qtrubyinit.cpp29
-rwxr-xr-xqtruby/bin/rbqtapi103
-rwxr-xr-xqtruby/bin/rbqtsh627
-rw-r--r--qtruby/rubylib/Makefile.am1
-rw-r--r--qtruby/rubylib/designer/Makefile.am1
-rw-r--r--qtruby/rubylib/designer/examples/colortool/Makefile30
-rw-r--r--qtruby/rubylib/designer/examples/colortool/README8
-rw-r--r--qtruby/rubylib/designer/examples/colortool/colornameform.ui168
-rw-r--r--qtruby/rubylib/designer/examples/colortool/colornameform.ui.rb19
-rw-r--r--qtruby/rubylib/designer/examples/colortool/findform.ui141
-rw-r--r--qtruby/rubylib/designer/examples/colortool/findform.ui.rb11
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/editcopybin0 -> 268 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/editcopy.pngbin0 -> 187 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/editcutbin0 -> 214 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/editcut.pngbin0 -> 179 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/editraise.pngbin0 -> 489 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/filenewbin0 -> 184 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/filenew.pngbin0 -> 128 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/fileopenbin0 -> 231 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/fileopen.pngbin0 -> 178 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/filesavebin0 -> 230 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/filesave.pngbin0 -> 158 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/iconview.pngbin0 -> 898 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/richtextedit.pngbin0 -> 878 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/searchfindbin0 -> 658 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/searchfind.pngbin0 -> 554 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/table.pngbin0 -> 407 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/tabwidget.pngbin0 -> 545 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/images/widgetstack.pngbin0 -> 664 bytes
-rw-r--r--qtruby/rubylib/designer/examples/colortool/main.rb20
-rw-r--r--qtruby/rubylib/designer/examples/colortool/mainform.ui601
-rw-r--r--qtruby/rubylib/designer/examples/colortool/mainform.ui.rb530
-rw-r--r--qtruby/rubylib/designer/examples/colortool/optionsform.ui153
-rw-r--r--qtruby/rubylib/designer/rbuic/LICENSE.GPL280
-rw-r--r--qtruby/rubylib/designer/rbuic/Makefile.am24
-rw-r--r--qtruby/rubylib/designer/rbuic/TODO4
-rw-r--r--qtruby/rubylib/designer/rbuic/domtool.cpp453
-rw-r--r--qtruby/rubylib/designer/rbuic/domtool.h53
-rw-r--r--qtruby/rubylib/designer/rbuic/embed.cpp297
-rw-r--r--qtruby/rubylib/designer/rbuic/form.cpp1017
-rw-r--r--qtruby/rubylib/designer/rbuic/globaldefs.h45
-rw-r--r--qtruby/rubylib/designer/rbuic/main.cpp293
-rw-r--r--qtruby/rubylib/designer/rbuic/object.cpp750
-rw-r--r--qtruby/rubylib/designer/rbuic/parser.cpp71
-rw-r--r--qtruby/rubylib/designer/rbuic/parser.h33
-rw-r--r--qtruby/rubylib/designer/rbuic/rbuic.pro24
-rw-r--r--qtruby/rubylib/designer/rbuic/subclassing.cpp197
-rw-r--r--qtruby/rubylib/designer/rbuic/uic.cpp1104
-rw-r--r--qtruby/rubylib/designer/rbuic/uic.h181
-rw-r--r--qtruby/rubylib/designer/rbuic/widgetdatabase.cpp833
-rw-r--r--qtruby/rubylib/designer/rbuic/widgetdatabase.h85
-rw-r--r--qtruby/rubylib/designer/rbuic/widgetinterface.h29
-rw-r--r--qtruby/rubylib/designer/uilib/Makefile.am7
-rw-r--r--qtruby/rubylib/designer/uilib/extconf.rb6
-rw-r--r--qtruby/rubylib/designer/uilib/qui.cpp175
-rw-r--r--qtruby/rubylib/designer/uilib/test/test.rb20
-rw-r--r--qtruby/rubylib/examples/base/kicons.rb54
-rw-r--r--qtruby/rubylib/examples/base/rui.rb21
-rw-r--r--qtruby/rubylib/examples/canvastest/canvastest.rb75
-rw-r--r--qtruby/rubylib/examples/killerfilter/killerfilter.rb56
-rw-r--r--qtruby/rubylib/examples/network/clientserver/client/client.rb88
-rw-r--r--qtruby/rubylib/examples/network/clientserver/server/server.rb115
-rw-r--r--qtruby/rubylib/examples/passivepopup/passivepopup.rb39
-rw-r--r--qtruby/rubylib/examples/qt-examples/aclock/aclock.rb113
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/aclock/main.rb15
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/README8
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/canvastext.rb16
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/canvasview.rb53
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/chartform.rb488
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/chartform_canvas.rb212
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/chartform_files.rb102
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/element.rb161
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/chart-forms.sk256
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/file_new.xpm36
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/file_open.xpm33
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/file_print.xpm115
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/file_save.xpm33
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/file_saveaspostscript.xpm34
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/options_horizontalbarchart.xpm31
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/options_piechart.xpm30
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/options_setdata.xpm34
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/options_setfont.xpm27
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/options_setoptions.xpm32
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/options_verticalbarchart.xpm31
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern01.xpm27
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern02.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern03.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern04.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern05.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern06.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern07.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern08.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern09.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern10.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern11.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern12.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern13.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/images/pattern14.xpm28
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/main.rb26
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/optionsform.rb127
-rw-r--r--qtruby/rubylib/examples/qt-examples/chart/setdataform.rb184
-rw-r--r--qtruby/rubylib/examples/qt-examples/checklists/checklists.rb147
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/checklists/main.rb15
-rw-r--r--qtruby/rubylib/examples/qt-examples/dclock/dclock.rb67
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/dclock/main.rb12
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/main.rb14
-rw-r--r--qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/viewer.rb140
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/forever/forever.rb84
-rw-r--r--qtruby/rubylib/examples/qt-examples/hello/hello.rb78
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/hello/main.rb23
-rw-r--r--qtruby/rubylib/examples/qt-examples/progress/progress.rb275
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/tictac/main.rb13
-rw-r--r--qtruby/rubylib/examples/qt-examples/tictac/tictac.rb311
-rwxr-xr-xqtruby/rubylib/examples/qt-examples/tooltip/main.rb12
-rw-r--r--qtruby/rubylib/examples/qt-examples/tooltip/tooltip.rb95
-rw-r--r--qtruby/rubylib/examples/qtscribble/scribble.rb274
-rw-r--r--qtruby/rubylib/examples/ruboids/Manifest26
-rw-r--r--qtruby/rubylib/examples/ruboids/README53
-rw-r--r--qtruby/rubylib/examples/ruboids/TODO29
-rw-r--r--qtruby/rubylib/examples/ruboids/boids.properties33
-rwxr-xr-xqtruby/rubylib/examples/ruboids/generateManifest.rb42
-rw-r--r--qtruby/rubylib/examples/ruboids/index.html147
-rwxr-xr-xqtruby/rubylib/examples/ruboids/release.rb152
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Boid.rb141
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/BoidView.rb159
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Camera.rb24
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/CameraDialog.rb213
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Canvas.rb144
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Cloud.rb61
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/CloudView.rb54
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Flock.rb47
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Graphics.rb278
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Params.rb87
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Point.rb153
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Thing.rb34
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/Triangle.rb21
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/View.rb88
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/World.rb82
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/WorldWindow.rb54
-rw-r--r--qtruby/rubylib/examples/ruboids/ruboids/info.rb12
-rwxr-xr-xqtruby/rubylib/examples/ruboids/ruboids/ruboids.rb29
-rw-r--r--qtruby/rubylib/examples/testcases/bugs.rb57
-rw-r--r--qtruby/rubylib/examples/testcases/error_reporting.rb85
-rw-r--r--qtruby/rubylib/examples/testcases/opoverloading.rb46
-rw-r--r--qtruby/rubylib/examples/textedit/textedit.rb150
-rw-r--r--qtruby/rubylib/qtruby/Makefile.am15
-rw-r--r--qtruby/rubylib/qtruby/Qt.cpp2967
-rw-r--r--qtruby/rubylib/qtruby/configure.in.in19
-rw-r--r--qtruby/rubylib/qtruby/extconf.rb5
-rw-r--r--qtruby/rubylib/qtruby/handlers.cpp1978
-rw-r--r--qtruby/rubylib/qtruby/lib/Makefile.am4
-rw-r--r--qtruby/rubylib/qtruby/lib/Qt.rb1
-rw-r--r--qtruby/rubylib/qtruby/lib/Qt/Makefile.am2
-rw-r--r--qtruby/rubylib/qtruby/lib/Qt/qtruby.rb1978
-rw-r--r--qtruby/rubylib/qtruby/marshall.h46
-rw-r--r--qtruby/rubylib/qtruby/qtruby.h55
-rw-r--r--qtruby/rubylib/qtruby/smokeruby.h321
-rwxr-xr-xqtruby/rubylib/tutorial/t1/t1.rb11
-rw-r--r--qtruby/rubylib/tutorial/t10/cannon.rb71
-rw-r--r--qtruby/rubylib/tutorial/t10/lcdrange.rb35
-rwxr-xr-xqtruby/rubylib/tutorial/t10/t10.rb57
-rw-r--r--qtruby/rubylib/tutorial/t11/cannon.rb137
-rw-r--r--qtruby/rubylib/tutorial/t11/lcdrange.rb35
-rwxr-xr-xqtruby/rubylib/tutorial/t11/t11.rb67
-rw-r--r--qtruby/rubylib/tutorial/t12/cannon.rb173
-rw-r--r--qtruby/rubylib/tutorial/t12/lcdrange.rb47
-rwxr-xr-xqtruby/rubylib/tutorial/t12/t12.rb68
-rw-r--r--qtruby/rubylib/tutorial/t13/cannon.rb219
-rw-r--r--qtruby/rubylib/tutorial/t13/gamebrd.rb112
-rw-r--r--qtruby/rubylib/tutorial/t13/lcdrange.rb55
-rwxr-xr-xqtruby/rubylib/tutorial/t13/t13.rb14
-rw-r--r--qtruby/rubylib/tutorial/t14/cannon.rb279
-rw-r--r--qtruby/rubylib/tutorial/t14/gamebrd.rb121
-rw-r--r--qtruby/rubylib/tutorial/t14/lcdrange.rb55
-rwxr-xr-xqtruby/rubylib/tutorial/t14/t14.rb14
-rwxr-xr-xqtruby/rubylib/tutorial/t2/t2.rb17
-rwxr-xr-xqtruby/rubylib/tutorial/t3/t3.rb20
-rwxr-xr-xqtruby/rubylib/tutorial/t4/t4.rb27
-rwxr-xr-xqtruby/rubylib/tutorial/t5/t5.rb31
-rwxr-xr-xqtruby/rubylib/tutorial/t6/t6.rb45
-rw-r--r--qtruby/rubylib/tutorial/t7/lcdrange.rb25
-rwxr-xr-xqtruby/rubylib/tutorial/t7/t7.rb37
-rw-r--r--qtruby/rubylib/tutorial/t8/cannon.rb38
-rw-r--r--qtruby/rubylib/tutorial/t8/lcdrange.rb35
-rwxr-xr-xqtruby/rubylib/tutorial/t8/t8.rb44
-rw-r--r--qtruby/rubylib/tutorial/t9/cannon.rb43
-rw-r--r--qtruby/rubylib/tutorial/t9/lcdrange.rb36
-rwxr-xr-xqtruby/rubylib/tutorial/t9/t9.rb44
197 files changed, 27359 insertions, 0 deletions
diff --git a/qtruby/AUTHORS b/qtruby/AUTHORS
new file mode 100644
index 00000000..3b98da28
--- /dev/null
+++ b/qtruby/AUTHORS
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * (C) 2003-2004 Richard Dale All rights reserved. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+Chief Wreck On The Highway
+ Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+Bug fixes, enhancements, sample code
+ Alex Kellett
+
+Other contributions (from the ChangeLog), bug reports, fixes etc:
+ Alex Zepeda
+ Mikhail Yakshin
+ Imobach Sosa
+ Marek Janukowicz
+ Jochen Immend�fer
+ Dominique Devriese
+ Han Holl
+ Thibauld Favre
+ Zack Rusin
+ Jim Menard (RuBoids)
+ Ian Monroe
+ Raph Bauduin
+ Stephan Oehlert
+ David Crosby
+ Dave M
+ Caleb Tennis
+ Blackshack
+ Armin Joellenbeck
+ Dmitry Morozhnikor
+ Michael Doppler
+ Daniel Morris
+ Ryutaro Amano
+
+QtRuby is a ruby version of the PerlQt/Smoke project, written by:
+ Ashley Winters
+ Germain Garand
+ David Faure
+
+Equipment
+ 800 Mhz iBook with Yellow Dog 3.0, Macally Micro 3 button mouse
+
+Books
+ 'Programming with Qt' by Mathias Kalle Dalheimer
+ 'Programming Ruby' by David Thomas and Andrew Hunt
+ 'The Ruby Way' by Hal Fulton
+ 'Ruby In a Nutshell' by Yukihiro Matsumoto
+ 'Advanced Perl Programming' by Sriram Srinivasan
diff --git a/qtruby/COPYING b/qtruby/COPYING
new file mode 100644
index 00000000..6ab293f6
--- /dev/null
+++ b/qtruby/COPYING
@@ -0,0 +1,297 @@
+Trademarks
+----------
+
+"[QtRuby": "[Qt]" name usage by permission of Trolltech AS, owner of the
+Qt(TM) trademark
+
+
+License
+-------
+
+
+NOTE! The GPL below is copyrighted by the Free Software Foundation, but
+the instance of code that it refers to (the kde programs) are copyrighted
+by the authors who actually wrote it.
+
+---------------------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/qtruby/ChangeLog b/qtruby/ChangeLog
new file mode 100644
index 00000000..89e65292
--- /dev/null
+++ b/qtruby/ChangeLog
@@ -0,0 +1,1640 @@
+2007-02-19 Richard Dale <rdale@foton.es>
+
+ * Fixed a bug where the sort method of Qt::ListView and Qt::ListViewItem
+ was no longer working, as the classes are 'Enumerable' and ruby was
+ calling the ruby sort method instead. Thanks to kelko for reporting it
+ on #kde-ruby.
+
+2006-12-05 Richard Dale <rdale@foton.es>
+
+ * Backported some improvements to Qt::Variants from Qt4 QtRuby
+ * When marhalling QMap types with QVariant values, if the Ruby value isn't
+ a Qt::Variant then one is created
+ * Qt::Variants can now be constructed with Hash's of String/Qt::Variant
+ pairs, and from Arrays of Qt::Variants
+ * When marshalling QValueList<QVariant> types from Ruby to C++, if any elements
+ aren't Ruby Qt::Variants, they are automatically converted. Hence, the
+ following will work:
+
+ v = Qt::Variant.new([1, 2, 3])
+
+ The Qt::Variant v will contain a list of 3 QVariants with typeName 'int'
+ * Change all instances of strcmp() to qstrcmp()
+
+2006-11-20 Richard Dale <rdale@foton.es>
+
+ * Made Qt::ListView, Qt::ListViewItem, Qt::BoxLayout, Qt::HBoxLayout,
+ Qt::VBoxLayout and Qt::GridLayout Enumerable with implementations
+ of each() so they don't need to use the Qt External iterators like
+ Qt::LayoutIterator anymore. For instance:
+
+ lv = Qt::ListView.new do
+ ["one", "two", "three", "four"].each do |label|
+ Qt::ListViewItem.new(self, label, "zzz")
+ end
+ end
+
+ lv.each do |item|
+ p item.inspect
+ pp item.inspect
+ end
+
+ * Add inspect() and pretty_print() methods to Qt::ListViewItem so that
+ they show the text of their columns
+
+2006-09-19 Richard Dale <rdale@foton.es>
+
+ * Upped the QtRuby version to 1.0.13 for the KDE 3.5.5 release
+
+ * Fixed a crash when a slot was inherited by a subclass, and the
+ subclass had no slots or signals of its own
+
+2006-09-17 Richard Dale <rdale@foton.es>
+
+ * Fixed bug reported by Caleb Tennis where temporary QString const arguments
+ were only being deleting after marshalling if they weren't const types.
+
+2006-09-14 Richard Dale <rdale@foton.es>
+
+ * Added a new variant of connect, which takes a SIGNAL as an argument, along with
+ a block. For example:
+
+ quit.connect(SIGNAL(:clicked)) { puts 'quit pressed' }
+
+ The block is called in the context of where the connect call was made, and 'self'
+ needn't be a Qt::Object. It is similar to the signal_connect() method in
+ ruby-gnome. This was suggested by rickdangerous on the #qtruby irc channel.
+
+2006-09-13 Richard Dale <rdale@foton.es>
+
+ * Blocks can now be used as slots in Qt::Object.connect() calls. There are two
+ versions, a singleton method and an instance method.
+
+ * Here is an example of the class method connect() call with a block as a target:
+
+ app = Qt::Application.new(ARGV)
+ quit = Qt::PushButton.new('Quit')
+ Qt::Object.connect(quit, SIGNAL('clicked()'), app) { puts 'quit clicked' }
+
+ The block is executed in the context of the target instance, 'app' in this
+ case.
+
+ * And the instance method form:
+
+ class MyButton < Qt::Button
+ def initialize(text)
+ super(text)
+ connect(self, SIGNAL('clicked()')) { puts 'button clicked' }
+ end
+ ...
+
+ The block is executed in the context of self - the instance making the
+ connect() call.
+
+ * The Rails version of the Ruby 1.9 method Object#instance_exec was used
+ to invoke the block. Thanks to kelko on the #kde-ruby channel for the
+ idea and the code, and #rickdangerous for further discussion.
+
+2006-08-29 Richard Dale <rdale@foton.es>
+
+ * Backported some memory leak fixes from Qt4 QtRuby
+
+2006-08-10 Richard Dale <rdale@foton.es>
+
+ * The Ruby VALUE to 'uchar *' marshaller wasn't working correctly if the
+ Ruby string contained nulls. Fixed by Dirk Mueller (thanks) and also
+ applied for 'char *' types.
+
+2006-07-12 Richard Dale <rdale@foton.es>
+
+ * The Ruby String to 'char *' and String to 'unsigned char *' were using
+ the pointer within the Ruby String directly which meant they were
+ deleted when the Ruby String was gc'd. So they are copied with
+ strdup () instead.
+
+2006-06-05 Richard Dale <rdale@foton.es>
+
+ * The metaObject methods for slots and signals are no longer added when
+ a Qt::Object is constructed, but when slots or signals are added to
+ a class. This means that signals as well as slots can be added to an
+ existing instance.
+
+2006-06-04 Richard Dale <rdale@foton.es>
+
+ * For Qt::QObject classes which are immediate subclasses of Qt::Base,
+ don't add C metaObject() and qt_invoke() methods as they aren't
+ needed. This means that a QMetaObject is no longer constructed for
+ these classes, and the one that the corresponding C++ class has is
+ returned instead.
+
+2006-05-20 Richard Dale <rdale@foton.es>
+
+ * Fix regression for dynamic class creation via QMetaObject info causing
+ a crash.
+ * A list of properties is now returned via Qt::MetaObject.propertyNames
+ for a Qt::Object with properties for the inspect and pretty_print
+ methods.
+
+2006-05-15 Richard Dale <rdale@foton.es>
+
+ * Removed the customized version of Kernel.exec, Kernel.open etc
+ as they aren't needed anymore.
+
+2006-05-14 Richard Dale <rdale@foton.es>
+
+ * When an unknown C++ class is found, a corresponding Ruby class is now
+ created. For instance, if a KPresenter KPart is loaded, a
+ KDE::PresenterDoc class is created.
+ * It is now possible to set and get properties without needing to use
+ Qt::Object.property() and Qt::Object.setProperty(). For instance:
+
+ factory = KDE::LibLoader.self().factory("libkpresenterpart")
+ @kpresenter = factory.create(self)
+ p @kpresenter.presentationDuration
+ @kpresenter.presentationDuration = true
+
+ * A Qt::Variant.to_ruby method has been added which returns a Ruby value
+ corresponding to the current value of a Qt::Variant
+ * A boolean Qt::Variant can now be constructed with a Qt::Variant.new(true)
+ call, and a dummy second arg (as for C++) is no longer needed.
+
+2006-05-07 Richard Dale <rdale@foton.es>
+
+ * An an type of Q_UINT16 wasn't working with QtRuby. Fixes problem
+ reported by maelclerambault.
+
+2006-05-03 Richard Dale <rdale@foton.es>
+
+ * The qt_emit() and qt_invoke() methods are overriden by the QtRuby
+ runtime. When they are called the runtime looks for a Ruby slot or
+ signal matching the call, and invokes it if found. If a Ruby version
+ wasn't found for a signal however, the qt_invoke() method was being
+ called in the Smoke library instead of qt_emit(). This occasionally
+ caused a crash in code using KDE::HTMLPart.
+
+2006-04-17 Richard Dale <rdale@foton.es>
+
+ * Made :foobar a synonym for 'foobar()' for slots and signals
+ * Added some calls for Qt::Event.type methods to force them
+ to go via method_missing()
+
+2006-03-29 Richard Dale <rdale@foton.es>
+
+ * Don't special case open() in virtual method callbacks, because all
+ the Qt classes with open methods now have explicit open() method
+ calls. So it isn't possible that Kernel.open() will be called
+ wrongly anymore.
+
+2006-03-29 Richard Dale <rdale@foton.es>
+
+ * Added a KDE::KonsolePart class for when a konsolePart KPart is
+ dynamically loaded.
+
+2006-03-21 Richard Dale <rdale@foton.es>
+
+ * Added various explicit calls to method_missing() for methods which
+ are defined in Kernel and Object, such as 'exec', 'select', 'format'
+ etc. Otherwise, the corresponding methods in the Smoke library were
+ not being invoked correctly.
+ * Removed a virtual destructor compile warning
+ * Removed obsolete qtruby-only.patch and kdevelop project file
+
+2006-03-14 Richard Dale <rdale@foton.es>
+
+ * Fixed bugs in const lists marshallers, where the items in the ruby
+ Array were wrongly being updated after a method call
+
+2006-02-09 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The Kernel#select method was being redefined as it clashed with
+ Qt::SqlCursor#select and Qt::SqlSelectCursor#select methods. This
+ caused a problem when QtRuby was used with Rails ActiveRecord which
+ also has a select method. So the methods are now defined in the Sql
+ classes, and use method_missing() to explictly invoke the methods in
+ the Smoke library. Fixes problem reported by Imo Sosa.
+
+2006-01-18 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Improved the debug logging of virtual method callbacks so that the
+ arg types are shown too
+
+2005-12-16 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The logger_backend() function has been removed and replaced with
+ qWarning() calls. This was because of problems with getting the
+ logger_backend() code to work on Windows.
+
+2005-12-16 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Improved the code to call a C++ slot via qt_invoke() when a ruby slot hasn't
+ been defined. It now invokes the method in the Smoke lib directly, rather
+ than going via method_missing().
+
+2005-12-08 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The ruby display() method was clashing with a display() method in some
+ QtRuby classes, and so it was aliased to _display(). However, this caused
+ problems with the ruby RMagick extension. The display methods are now
+ special cased in Qt::LCDNumber, Qt::WhatsThis and Qt::TimeEdit. Fixes
+ problem reported by David Corbin.
+ * The slots and signals methods are now module methods of Qt::Base,
+ rather than defined as ordinary methods in class Module, reducing name
+ space pollution. Thanks to Esteban Manchado for pointing this out.
+
+2005-12-06 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * QtRuby didn't work with versions of ruby > 1.8.3, as it didn't call
+ initialize methods correctly. It used the rb_respond_to() method
+ to check it a newly created qt instance responded to :initialize.
+ However, in newer versions of ruby rb_responds_to() ignores
+ private methods such as initialize(). The solution was to just remove
+ the test, as it was redundant anyway.
+ * Fixes problem reported by Hans Fugel and Caleb Tennis.
+
+2005-11-21 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * When dispose() was used to delete a ruby instance, the mapping between
+ the C++ ptr and corresponding ruby instance was not being removed, and
+ this caused a crash. Fixes problem reported by Christopher Chan-Nui.
+
+2005-11-04 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * 'signed int&' types were not being matched or marshalled correctly
+
+2005-11-02 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * A Qt::Canvas owned by a Qt::CanvasItem is marked as in use
+ and not needing garbage collection
+
+2005-10-21 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Argument types of 'unsigned short int' were not working. Fixes
+ problem reported by Ian Monroe
+
+2005-10-05 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * More fixes from the Qt4 version
+ * The Qt::ByteArray class is now a normal Smoke class,
+ rather than a special case, as it's easier to make a
+ Qt::ByteArray look like a ruby String, than the other way
+ round.
+ * The overloaded method resolution for enum arg types has been
+ improved
+ * Added missing relational operators to Qt::Integer
+
+
+2005-09-26 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added some fixes from the Qt4 version of QtRuby
+ * There was a clash between operator methods in Kernel
+ for '>', '>=', '<' and '<=' and the ones in the Smoke lib.
+ * Fixed a Qt::ByteArray marshalling problem
+
+2005-09-12 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed various problems with the rbuic code generation for database
+ .ui forms reported by Daniel Morris
+
+2005-09-11 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed problem with Qt::SqlCursor.select() reported by Daniel Morris
+
+2005-09-02 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added a Qt::Char.to_s method for converting a Qt::Char to a ruby
+ string
+
+2005-08-09 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Caleb Tennis wrote:
+ One nice feature would be to allow Qt::Object::inherits() to use the QtRuby
+ naming scheme for valid lookups. For example, right now:
+
+ irb(main):001:0> w = Qt::Widget.new(nil)
+ irb(main):002:0> w.inherits("Qt::Widget")
+ => true
+ irb(main):003:0> w.inherits("Qt::Object")
+ => false
+ irb(main):004:0> w.inherits("QWidget")
+ => true
+ irb(main):005:0> w.inherits("QObject")
+ => true
+
+ * Inherits now works for "QObject", and for "Qt::Object" as well.
+
+2005-08-04 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added a file called 'COPYING' to the qtruby project, with a note that
+ the 'Qt' trademark in the QtRuby name is used with Trolltech's permission,
+ followed by the text of the GPL v2 license.
+
+2005-07-30 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Qt::version and Qt::ruby_version are now module methods
+
+2005-07-15 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Qt::Socket started working correctly when I and regenerated and rebuilt
+ my Smoke library. Before then it was calling the wrong version of
+ QSocket::at() for some reason, and wasn't discarding bytes that had
+ already been read.
+ * Removed comment from the client.rb example about Qt::Socket.canReadLine
+ always returning true now it works.
+
+2005-07-14 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added example programs for client/server programming with Qt::Socket
+ and associated classes. client.rb illustrates current bugs in QtRuby
+ * Qt::Socket.canReadLine() always returns true
+ * Qt::readLine() seg faults when called a second time
+ * A memory leak and seg faulting problems like the above were reported
+ by Caleb Tennis
+
+2005-07-09 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * When a Qt method returned a QString value type, such as:
+ QString QSocket::readLine()
+ A temporary QString was being created that wasn't deleted and caused a
+ memory leak. Fixes problem reported by Caleb Tennis.
+
+2005-06-28 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Improved display of Qt::Enums in the KDevelop debugger. With a p
+ command it just looks like a constant, but a pretty print pp command
+ shows the type of the underlying C++ enum:
+
+ (rdb:1) p AlignTop
+ 16
+
+ (rdb:1) pp AlignTop
+ #<Qt::Enum:0x1825db68 @type=Qt::AlignmentFlags, @value=16>
+
+2005-06-04 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Upped the version to 1.0.10
+
+2005-06-04 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The Object.id method was clashing with the one in Qt::WidgetStack.
+ Both methods now work correctly. Fixes problem reported by Dave M.
+
+2005-05-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The rbuic '-subimpl' option now works correctly
+
+2005-05-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The initialize methods in code generated by the rbuic tool, now have
+ named parameters with default values, rather than '*k'
+
+2005-05-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed bug where the rbuic tool was generating incorrect code
+ for an array of strings used as a combo box value
+
+2005-05-28 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added support for the QScintilla text editing widget, including an optional
+ '--enable-qscintilla=yes' configure option. The QScintilla classes are included in a
+ Qext:: namespace. Thanks to Blackshack for the idea and configure code.
+ * The KDE namespace modules are only created if the Korundum extension is used.
+ Otherwise the Object namespace was being polluted with unused constants.
+ * Some enums in the QScintilla headers had a spurious comma after
+ the last enum value, and kalyptus was failing with a parse error.
+ The comma is now ignored.
+
+2005-05-25 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * '!=' operator methods in the Smoke library were being shown via ruby introspection when they
+ can't actually be written in ruby, and are derived from the corresponding '==' operator method.
+ * '==' operator methods can now be called.
+
+2005-05-22 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed bug in Smoke code generation where spaces were not being removed from operator
+ methods such as 'operator *'
+ * Operator methods are now displayed correctly via ruby introspection
+
+2005-05-21 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Improved the format of enums displayed by rbqtapi and rbkdeapi
+
+2005-05-20 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Removed unused Qt::Internal functions
+ * Added KNS:: to the namespaces expected by the rbkdeapi tool
+ * Introspection via Object#methods, public_methods, protected_methods and singleton_methods
+ or Module#constants, instance_methods, protected_instance_methods and public_instance_methods
+ now all include methods from the Smoke runtime. This fixes part of the request in bug 105772, but
+ not enabling 'respond_to?' to be used with Smoke methods.
+
+2005-05-16 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The Kernel.format() method was clashing with the Qt::MimeSource.format() method.
+ The correct method is now called according to the type of the first argument. Fixes
+ problem reported by Armin Joellenbeck
+
+2005-04-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Removed superfluous "require 'pp'" statement
+
+2005-04-25 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Upped the version to 1.0.9 for the RubyForge release
+
+2005-04-09 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed regressions in the rbqtapi and rbkdeapi utilities caused by the Qt::Internal namespace
+ tidy up
+ * Qt::version and Qt::ruby_version had wrongly been moved to the Qt::Internal module
+
+2005-04-03 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Upped the version to 1.0.8 for the RubyForge release
+
+2005-03-30 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * An 'include Qt' statement in qtruby.rb where a couple of methods were being added to
+ class Module was causing all the Qt methods to be added to Module. Oops, this a really
+ serious bug. Various methods in qtruby.rb are now module methods in the Qt::Internal
+ module. Big thanks to Eric Veensta and Samir Patel for pointing out this can of worms.
+
+ * It also fixes a problem reported by David Crosby where a "require 'time'" statement was
+ incompatible with a "require 'Qt'" statement. As the cause was unknown, a hacky workround
+ had to be added, which is no longer needed.
+
+2005-03-24 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * When a subclass of QObject is instantiated in the C++ world, and the exact class doesn't
+ exist in ruby, then scan up the inheritance heirarchy via QObject::metaObject() until a
+ class is found which does have a ruby equivalent. Fixes problem reported by Dmitry Morozhnikor
+ where a KViewPart was being returned as a Qt::Object, rather than a KParts::ReadOnlyPart.
+ * The internal method 'cast_object_to()' now takes a class literal as a second parameter,
+ rather than the class name as a string
+
+2005-03-21 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Moved Qt.rb from qtruby/lib/Qt to qtruby/lib. Fixes problem building qtruby on Mac OS X
+ with extconf.rb reported by Michael Doppler
+ * Rename 'README.build' as INSTALL
+
+2005-02-21 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Upped the version to 1.0.7 for the KDE 3.4 release
+ * Removed the khtml:: namespace as it wasn't being used
+
+2005-02-07 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added a KNS:: namespace for the KNewStuff library
+
+2005-02-06 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The KDE::Win::WindowInfo nested class is included in the Korundum runtime
+
+2005-01-27 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Made some changes to get code generated by the rbkconfig_compiler
+ to work. When an argument is a non-const reference to a primitive
+ type, or a QString or QStringList, then don't delete it after the
+ method call. This is because a class like KConfigSkeleton takes
+ references, and then 'squirrels them away' - before the references
+ were just pointing to junk on the stack.
+ * The method 'isImmutable' is added to KDE::ConfigSkeletonItems
+
+2005-01-26 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * If a ruby Array is passed as an argument to an overloaded method, give
+ priority to QStringList args.
+
+2005-01-21 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * rbuic was giving widgets names containing a '@' to match the ruby instance variable
+ name. However, this doesn't work with KDE::ConfigDialog which expects the names to
+ match the ones generated in a KDE::ConfigSkeleton by rbkconfig_compiler so '@' is no
+ longer added.
+
+2005-01-20 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed bug reported by Ian Monroe where the KIO.copy() method wasn't being found in
+ the Smoke runtime. Modules methods are now trapped with method_missing and
+ despatched to call Smoke methods correctly
+ * Added support for the KDE::ConfigSkeleton and subclasses. Constructors for nested
+ classes can now be called correctly
+
+ CCMAIL: ian.monroe@gmail.com
+
+2005-01-16 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added a Qt::Integer.coerce method so that Qt::Integers and Qt::Enums can be
+ combined in arithmetic expressions with ruby Integers.
+
+2005-01-04 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Upped the version to 1.0.6 for the KDE 3.4 beta 1 release
+
+2005-01-02 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The Qt::Object pretty_print method now shows the class name of enum properties
+
+2004-12-30 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed an interesting bug reported by Stephan Oehlert. Kernel has a method called
+ open() which takes a String as the first argument. But when a call is made to an open()
+ method in the Qt classes, it messes up the method_missing() logic to divert it to the
+ Smoke library. Instead it attempts to call the Kernel method with the wrong arg types.
+
+ * The problem is fixed by calling the appropriate method based on the
+ type of the first arg. However, it is no longer possible to override virtual methods
+ called 'open'.
+
+ CCMAIL: stephan.oehlert@gmx.net
+
+2004-12-28 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added a parent attribute to the Qt::Object pretty_print() method
+ * Removed all the properties from the Qt::Object inspect() method except name,
+ x, y, width, height (the last four for for Qt::Widgets only). This speeds up fetching
+ the details of Qt::Objects that have more than just a handful of children.
+ The full details can still be fetched with a pretty_print() call via a debugger 'pp'
+ command.
+
+2004-12-21 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The qtruby runtime needs to be able to run the code for an initialize() method up
+ to the point where the C++ instance has been constructed and wrapped, and then
+ jump out. It then re-runs initialize() with the wrapped instance. Before a callcc() call
+ had been used for the jumping which worked fine. However, it made the frame stack
+ look strange when debugging code with the KDevelop debugger. The fix is to use
+ catch and throw instead, as they leave the stack in a more normal looking state.
+
+2004-12-20 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added a work round for a bug caused by an incompatibility between QtRuby
+ the 'require time' statement, reported by David Crosby
+
+ CCMAIL: dcrosby42@gmail.com
+
+2004-12-18 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added a 'receivers' property to the Qt::Object inspector. This allows the active signal
+ connections for a Qt::Object instance to be viewed in the KDevelop debugger as a
+ Hash. The hash keys are the signal names, and the hash values are arrays of the target
+ signals/slots as Qt::Connection instances.
+
+2004-12-17 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added 'metaObject' as an expandable property for Qt::Objects. This allows the
+ Qt::MetaClass class heirarchy to be browsed, and signals/slots declarations inspected.
+
+2004-12-17 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed bug in lower case/underscore method naming to camel case conversion
+
+2004-12-15 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added an attribute of 'children' to the Qt::Object inspect method, which is an array
+ of the Qt::Object's children
+ * The QObjects in a QObjectList were not being created with the exact ruby class
+ if they hadn't been allocated from within the ruby code, and just left as Qt::Objects
+
+2004-12-14 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Qt::Object properities of type enum are shown by name in the KDevelop debugger,
+ and not as numeric literals
+
+2004-12-14 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Changed the format of the Qt::Color inspect string to #<Qt::Color:0x0 #ffffff>
+ * Added some more attributes to the Qt::Font inspector
+ * Added a Qt::Cursor inspector
+
+2004-12-12 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed a bug where the debugger was calling an inspect method on an instance
+ which wasn't fully initialized yet, and not of type T_DATA.
+
+2004-12-10 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added inspect() and pretty_print() methods for Qt::SizePolicy
+ * Greatly improved the Qt::Object Qt property based inspect() and pretty_print()
+ methods. Property types such as Qt::Point, Qt::Font and Qt::Rect can be
+ viewed as expandable items in the KDevelop debugger variable tree.
+
+2004-12-09 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * More inspect() and pretty_print() methods for common classes to improve debugging -
+ Qt::Color, Qt::Font, Qt::Point, Qt::Rect, Qt::Size, Qt::Date, Qt::DateTime and Qt::Time
+
+2004-12-08 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added inspect() and pretty_print() methods for Qt::Objects that get the QObject properties and
+ show them as 'name=value' pairs. This means the KDevelop debugger can make Qt::Object
+ variables expandable and show their properties.
+
+2004-11-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Upped the QtRuby version to 1.0.5 for the KDE 3.3.2 release
+
+2004-10-30 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * qError(), qWarning() and qFatal() are now Object instance methods, rather than Qt module
+ methods. This means they don't need to be referenced with an ugly 'Qt.' module scope anymore.
+
+2004-10-21 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * If a class method was called before super, it was wrongly throwing an exception
+ as an error. For instance, this call to i18n():
+
+ def initialize()
+ super(TreeList, i18n("My App Preferences"),
+ Help|Default|Ok|Apply|Cancel, Ok)
+ ...
+
+
+2004-10-16 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Until super has been called in an initialize() method, Qt methods can't be called on
+ it. An exception is now thrown 'Instance not initialized', instead of it causing a seg fault.
+ * For instance:
+
+ class MyWidget < Qt::ComboBox
+ def initialize
+ # Must call super first
+ insertItem('abc')
+ super
+ end
+ end
+
+ * Fixes problem reported by Han Holl
+ CCMAIL: kde-bindings@kde.org
+
+2004-10-16 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Upped the version to 1.0.4 for the RubyForge release
+ * Added some names to AUTHORS from the ChangeLog
+
+2004-10-14 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * If the smokeruby_mark() function was called for an instance of a QObject, it should
+ mark all the instances below it in the QObject tree, as not needing garbage collection.
+ However, if a node in the tree didn't have a mapping onto a ruby instance the marking
+ process stopped there, even though the grandchildren and their descendants might
+ have a valid mapping onto ruby instances.
+ * The solution is to always traverse the entire tree. Fixes problem reported by Han Holl.
+
+ CCMAIL: kde-bindings@kde.org
+
+2004-10-13 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * All the Qt::CanvasItems owned by a Qt::Canvas are marked with rb_gc_mark() to
+ prevent them being garbage collected
+ * The top level widgets are no longer disposed() on Qt::Application exit
+ * Fixed some bugs in the chart example.
+
+2004-10-13 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed arg matching to give priority to 'int' or 'signed' when passed a ruby Integer, or
+ 'double' when passed a ruby Float
+ * The chart example can now save and load chart files
+
+2004-10-13 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added greater than and less than operators to Qt::Enum, so that enums can be compared with
+ Integers
+ * Added the chart example for Qt Tutorial #2
+
+2004-10-12 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added Qt::Application.ARGV. It returns the original ruby ARGV array with Qt command line
+ options removed.
+
+2004-10-11 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added a global flag 'application_terminated'. Once this is set the QtRuby runtime will no longer
+ delete any C++ instances. This will hopefully fix crash on application exit problems reported
+ by Thibauld Favre.
+
+ CCMAIL: kde-bindings@kde.org
+
+2004-10-10 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The recent fix for checking invalid arg types, didn't work with nil passed as a value
+
+2004-10-10 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * A QRgb[] color table was being wrongly deleted after marshalling
+
+2004-10-10 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * If a ruby method overriding a virtual method returned a primitive type when an instance of a class
+ was expected, it caused a seg fault. A ruby exception is now thrown instead. Fixes problem reported by
+ Han Holl.
+
+ * For instance,
+ class ContainerGrid < Qt::Widget
+ def sizeHint
+ # next line should return a Qt::Size, not an integer
+ 100
+ end
+ end
+
+ Now gives the following error:
+
+ qsize.rb:12:in `method_missing': Invalid type, expecting QSize (ArgumentError)
+ from qsize.rb:12
+
+ CCMAIL: kde-bindings@kde.org
+
+2004-10-10 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The smokeruby_mark() function was only marking the immediate children of a
+ Qt::Object for not being garbage collected. It now marks all the Qt::Objects
+ in the object tree below it.
+
+2004-10-07 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added Qt Designer Tutorial 'Creating Dialogs' translated into QtRuby. It
+ shows how you can combine ruby code generated from .ui files with the rbuic
+ tool, with your own code.
+
+ * The .ui files and images are identical to the original C++ versions.
+
+ * It features a simple Makefile to run rbuic when you change the .ui files, and
+ regenerate the ruby sources.
+
+2004-10-06 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed rbuic '-embed' option which had been broken after adding DCOP suppot
+ to Korundum, after changes in the Qt::ByteArray class.
+ * Fixed QRgb* marshalling problem where the ruby value was overflowing a signed int.
+ The target for marshalling is now an array of unsigned ints.
+ * When a Qt::Application exits after returning for an Qt::Application.exec() call, the top
+ level widgets are deleted as well as the Qt::Application itself. This fixes a problem where
+ ruby does garbage collection in an arbitrary order after the ruby app has exited. It destroys
+ a ruby Hash of QMetaData info that the Qt::Application or Qt::MainWindow need to clean up.
+ * The layout of the ruby code generated by rbuic has been improved with better indenting.
+ * attr_reader attribute accessors have been added for the most important instance variables
+ in an rbuic generated class to make them more easily accessed from another class.
+
+2004-10-05 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Given a C++ instance and an approximate classname, the QtRuby runtime uses the
+ various Qt rtti mechanisms such as QObject::className() to improve the resolution
+ of the name. However, the numeric classId into the array of classnames in the Smoke
+ runtime was not being updated in line with the more accurate name.
+ * This caused problems with method argument matching which uses the numeric classId
+ rather than the ruby object's classname, and so QtRuby wrongly assumed that a an
+ instance of a Qt::Widget was a Qt::Object.
+ * Fixes problem reported by Han Holl
+
+ CCMAIL: kde-bindings@kde.org
+
+2004-10-05 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed a couple of errors in the rbuic generated code found as a result of
+ the recently improved stricter arg type matching.
+
+2004-10-04 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * When a ruby app exits, rb_gc_call_finalizer_at_exit() is called and all the ruby
+ instances are garbage collected. The problem is that this is done in an arbitrary
+ order, and Qt::Application was occasionally crashing in its destructor because
+ QMetaObject info it still needed was being deleted before then.
+
+ * Fixes problem reported by Thibauld Favre
+
+ CCMAIL: <tfavre@mandrakesoft.com>
+
+2004-10-04 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * When a QMetaData object was contructed the class name was a pointer from a ruby
+ string, and was being corrupted when the string was freed. The string is now copied.
+
+2004-10-03 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Han Holl's report about a when you pass an incorrect arg type to a QtRuby
+ method, it caused a crash has opened a 'can of worms'. This was because there
+ was no arg type checking if there was only one candidate method in the
+ Smoke runtime. Now that arg type checking is applied to all QtRuby method calls, not
+ not just those that after lookup in Smoke map onto a single method, the overloaded
+ method resolution via the arg types has had to be greatly improved. This has
+ been done, and so the arg type matching is now extremely fussy.
+
+ CCMAIL: kde-bindings@kde.org
+
+2004-10-03 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * An optimization in the overloaded method resolution matching causes a crash;
+ instead of throwing a ruby exception when a programming error is made.
+ If there is only one method found in the Smoke runtime, it assumes that it must
+ be the right one and just takes that.
+
+ * For example:
+
+ lay = Qt::HBoxLayout.new(self)
+ ed = Qt::LineEdit.new('blah',self)
+ # The next line should be: lay.addWidget(ed)
+ lay.addLayout(ed)
+
+ * Fixes problem reported by Han Holl
+
+ CCMAIL: kde-bindings@kde.org
+
+2004-10-03 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * A common programming error is to accidently leave off the 'new' method call when
+ creating an instance. The QtRuby runtime wasn't correctly trapping an attempt to
+ call an instance method on a class object, and was seg faulting rather than
+ throwing an exception.
+
+ * For example:
+
+ # The next line should be: lay = Qt::HBoxLayout.new(self)
+ lay = Qt::HBoxLayout
+ ed = Qt::LineEdit.new('blah',self)
+ lay.addWidget(ed)
+
+ * Fixes problem reported by Han Holl
+
+ CCMAIL: kde-bindings@kde.org
+
+2004-10-03 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Upped version to 1.0.3 for the KDE 3.3.1 release
+
+2004-10-02 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added Ruby Array to QPair<int,int>& marshaller
+
+2004-09-30 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The resolve_classname() function in handlers.cpp uses the various Qt rtti mechanisms to
+ get a more accurate classname to instantiate as a ruby instance. It has now been extended
+ with a callback to the Korundum library to do the same for KDE classes.
+
+ CCMAIL: zack@kde.org
+
+2004-09-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added Jim Menard's ruboids as an OpenGL/Qt::GL* Widgets example
+ * Improved instructions and exconf.rb for building the gui extension from Michal 'hramrach' Suchanek
+
+2004-09-13 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Upped the version to 1.0.2 for Rubyforge release
+
+2004-09-12 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added a 'qui' extension for reading in .ui Qt Designer files at runtime
+ * For example:
+
+ require 'Qt'
+ require 'qui'
+
+ a = Qt::Application.new(ARGV)
+ if ARGV.length == 0
+ exit
+ end
+
+ if ARGV.length == 2
+ QUI::WidgetFactory.loadImages( ARGV[ 0 ] )
+ w = QUI::WidgetFactory.create( ARGV[ 1 ] )
+ if w.nil?
+ exit
+ end
+ w.show()
+ a.connect( a, SIGNAL('lastWindowClosed()'), a, SLOT('quit()') )
+ a.exec()
+ end
+
+
+2004-09-07 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Upped the version to 1.0.1 for the current Rubyforge release
+
+2004-09-05 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added Kate:: and KTextEdit:: namespaces for writing Kate plugins
+
+2004-09-03 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Some newer changes from the uic were added to the rbuic tool.
+
+2004-09-03 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Brought the rbuic code to uncompress zip files in line with the current uic code
+ * Added a qmake project file for building the rbuic tool on Mac OS X, and some
+ notes on how to build QtRuby on a Mac.
+
+2004-08-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added Kontact module to provide a namespace for the kontact plugin api
+
+2004-08-25 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Underscore naming for can be used for method names instead of camel case if
+ preferred. Any underscores in method names are removed, and the following
+ character is capitalised. For example, either of these two forms can be used
+ to call the same method:
+
+ create_standard_status_bar_action()
+
+ createStandardStatusBarAction()
+
+2004-08-23 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * A 'thing?' ruby method can now be used as a synonym for either isThing() or hasThing() in the Smoke runtime
+
+2004-08-04 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Upped the QtRuby version to 1.0.0 - it must work now then..
+
+2004-08-02 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added 'long long' and 'unsigned long long' marshallers
+
+2004-07-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The smokeruby_mark() gc marking f'n now marks the QTableItems owned
+ by a QTable so they don't get garbage collected, even if there are no
+ remaining references in the user code.
+
+2004-07-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added a template based method for QValueList marshallers, and several
+ QValueList types.
+
+2004-07-28 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Removed any marshaller types that weren't in the Smoke runtime from the
+ type name to marshaller function lookup table.
+
+2004-07-28 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * If a class doesn't have a virtual destructor, then no mapping was being
+ kept from the C++ instance to the corresponding ruby value. If the class
+ had virtual method callbacks, this meant that the ruby instance couldn't
+ be found, and the callback couldn't be made.
+
+ * Hence, the Qt::ToolTip callback in examples/qt-examples/tooltip didn't
+ work, as that class doesn't have a virtual destructor.
+
+ * Added an 'isEnum()' function to use when matching args in overloaded
+ method resolution.
+
+ * QCString arg types are chosen in preference to QByteArray ones, matching
+ against ruby strings, when resolving an overloaded method call.
+
+ * Qt::Enums and Qt::Integers can be marshalled to uints, longs and ulongs as
+ well as ints.
+
+ * Added a '==' operator to Qt::Enums so they can be compared with ruby Integers
+
+2004-07-27 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Qt::Integer arithmetic and bit operations return Qt::Integers, rather
+ than ruby Integers so that ops can be nested as for Qt::Enums.
+
+2004-07-27 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The recently added Qt::Integer bit operators were returning a ruby Integer
+ type. When they were nested, the Integer didn't know how to convert the
+ Enum it was being or'd with to an Integer.
+
+ * The solution is to add bit operators to the Enum class which return Enums
+ rather than Integers.
+
+ * The following code didn't work:
+
+ def initialize(message)
+ super(nil, "passivedlg",
+ Qt::WStyle_Customize | Qt::WX11BypassWM | Qt::WStyle_StaysOnTop |
+ Qt::WStyle_Tool | Qt::WStyle_NoBorder)
+
+2004-07-27 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Replaced QString casts to 'const char *' with latin1() calls
+
+2004-07-27 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The Qt::Enum class was missing bit operations, so various bit methods
+ were added to Qt::Enum's superclass, Qt::Integer.
+
+ * This was causing this line from examples/uimodules/uidialogs.rb to fail:
+
+ dlg = KDE::DialogBase.new(parent, "sample_dialog", false, caption,
+ KDE::DialogBase::Ok | KDE::DialogBase::Cancel,
+ KDE::DialogBase::Ok, true )
+
+2004-07-27 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added error messages for invalid slot or signal declarations
+
+2004-07-27 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The standard ruby error message for missing constants and methods is
+ now used when they can't be found in the Smoke library. Removed Alex's
+ comment about the previous approach, now I agree this is the best way
+ to show errors.
+
+ CCMAIL: me@lypanov.ne
+
+2004-07-27 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added qDebug(), qFatal() and qWarning() module methods
+
+2004-07-26 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The parsing of types passed to slots, (or returned from dcop slots) didn't
+ work with template types containing commas such as 'QMap<QString,QString>'.
+ * Added 'QMap<QString,QString>&' and 'QMap<QString,QVariant>&' to the
+ handlers.cpp string to marshaller lookup table.
+
+2004-07-26 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added marshallers for QMap<QString,QString> and QMap<QString,QVariant> to and from ruby hashes
+
+2004-07-26 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The error messages for missing methods or missing constants now give the
+ name of the missing item.
+ * For example, this incorrect line:
+
+ color_group.setColor( ColorGroup::MyMissingConst, blue )
+
+ Gives this error:
+
+ splitter.rb:16:in `const_missing': unresolved constant
+ reference MyMissingConst (ArgumentError)
+
+ * Implements suggestion from Jeff on the kdebindings list
+
+ CCMAIL: kde-bindings@kde.org
+
+2004-07-19 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added Qt::Enum type. Before a C++ enum was being marshalled to a ruby
+ Integer, and the type name of the enum was lost. A Qt::Enum is a subclass
+ of Integer with an extra type name.
+ * This fixes a problem with overloaded method resolution where two methods differ
+ only be an enum type such as this:
+
+ # KPasswordEdit(EchoMode echoMode, QWidget *parent, const char *name);
+ # KPasswordEdit(EchoModes echoMode, QWidget *parent, const char *name);
+
+ pw2 = KDE::PasswordEdit.new(KDE::PasswordEdit::ThreeStars, page, "")
+
+2004-07-17 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * After a non-const string arg was passed to a method, the value of the QString
+ is copied into the ruby value. But it wasn't being correctly converted to the
+ correct string format according to $KCODE.
+ * QString to ruby string conversions in QStringLists were not localised either.
+
+2004-07-14 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Removed superfluous '(void *)' cast which was causing compilation
+ problems with gcc 3.4
+ * Fixes problem reported by Jochen Immend�fer on comp.lang.ruby
+ CCMAIL: kde-bindings@kde.org
+
+2004-07-11 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Qt eucJP and Shift-JIS codecs used to support ruby $KCODE values of 's'
+ for SJIS and 'e' for EUC
+
+2004-07-08 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added support for strings in QtRuby programs being written in UTF-8.
+ Use the '-Ku' command line option or '$KCODE=u' in the program.
+ * Removed recently added QChar marshalling as it wasn't very i18n friendly
+
+2004-07-07 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added QChar marshalling
+
+2004-07-06 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fix for passing C++ 'bool*' and 'bool&' argument types
+ There is a similar problem for bool arg types as with ints, and the mutable
+ Qt::Boolean class can be used like this:
+
+ # QFont getFont(bool * ok, const QFont&initial, QWidget* parent = 0);
+
+ ok = Qt::Boolean.new
+ font = Qt::FontDialog.getFont(ok, Qt::Font.new("Helvetica [Cronyx]", 10), self)
+ if !ok.nil?
+ # font is set to the font the user selected
+ else
+ # the user canceled the dialog
+ end
+
+ Use 'nil?' to test the value returned in the Boolean
+ * Signal and slot type signatures are 'normalized' and any unwanted white space
+ removed
+ * Fixed problem with QByteArray arg type matching in overloaded method resolution
+
+2004-07-04 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fix for passing C++ 'int*' and 'int&' argument types
+ Ruby passes numeric values by value, and so they can't be changed when passed to a
+ method. The Qt::Integer class provides a mutable numeric type which does get updated
+ when passed as an argument. For example, this C++ method 'findByFileContent()':
+
+ # static Ptr findByFileContent( const QString &fileName, int *accuracy=0 );
+
+ acc = Qt::Integer.new(0)
+ fc = KDE::MimeType.findByFileContent("mimetype.rb", acc)
+
+ It supports the arithmetic operators, and so expressions such as 'acc + 3'
+ will work.
+
+2004-07-02 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Replaced obsolete STR2CSTR() calls with StringValuePtr()
+
+2004-06-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The internal findAllMethods() method now returns nil rather than an empty array
+ if the given classid is greater than 'smoke->numClasses'. Otherwise, it wasn't
+ possible to distinguish between a class with no methods, or reaching the end of
+ the classes array.
+
+2004-06-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added QStrList marshalling
+
+2004-06-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Improved Garbage Collection, dispose() and isDisposed() methods
+ - When a ruby instance is garbage collected, the underlying C++ instance will only be
+ deleted if it isn't 'owned' by a parent object. Normally this will 'just work', but
+ there are occasions when you need to delete the C++ ahead of garbage collection, and
+ whether or not it has a parent. Use the dispose() and isDisposed() methods like
+ this:
+
+ item0.takeItem(item1)
+ item0.insertItem(item1)
+
+ item2.dispose
+ if item2.isDisposed
+ puts "item2 is disposed"
+ end
+
+ - Fixes problem reported by Hans Fugel
+
+2004-06-26 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The marshalling TypeHandler function pointers are now looked up in a
+ QAsciiDict, rather than a ruby Hash.
+ * Some unused functions removed
+ * QtRuby version upped to 0.9.8
+
+2004-06-09 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * New flags were added for Smoke methods - mf_internal and mf_copyctor.
+ This allows copy constructors which are only used internally by the ruby
+ runtime, to be excluded from the standard api.
+
+
+2004-05-12 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * When ARGV was passed to the Qt::Application constructor, it was being
+ altered, and the name of the ruby program added as a first entry. The
+ constructor now uses a copy of the array, and ARGV is left unchanged.
+
+2004-05-03 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added a '-kde' option to the rbuic tool to generate require 'Korundum'
+ instead of require 'Qt' statements, and use KDE widgets.
+
+2004-04-30 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Applied patch from Marek Janukowicz.
+ * The patch fixes some perlisms, that caused errors on loading a Ruby file
+ generated from .ui file for Qt::MainWindow subclass
+
+2004-04-20 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The rbuic now correctly names KDE widgets with a KDE:: prefix
+ * If the rbuic -x option is used, a KDE top level is generated if any
+ KDE widgets have been found.
+
+2004-04-17 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed bug in rbuic generated code for setResizeMode()
+
+2004-04-05 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Improved classname resolution for QListViewItem and QTableItem subclasses using rtti() calls
+
+2004-03-26 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Ruby slots and signals are now inherited correctly
+ * This causes problems with code generated by the rbuic utility
+ * Fixes bug 78273 reported by Imobach Sosa
+
+2004-03-10 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * When a mutable, non-const QString, int*, int&, bool* or bool& is passed
+ to a method, the corresponding ruby value is now updated after the
+ method call.
+ * Some f'ns are no longer static, so that the korundum extension can link
+ against them.
+
+2004-03-03 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The f'n new_qobject is no longer static, and can be called from korundum
+
+2004-03-01 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed bugs in QCString, QString and QByteArray marshalling.
+ - When a C++ method with a mutable, non-const QCString arg type
+ is called from ruby, the C++ arg value is copied back into the
+ corresponding ruby arg VALUE after the call.
+ - A pointer to a locally allocated QString was being returned,
+ giving memory corruption problems.
+ * The default debug level in qtruby.rb is DebugLevel::OFF, otherwise
+ very verbose error messages are produced.
+
+2004-01-28 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed bug where a QCString was being ranked equally with a QString,
+ when resolving ambiguous method overloading. Caused the KDE::URL
+ constructor to fail with a string arg.
+
+2003-11-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added DOM:: namespace for the DOM:: classes in the Smoke library.
+ * The scope operator in nested classnames is now '::' rather
+ than '__', so changed the qtruby runtime to expect that.
+
+2003-11-13 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added the KillerFilter event filtering example from chapter 16
+ of 'Programming with Qt'
+ * Improved classname resolution via the Qt rtti mechanisms in
+ QObject, QEvent and QCanvasItem. This fixed a problem in the
+ KillerFilter example when a QMouseEvent was passed to the ruby
+ event handler, it was being instantiated as a ruby Qt::Event,
+ rather than a Qt::MouseEvent.
+
+2003-11-11 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Improved nil argument matching, and nil can match any type now
+ not just classes. Translated the code from the Qt.pm in PerlQt,
+ after discussion on the kde-perl list.
+ * Fixed bug in rbuic where a C++ 'QString::null' was "" in ruby, and
+ should have been a nil.
+
+2003-11-08 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Finally fixed huge leak, causing the progress.rb example to grow by
+ 1 Mb a minute.
+ * Added a cache from ruby classname to Smoke class id
+ * Speeded up method selector look ups
+ * Put some C++ code inside blocks to ensure that the destructor clean
+ up code was called, when the current f'n longjmp's up the stack rather
+ than returns normally.
+ * QtRuby looking good, raised the version to 0.9.6 to celebrate
+
+2003-11-07 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed some memory leaks
+ * Ensured that any instance 'owned' by ruby, ie with the the allocated
+ flag set to true, is always added to the pointer_map.
+ Otherwise, the same C++ instance can be wrapped twice and will be deleted
+ twice.
+
+2003-11-03 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * When marshalling a const ref type to a ruby VALUE, it is now copied
+ * Applied some fixes for construct_copy() from the PerlQt version of
+ handlers.cpp
+ * Fixed some minor bugs in the progress.rb Qt example
+
+2003-11-03 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added method selector caching for class methods and constructors,
+ although performance still 'sedate' compared with C++ or Perl.
+
+2003-10-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The smokeruby_mark() f'n now marks the QListViewItems in a QListView
+ * Fixed a QLayoutItem crash in smokeruby_free()
+
+2003-10-27 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The smokeruby_mark() f'n was completely wrong, as it is only called if
+ the current object is already marked. So marking the current object
+ doesn't make a lot of sense. Instead, if the instance is a kind of
+ QObject then its childeren are marked.
+ * The smokeruby_delete() object doesn't delete instances which have
+ parents of one sort or another.
+ * Made some fixes to the tutorial examples
+ * Removed equality '==' operator overloading as it only expects a single
+ arg in ruby, and not two.
+
+2003-10-22 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Changed some error messages in do_method_missing() to be 'debug only' for now.
+
+2003-10-22 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Got the checklists.rb example working after bug report from Mikhail Yakshin
+ - Corrected some coding errors in the example itself.
+ - The arg matching code in method_missing() has been improved and simplified.
+ - In the overloaded arg type resolution matching, an enum is type 'long'
+ - A class which matches exactly is a better match than a subclass.
+ Multiple matches are allowed as long as there is a 'best match'.
+ - Operator overloading now looks for methods of the form 'operator+=',
+ 'operator-=' etc in the Smoke runtime.
+
+2003-10-14 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed serious random crash problem
+ - qt_invoke() and qt_emit() were not calling super if a ruby signal or
+ slot hadn't been found, which stopped C++ signals from working.
+ - This prevented destroy() signals from invoking event filter list clean
+ up when a QObject was deleted, leaving deleted instances in the list.
+ - 'QUObject*' args are now marshalled as a ruby list with a single
+ entry of a VALUE wrapping the pointer.
+ * The ruby ALLOCA_N macro is no longer used as it is based on alloca(),
+ which doesn't seem a good idea. malloc(), calloc() and free() are used
+ instead
+
+2003-10-11 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added khtml:: namespace, although it isn't in the SmokeKDE runtime yet
+ * Improved method_missing error messages if a method can't be resolved
+
+2003-10-09 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added KIO:: and KParts:: namespaces for the new classes in libsmokekde
+
+2003-10-08 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Korundum KDE ruby extension
+ - made various changes so it can be linked against the QtRuby code
+
+2003-09-18 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Removed leading 'K' from class names of when adding to KDE:: namespace.
+ As per Germain Garand's suggestion on the kde-bindings list:
+
+ ..actually, I used the same scheme as for Qt when possible, that is:
+ $class =~ s/^Q/Qt::/ or
+ $class =~ s/^K/KDE::/ or
+ $class = "KDE::" . $class
+ unless $class eq "Qt";
+
+2003-09-18 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added support for KDE classes under module KDE:: for use with
+ the new libsmokekde.so. You can now write KDE programs in Ruby,
+ here is Hello World:
+
+ about = KDE::KAboutData.new("one", "two", "three")
+ KDE::KCmdLineArgs.init(1, ["four"], about)
+ a = KDE::KApplication.new()
+ hello = KDE::KPushButton.new(nil) { setText "Hello World" }
+ a.setMainWidget(hello)
+ hello.show()
+ a.exec()
+
+2003-09-14 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The rbuic -embed option finally works. Fixed QByteArray marshalling.
+
+2003-09-13 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Improved the rbuic -embed option, and added some fixes
+
+2003-09-12 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * More passing blocks to constructors fun! You can now also pass
+ an arg to the block, and it will be run in the context of the arg:
+
+ w = MyWidget.new { |theWidget| theWidget.setCaption "foobar" }
+
+ I got this idea from the FXRuby bindings, from the ChangeLog:
+
+ "This approach has the advantage that the initialization code now has
+ access to the outer scope, as blocks normally would. Thanks to
+ Rich Kilmer for this suggestion."
+
+ If you don't pass an arg to the block, the block is run in the context
+ of the new instance as before.
+
+ * Debugging left in handlers.cpp (must stop doing this)
+
+2003-09-12 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Marshallers now return Qnil, rather than Qundef (for internal use only)
+
+2003-09-10 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Improved garbage collection with various 'ad hoc' rules from the
+ QtJava bindings about when it's ok/not ok to destruct an instance.
+ Not always just a 'parent() != 0' check in Qt.
+
+2003-09-10 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added QByteArray <-> Ruby string marshaller
+
+2003-09-09 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Blocks can now be passed to constructors, like this:
+ w = MyWidget.new { setCaption("foobar") }
+
+2003-09-08 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added method selector caching, scribbling may be slightly faster..
+
+2003-09-08 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * GC getting closer to working. Debugging code improved.
+
+2003-09-08 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * From below 'watch out for extra crashes!' - indeed! Have now disabled
+ smokeruby_free() and smokeruby_mark() until garbage collection works.
+
+2003-09-08 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * The pointer_map is now a QPtrDict rather than a ruby Hash, and
+ the entries are weak references. An implementation was tried
+ using the ruby WeakRef class, but it didn't work because rb_gc_mark()
+ didn't prevent them being garbage collected.
+ * smokeruby_free() and smokeruby_mark() have been implemented
+ * The C++ instance for a ruby object is deleted in smokeruby_free(),
+ so watch out for extra crashes!
+ * Improved README with more details about QtRuby
+
+2003-09-07 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Improved error message handling, changed rb_error() calls to rb_raise()
+ * Decided changing method calls like foobar? to isFoobar() not a good idea,
+ as the Qt property could just as also be hasFoobar() or foobar()
+
+2003-09-06 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Set methods such as autoMask= are converted to setAutoMask()
+ * Get methods such as modal? are converted to isModal()
+
+2003-08-31 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * rbuic code generation brought up to date wrt Qt 3.2 uic
+ Main change is that a 'languageChanged()' method is generated
+
+2003-08-30 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * rbuic() code generation fixes
+
+2003-08-30 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added 'Run Selection' menu option to the QtRuby shell
+
+2003-08-30 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Operator methods are now called 'operator..' in QGlobalSpace and not renamed
+ * Added unary minus, and a test in opoverloading.rb
+
+2003-08-29 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Updated TODO list, improved rbuic code generation for images
+
+2003-08-28 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Improved operator overloading to work with operators not in QGlobalSpace
+
+2003-08-27 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Changed the operator overloading implementation to be more like PerlQt
+
+2003-08-27 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Translated the rbqtsh filePrint() method from perl
+
+2003-08-26 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added 'changed' attribute to the MetaInfo class, so that the C++ metaObject
+ is reconstructed if the slots or signals are changed.
+ * Changed window title on rbqtsh to 'QtRuby'. The example slot now works
+ correctly. Only just tried this utility - Wow Alex!!
+
+2003-08-26 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * findMethod() now looks in the QGlobalSpace pseudo class as well as the normal target class.
+ * The bitBlt() code in the scribble example works correctly
+
+2003-08-25 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Removed ugly _current_object global variable.
+ The current target object is now passed to the MethodCall constructor.
+
+2003-08-25 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Removed obsolete rb_enable_super() calls
+ * Removed test for _current_object in class_method_missing()
+ * Fixed missing index in signalInfo() method
+ * Added Qt scribble example - TODO add Qt::PaintDevice.bitBlt() calls to SMOKE runtime
+
+2003-08-23 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added rbuic tool for ruby Qt Designer support
+
+2003-08-12 Alexander Kellett <lypanov@kde.org>
+
+ * Add debug level setting via Qt::debug_level
+ * When calling .new on a Qt object with a incorrect prototype
+ the list of appropriate constructors is printed
+ * Fix a number of cases in which imperfect code would cause a crash
+
+2003-08-11 Alex Zepeda <zipzippy@sonic.net>
+
+ * Various fixes to get QStringList marshalling working
+ * Treat Ruby strings as UTF-8 strings in order to fix the QFont examples
+
+2003-08-09 Alexander Kellett <lypanov@kde.org>
+
+ * Added support for operator overloading
+
+2003-08-07 Alexander Kellett <lypanov@kde.org>
+
+ * Added rbqtapi and rbqt tools (port of the PerlQt tools of the same name)
+
+2003-08-06 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Added some TODO list entries, added Alex to the AUTHORS list
+
+2003-08-06 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed 'int&' marshalling so script name appears in window title
+
+2003-08-12 Alexander Kellett <lypanov@kde.org>
+
+ * Add several new marshalling types - QCanvasItemList for example,
+ unfortuantely due to several improvements in Qt 3.2 these
+ improvements will not be seen when compiling against Qt 3.1.2
+
+2003-08-05 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Moved SLOT(), SIGNAL() and emit() to global scope
+
+2003-08-05 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Removed redundant 'rb_eval_string("include Qt")' call from extension initialization.
+
+2003-08-05 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Qt::Application constructor safer, but program name still not appearing in the window title
+
+2003-08-05 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed bug in resolution of overloaded Qt::Popup.insertItem() methods
+
+2003-08-05 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Use new const_missing from ruby 1.8.x to allow for constant access from base class, for example "Qt::RichText"
+ * QString::null now maps onto Qnil, rather than a zero length ruby string
+
+2003-08-04 Alexander Kellett <lypanov@kde.org>
+
+ * Allow for accumulative slots/signals declarations in a class
+ * Minor build fixes
+
+2003-08-02 Alexander Kellett <lypanov@kde.org>
+
+ * Fix several deprecation warnings when running under 1.8.x
+ * Several more build fixes
+
+2003-08-01 Alexander Kellett <lypanov@kde.org>
+
+ * Slightly improve ease of debugging of qtruby programs
+ which subclass Qt base classes by print out some useful
+ debugging informationn when/if method_missing ever
+ fails to find a matching function in the baseclass.
+
+2003-08-01 Alex Zepeda <zipzippy@sonic.net>
+
+ * Remove need to manually run extconf.rb by some automation via a configure.in.in
+ * Various other build fixes
+
+2003-07-31 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed bug in marshalling QString::null to a ruby VALUE
+
+2003-07-31 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Changed require in Qt.cpp to 'Qt/Qt.rb' instead of 'lib/Qt/Qt.rb'
+
+2003-07-31 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * Fixed problem with non-working installed version, lib/Qt.rb moved to lib/Qt/Qt.rb
+
+2003-07-30 Richard Dale <Richard_Dale@tipitina.demon.co.uk>
+
+ * QtRuby - a Ruby SMOKE adaptor for Qt, initial checkin
+
+
diff --git a/qtruby/INSTALL b/qtruby/INSTALL
new file mode 100644
index 00000000..86e05d3d
--- /dev/null
+++ b/qtruby/INSTALL
@@ -0,0 +1,144 @@
+Dependencies
+------------
+
+- ruby 1.8 or greater
+- automake 1.7 or greater
+- Qt 3.1 or greater
+- KDE 3.1 or greater (for korundum)
+
+CVS Snapshot
+------------
+
+If building from a CVS snapshot, this initial make command in needed:
+
+$ make -f Makefile.cvs
+
+Configure flags needed
+----------------------
+
+In order to build korundum: (this is the default in fact, so you can just use ./configure)
+ ./configure --with-smoke="qt kde"
+in order to build just qtruby:
+ ./configure --with-smoke="qt"
+
+Building the Qt extension without KDE build process
+---------------------------------------------------
+
+To build the Qt.so extension, provide 'extconf.rb' with the directories where
+the Qt and Smoke libraries are installed:
+
+$ cd qtruby/rubylib/qtruby
+$ ruby extconf.rb --with-smoke-dir=/opt/kde3 \
+ --with-qt-dir=/home/duke/src/kde/HEAD/qt-copy
+$ make
+$ make install
+
+Building on Mac OS X
+--------------------
+
+Automake/autoconf don't work very well on Mac OS X, and so qmake and
+exconf.rb must be used instead. You can use the native Aqua/Quartz Qt/Mac
+version of Qt - QtRuby doesn't require X11.
+
+Build Qt/Mac and install in /Developer/qt. These configure flags work well:
+
+./configure -system-zlib -qt-gif -plugin-imgfmt-mng -thread -no-stl
+-no-exceptions -fast
+
+Configure QtRuby and build the Smoke library:
+$ ./configure '--with-qt-dir=/Developer/qt' '--enable-mac'
+$ cd smoke/qt
+# Generate the Smoke library sources:
+$ perl generate.pl
+# Overwrite the automake generated Makefile:
+$ qmake -makefile
+# Build the Smoke library and install into /usr/lib
+$ sudo make
+...
+
+# Build the 'Qt' extension:
+$ cd qtruby/rubylib/qtruby
+$ ruby extconf.rb --with-qt-dir=/Developer/qt --with-smoke-dir=/usr \
+ --with-smoke-include=../../../smoke
+$ make
+$ sudo make install
+...
+
+# Build the rbuic tool and install into /usr/bin
+$ cd qtruby/rubylib/designer/rbuic
+$ qmake -makefile
+$ sudo make
+...
+
+# Build the 'qui' QWidgetFactory extension
+$ cd qtruby/rubylib/designer/uilib
+$ ruby extconf.rb --with-qtruby-include=../../qtruby --with-qt-dir=/Developer/qt
+$ make
+$ sudo make install
+
+To get Mac menus to appear, when a QtRuby program is run from the command line,
+link ruby against the carbon resource lib and call it 'rubyw', see:
+
+http://www.rubygarden.org/ruby?RubyTkOnOSX
+
+"Create rubyw executable for MacOS?: the Win32 distribution of ruby includes a
+'rubyw.exe' so I decided to attempt creating a 'rubyw' executable:
+
+On my machine, ruby is installed at /usr/local/bin/ruby, so I did sudo
+cp /usr/local/bin/ruby /usr/local/bin/rubyw
+Using the suggestion directly above (on this page), I then ran
+sudo /Developer/Tools/Rez -t APPL Carbon.r -o rubyw
+I was then able to successfully run an example RubyTk app by
+running /usr/local/bin/rubyw ruby-1.8.0/ext/tk/sample/tkmenubutton.rb
+Everything worked as expected, and I was able to interact with the UI without
+any SetFrontProcess errors. "
+
+Ryutaro Amano wrote this about creating a double clickable bundle:
+
+"Thanks all, I have succeeded make rubyw.
+sample script is launched in foreground.
+And I have known the following steps to launch qt-ruby script by double clicking
+from Finder.
+
+As an example, I take qtruby-1.0.11/qtruby/rubylib/tutorial/t14
+
+cd qtruby-1.0.11/qtruby/rubylib/tutorial/t14
+chmod 755 t14.rb
+replace first line of t14.rb with "#!/usr/local/bin/rubyw"
+mkdir -p Shoot.app/Contents/MacOS
+mv t14.rb Shoot.app/Contents/MacOS/Shoot
+cp {cannon.rb,gamebrd.rb,lcdrange.rb} Shoot.app/Contents/MacOS
+cp Info.plist Shoot.app/Contents
+
+Info.plist is
+
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>Shoot</string>
+ <key>CFBundleIdentifier</key>
+ <string>jp.co.ryutaro.qtquit</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+</dict>
+</plist>
+
+echo -n "APPL????" > Shoot.app/Contents/PkgInfo
+
+Double click Shoot.app, Qt-Window appears in foreground."
+
+QScintilla text editing widget support
+--------------------------------------
+
+QScintilla is a text editing widget with syntax highlighting for a
+number of languages including ruby. It can be downloaded from here:
+
+http://www.riverbankcomputing.co.uk/qscintilla/download.php
+
+Use the '--enable-qscintilla=yes' configure option to build QtRuby with
+QScintilla support. The classes in a 'Qext::' module, with names such as
+Qext::Scintilla.
diff --git a/qtruby/Makefile.am b/qtruby/Makefile.am
new file mode 100644
index 00000000..fc090dfa
--- /dev/null
+++ b/qtruby/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = rubylib bin
+
+EXTRA_DIST = rubylib.kdevprj AUTHORS ChangeLog README TODO rubylib.lsm
diff --git a/qtruby/README b/qtruby/README
new file mode 100644
index 00000000..22dee743
--- /dev/null
+++ b/qtruby/README
@@ -0,0 +1,259 @@
+/***************************************************************************
+ * (C) 2003 Richard Dale All rights reserved. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as *
+ * published by the Free Software Foundation; either version 2 of the *
+ * License, or (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+Here is a Ruby SMOKE adaptor for Qt
+
+Why ruby? From the rubytalk list
+
+On 8/28/03 8:56 PM, "Scott Thompson" wrote:
+
+>> : Can anyone give me a good reason why I would want to use Ruby over
+>> Python?
+>>
+>> Ruby smells better than Python. Also, it has cuter girls.
+>>
+>> Python sometimes tastes better if you prepare it right.
+>
+> I hadn't noticed the odor thing. It does have a faintly floral aroma
+> doesn't it.
+>
+> Of course it is no surprise that you can get more and cuter girls with
+> Rubies than you can with Pythons.
+>
+> Scott
+
+So there you have it! :)
+
+Here is 'Hello World' in QtRuby:
+
+#!/usr/bin/ruby -w
+
+require 'Qt'
+
+a = Qt::Application.new(ARGV)
+hello = Qt::PushButton.new("Hello World!", nil)
+hello.resize(100, 30)
+a.setMainWidget(hello)
+hello.show()
+a.exec()
+
+Ruby 1.8 is unfortunately implicitly required as with 1.6.x it is not possible to:
+
+ Make dynamic constants available (thus forcing syntax such as Qt.RichText rather than Qt::RichText)<br>
+ Call super in the initialize method thus making subclassing of non trivial classes impossible
+
+QtRuby features a very complete coverage of the Qt api:
+
+ - You can call all Qt public and protected methods, and all friend methods
+ such as bitBlt() etc
+
+ - Virtual methods
+ All virtual methods can be overriden, not just event handlers
+
+ - Properties
+ 'fooBar = 5' is a synonym for 'setFooBar(5)'
+
+ - Predicates
+ 'if foo?' is a synonym for 'if isFoo()' or 'if hasFoo()'
+
+ - Use underscore naming for method names instead of camel case if you
+ prefer. Any underscores in method names are removed, and the following
+ character is capitalised. For example, you can use either of these two
+ forms to call the same method:
+
+ create_standard_status_bar_action()
+
+ createStandardStatusBarAction()
+
+ - Operator overloading
+ The full range of Qt operator methods is available, for example:
+
+ p1 = Qt::Point.new(5,5) => (5, 5)
+ p2 = Qt::Point.new(20,20) => (20, 20)
+ p1 + p2 => (25, 25)
+
+ - Declare signals and slots
+ Signals and slots are declared as list of strings like this:
+
+ slots 'setColor(QColor)', 'slotLoad(const QString&)'..
+ signals 'clicked()'..
+
+ Currently C++ type signatures must be used, a future version of QtRuby
+ will allow ruby type signatures instead.
+
+ Connect slots and signals like this:
+
+ Qt::Object.connect( @_colormenu, SIGNAL( "activated( int )" ),
+ self, SLOT( "slotColorMenu( int )" ) )
+
+ And emit signals like this:
+
+ emit colorChanged( black )
+
+ - Constructors
+ You can call constructors in the conventional style:
+
+ quit = Qt::PushButton.new("Quit", self, "quit")
+
+ Or you can pass a block if you prefer:
+
+ w = MyWidget.new { setCaption("foobar") }
+
+ The block will be called in the context of the newly created instance.
+
+ Ordinary arguments can be provided as well as a block at the end:
+
+ w = MyWidget.new(nil) { setCaption("foobar") }
+
+ They are run in the context of the new instance.
+
+ And there's more! You can also pass an arg to the block, and it will
+ be run in the context of the arg:
+
+ w = MyWidget.new { |theWidget| theWidget.setCaption "foobar" }
+
+ - Garbage Collection
+ When a ruby instance is garbage collected, the underlying C++ instance will only be
+ deleted if it isn't 'owned' by a parent object. Normally this will 'just work', but
+ there are occasions when you need to delete the C++ ahead of garbage collection, and
+ whether or not it has a parent. Use the dispose() and isDisposed() methods like this:
+
+ item2.dispose
+ if item2.isDisposed
+ puts "item2 is disposed"
+ end
+
+ - C++ 'int*' and 'int&' argument types
+ Ruby passes numeric values by value, and so they can't be changed when passed to a
+ method. The Qt::Integer class provides a mutable numeric type which does get updated
+ when passed as an argument. For example, this C++ method 'findByFileContent()':
+
+ # static Ptr findByFileContent( const QString &fileName, int *accuracy=0 );
+
+ acc = Qt::Integer.new(0)
+ fc = KDE::MimeType.findByFileContent("mimetype.rb", acc)
+
+ It supports the arithmetic operators, and so expressions such as 'acc + 3' will work.
+
+ - C++ 'bool*' and 'bool&' argument types
+ There is a similar problem for bool arg types, and the mutable Qt::Boolean class can be
+ used like this:
+
+ # QFont getFont(bool * ok, const QFont&initial, QWidget* parent = 0, const char *name = 0);
+
+ ok = Qt::Boolean.new
+ font = Qt::FontDialog.getFont(ok, Qt::Font.new("Helvetica [Cronyx]", 10), self)
+ if !ok.nil?
+ # font is set to the font the user selected
+ else
+ # the user canceled the dialog
+ end
+
+ Use 'nil?' to test the value returned in the Boolean
+
+ - Debugging
+ If a method call can't be matched in the Smoke library giving a 'method_missing'
+ error, you can turn on debugging to trace the matching process:
+
+ a = Qt::Application.new(ARGV)
+ Qt.debug_level = Qt::DebugLevel::High
+ a.loadLibrary("foo") # Non existent method
+
+ Will give the following output:
+
+ classname == QApplication
+ :: method == loadLibrary$
+ -> methodIds == []
+ candidate list:
+ Possible prototypes:
+ static QWidget* QApplication::widgetAt(int, int, bool)
+ ...
+
+ Here, the list of candidate methods 'methodIds' is empty
+
+ Another debugging mechanism allows various trace 'channels' to be switched on.
+
+ You can trace virtual method callbacks:
+ Qt::Internal::setDebug(Qt::QtDebugChannel::QTDB_VIRTUAL)
+
+ Or trace QtRuby garbage collection:
+ Qt::Internal::setDebug(Qt::QtDebugChannel::QTDB_GC)
+
+ - String i18n
+
+ QtRuby supports $KCODE values of 'u', 'e' and
+ 's' or the corresponding '-K' options from the command line. Qt Designer
+ .ui files have UTF-8 strings so if you use any 8 bit UTF-8 characters, you
+ will need to set $KCODE='u' or use the -Ku command line option.
+
+ - Qt Designer
+ A 'rbuic' tool is included in qtruby/rubylib/designer/rbuic to compile
+ .ui files into ruby code. As described above, Qt Designer uses UTF-8.
+ In addition to the options in the original uic C++ utility an '-x' flag
+ has been added. This will generate a top level stub in the code:
+
+ $ rbuic mainform.ui -x -o mainform.rb
+
+ Will add this to the end of the generated code:
+
+ if $0 == __FILE__
+ a = Qt::Application.new(ARGV)
+ w = MainForm.new
+ a.setMainWidget(w)
+ w.show
+ a.exec
+ end
+
+ Then you can test the example code straight away:
+
+ $ ruby mainform.rb
+
+ - Loading .ui files at runtime with QWidgetFactory
+ You can load a Qt Designer .ui file at runtime with the qui extension,
+ for example:
+
+ require 'Qt'
+ require 'qui'
+
+ a = Qt::Application.new(ARGV)
+ if ARGV.length == 0
+ exit
+ end
+
+ if ARGV.length == 2
+ QUI::WidgetFactory.loadImages( ARGV[ 0 ] )
+ w = QUI::WidgetFactory.create( ARGV[ 1 ] )
+ if w.nil?
+ exit
+ end
+ w.show()
+ a.connect( a, SIGNAL('lastWindowClosed()'), a, SLOT('quit()') )
+ a.exec()
+ end
+
+ - QtRuby shell
+ You can use the QtRuby shell in bin/rbqtsh to create widgets
+ interactively from the command line.
+
+ - API reference
+ Use the bin/rbqtapi tool to discover which methods are available in
+ the QtRuby api.
+
+ - Example programs
+ The best way to start programming QtRuby is to look at some existing
+ code and start messing with it..
+ The are various samples under qtruby/rubylib/examples.
+
+ - Optional QScintilla text editing widget support
+ Great for building your own ruby IDE..
+
+Have Fun!
+
+-- Richard
diff --git a/qtruby/README.1st b/qtruby/README.1st
new file mode 100644
index 00000000..00c2cd4e
--- /dev/null
+++ b/qtruby/README.1st
@@ -0,0 +1,17 @@
+Startup Crashes
+---------------
+
+For some strange reason ruby occasionally needs to be compiled
+with --enable-pthread. Gentoo at the very least doesn't default
+this to using this unfortunately. Even worse, using this flag
+makes programs using the gnome2 bindings randomly crash so its
+highly unlikely it'll get into distributions / ruby by default.
+
+There is a workaround however:
+
+With the program krubyinit from korundum/bin installed it is
+possible to simply replace a programs shebang line with:
+ #!/usr/bin/env krubyinit
+Incidently as well as majorly fixing up pthread related startup
+crashes, this also makes it possible for kdeinit_wrapper usage,
+therefore improving startup speed yet further.
diff --git a/qtruby/TODO b/qtruby/TODO
new file mode 100644
index 00000000..aca08299
--- /dev/null
+++ b/qtruby/TODO
@@ -0,0 +1,13 @@
+ * Implement the special case method in Qt::Image constructor
+
+ * Allow 'String' and other ruby types to be used in SIGNALs/SLOTs
+
+ * More documentation or example code - contributions welcome!
+
+ * See the separate TODO list for the rbuic tool
+
+ * Write a rubyeditor plugin for Qt Designer
+
+ * Add an option to rbqtapi to show the api in ruby format, rather than C++
+
+ * Write a graphic class browser based on rbqtapi
diff --git a/qtruby/bin/Makefile.am b/qtruby/bin/Makefile.am
new file mode 100644
index 00000000..e53bd0fc
--- /dev/null
+++ b/qtruby/bin/Makefile.am
@@ -0,0 +1,9 @@
+INCLUDES = $(all_includes) -I$(RUBY_ARCHDIR)
+
+bin_PROGRAMS = qtrubyinit
+qtrubyinit_LDFLAGS = -module $(all_libraries) -version-info 0:0:0 -L$(top_srcdir)/smoke/qt/ -L$(RUBY_LIBDIR)
+qtrubyinit_METASOURCES = AUTO
+qtrubyinit_SOURCES = qtrubyinit.cpp
+qtrubyinit_LDADD = $(LIB_QT) $(RUBY_LIBRUBYARG) $(top_builddir)/smoke/qt/libsmokeqt.la $(top_builddir)/qtruby/rubylib/qtruby/libqtrubyinternal.la
+
+bin_SCRIPTS = rbqtapi rbqtsh
diff --git a/qtruby/bin/qtrubyinit.cpp b/qtruby/bin/qtrubyinit.cpp
new file mode 100644
index 00000000..2451e002
--- /dev/null
+++ b/qtruby/bin/qtrubyinit.cpp
@@ -0,0 +1,29 @@
+#include <ruby.h>
+
+/***************************************************************************
+qrubyinit - makes use of kdeinit_wrapper possible for ruby programs
+-------------------
+ begin : Wed Jan 7 2004
+ copyright : (C) 2004 by Alexander Kellett
+ email : lypanov@kde.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// this name can be used to allow apps
+// to detect what they were started with
+static const char* script_name = "qrubyinit_app";
+
+int main(int argc, char **argv) {
+ ruby_init();
+ ruby_script((char*)script_name);
+ ruby_options(argc, argv);
+ ruby_run();
+}
diff --git a/qtruby/bin/rbqtapi b/qtruby/bin/rbqtapi
new file mode 100755
index 00000000..30735b48
--- /dev/null
+++ b/qtruby/bin/rbqtapi
@@ -0,0 +1,103 @@
+#!/usr/bin/env ruby
+
+# Note: this program is part of qtruby and makes use of its internal functions.
+# You should not rely on those in your own programs.
+
+require 'getopts'
+getopts('r:hvimp')
+
+case File.basename $0
+when "rbqtapi"
+ require 'Qt'
+when "rbkdeapi"
+ require 'Korundum'
+end
+
+if $OPT_v
+ # TODO add and use version number #{Qt::VERSION}
+ print "qtruby using Qt-#{Qt::version}\n"
+ exit 0
+elsif $OPT_h
+ print $usage
+ exit 0
+end
+
+if $OPT_m
+ while 1
+ line = STDIN.readline.chomp
+ line.gsub!(/^Q(?=[A-Z])/,'Qt::')
+ line.gsub!(/^K/,'KDE::') unless line =~ /^(KDE)|(KIO)|(KParts)|(KNS)/
+ classid = Qt::Internal::find_pclassid($_)
+ puts "__START__"
+ if classid
+ a = Qt::Internal::findAllMethods(classid)
+ ids = (a.keys.sort.map{|k|a[k]}).flatten
+ candidates = Qt::dumpCandidates(ids)
+ sup = []
+ Qt::Internal::getAllParents(classid, sup)
+ sup.each {
+ |sup_item|
+ a = Qt::Internal::findAllMethods(sup_item)
+ ids = (a.keys.sort.map{|k|a[k]}).flatten
+ candidates << Qt::Internal::dumpCandidates(ids)
+ }
+ candidates.gsub("\t","") # erm. whats the "s" mean on s/\t//gs ?
+ print candidates
+ end
+ puts "__END__"
+ end
+end
+
+search_string = ARGV[0] ? ARGV[0].dup : nil
+search_string.gsub!(/^Q(?=[A-Z])/,'Qt::') if search_string
+# search_string.gsub!(/^K(?=[^D][^E])/,'KDE::') if search_string
+search_string.gsub!(/^K/,'KDE::') unless search_string.nil? or search_string =~ /^(KDE)|(KIO)|(KParts)|(KNS)/
+classid = search_string ? Qt::Internal::find_pclassid(search_string) : 1
+if classid == 0
+ puts "Class #{search_string} not found"
+ exit 1
+end
+regexp = nil
+regexp = ( $OPT_i ? Regexp.new($OPT_r, Regexp::IGNORECASE) : Regexp.new($OPT_r) ) if $OPT_r
+candidates = ""
+while true
+ a = Qt::Internal::findAllMethods(classid)
+ break if a.nil?
+ ids = (a.keys.sort.map{|k|a[k]}).flatten
+ candidates = Qt::Internal::dumpCandidates(ids)
+ if $OPT_p and !search_string.empty? and classid
+ sup = []
+ Qt::Internal::getAllParents(classid, sup)
+ sup.each {
+ |sup_item|
+ a = Qt::Internal::findAllMethods(sup_item)
+ ids = (a.keys.sort.map{|k|a[k]}).flatten
+ candidates << Qt::Internal::dumpCandidates(ids)
+ }
+ end
+ if regexp
+ candidates.split("\n").each {
+ |candidate|
+ puts candidate if candidate =~ regexp
+ }
+ else
+ print candidates
+ end
+ break unless search_string.nil?
+ classid += 1
+end
+
+BEGIN {
+$usage = <<USAGE
+rbqtapi - a qtruby introspection tool\t(c) Germain Garand 2003 <germain\@ebooksfrance.org>
+
+usage: rbqtapi [-r <re>] [<class>]
+
+options:
+\t-r <re> : find all functions matching regular expression/keyword <re>
+\t-i : together with -r, performs a case insensitive search
+\t-p : display also inherited methods for <class>.
+\t-v : print qtruby and Qt versions
+\t-h : print this help message
+USAGE
+}
diff --git a/qtruby/bin/rbqtsh b/qtruby/bin/rbqtsh
new file mode 100755
index 00000000..b9d8ee9e
--- /dev/null
+++ b/qtruby/bin/rbqtsh
@@ -0,0 +1,627 @@
+#!/usr/bin/env ruby
+
+# rbqtsh : a graphical shell for qtruby.
+#
+# author: Germain Garand <germain@ebooksfrance.org>
+# ruby port: Alexander Kellett <lypanov@kde.org>
+# license: GNU Public License v2
+#
+
+require 'stringio'
+
+case File.basename $0
+when "rbqtsh"
+ require 'Qt'
+when "rbkdesh"
+ require 'Korundum'
+end
+
+include Qt
+
+$image0_data =
+["22 22 7 1",
+". c None",
+"# c #000000",
+"b c #292c29",
+"c c #5a5d5a",
+"d c #838583",
+"e c #c5c2c5",
+"a c #ffffff",
+"......................",
+"....##########........",
+"....#aaaaaaa#b#.......",
+"....#aaaaaaa#cb#......",
+"....#aaaaaaa#dcb#.....",
+"....#aaaaaaa#edcb#....",
+"....#aaaaaaa#aedcb#...",
+"....#aaaaaaa#######...",
+"....#aaaaaaaaaaaaa#...",
+"....#aaaaaaaaaaaaa#...",
+"....#aaaaaaaaaaaaa#...",
+"....#aaaaaaaaaaaaa#...",
+"....#aaaaaaaaaaaaa#...",
+"....#aaaaaaaaaaaaa#...",
+"....#aaaaaaaaaaaaa#...",
+"....#aaaaaaaaaaaaa#...",
+"....#aaaaaaaaaaaaa#...",
+"....#aaaaaaaaaaaaa#...",
+"....#aaaaaaaaaaaaa#...",
+"....###############...",
+"......................",
+"......................"]
+
+$image1_data =
+["22 22 5 1",
+". c None",
+"# c #000000",
+"c c #838100",
+"a c #ffff00",
+"b c #ffffff",
+"......................",
+"......................",
+"......................",
+"............####....#.",
+"...........#....##.##.",
+"..................###.",
+".................####.",
+".####...........#####.",
+"#abab##########.......",
+"#babababababab#.......",
+"#ababababababa#.......",
+"#babababababab#.......",
+"#ababab###############",
+"#babab##cccccccccccc##",
+"#abab##cccccccccccc##.",
+"#bab##cccccccccccc##..",
+"#ab##cccccccccccc##...",
+"#b##cccccccccccc##....",
+"###cccccccccccc##.....",
+"##cccccccccccc##......",
+"###############.......",
+"......................"]
+
+$image2_data =
+["22 22 5 1",
+". c None",
+"# c #000000",
+"a c #838100",
+"b c #c5c2c5",
+"c c #cdb6d5",
+"......................",
+".####################.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbcbb####.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aaa############aaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaa#############aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+"..##################..",
+"......................"]
+
+$image3_data =
+["22 22 88 2",
+"Qt c None",
+".2 c #000000",
+".S c #08ff08",
+"#v c #100810",
+".U c #101010",
+"#c c #101018",
+".M c #181018",
+"#e c #181818",
+".A c #181820",
+".L c #201820",
+"#l c #202020",
+".z c #202029",
+"#m c #292029",
+"#u c #292829",
+"#n c #292831",
+".R c #29ff29",
+"#o c #312831",
+".T c #313031",
+"#p c #313039",
+".Z c #31ff31",
+"#q c #393039",
+"#t c #393839",
+".y c #393841",
+"#s c #413841",
+".o c #414041",
+"#h c #4a4852",
+".n c #5a505a",
+"#r c #5a5962",
+".I c #5ace5a",
+"#b c #6a616a",
+".p c #6a696a",
+".x c #6a6973",
+".Y c #6aff62",
+".l c #736973",
+".t c #7b717b",
+".s c #7b7183",
+".0 c #7bff7b",
+".r c #837983",
+".u c #83798b",
+"#g c #83858b",
+".v c #8b7994",
+"#i c #8b858b",
+".w c #8b8594",
+"#j c #8b8d8b",
+".8 c #8b8d94",
+".m c #948d94",
+"#k c #948d9c",
+"#f c #949594",
+".q c #94959c",
+".J c #94c694",
+"#d c #9c959c",
+"#a c #9c95a4",
+".k c #9c9d9c",
+".N c #9c9da4",
+".H c #9ccea4",
+".K c #a49da4",
+"#. c #a49dac",
+".i c #a4a5a4",
+".3 c #a4a5ac",
+"## c #ac9dac",
+".V c #aca5ac",
+".d c #acaeac",
+".j c #acaeb4",
+".9 c #b4aeb4",
+".# c #b4b6b4",
+".a c #bdbebd",
+".7 c #bdd6bd",
+".c c #c5c6c5",
+".5 c #cdc6cd",
+".b c #cdcecd",
+".4 c #cdced5",
+".F c #d5ced5",
+".G c #d5cede",
+".h c #d5d6d5",
+".E c #d5d6de",
+".Q c #d5ffd5",
+".B c #ded6de",
+".1 c #ded6e6",
+".g c #dedede",
+".D c #dedee6",
+".6 c #e6dee6",
+".f c #e6e6e6",
+".C c #e6e6ee",
+".X c #e6ffe6",
+".O c #eee6ee",
+".e c #eeeeee",
+".W c #f6f6f6",
+".P c #ffffff",
+"QtQtQtQtQtQt.#.a.b.b.b.b.c.c.a.a.d.aQtQtQtQt",
+"QtQtQtQtQtQt.a.e.f.f.f.f.f.e.e.e.g.aQtQtQtQt",
+"QtQtQtQtQtQt.a.c.c.c.b.b.c.c.c.c.a.cQtQtQtQt",
+"QtQtQtQtQtQt.#.a.a.a.a.#.a.a.#.#.d.aQtQtQtQt",
+"QtQtQtQtQt.c.d.c.a.c.c.c.a.a.a.c.#QtQtQtQtQt",
+"QtQtQtQtQt.a.a.#.a.a.a.a.a.a.c.c.#QtQtQtQtQt",
+"QtQtQtQtQt.a.#.c.a.a.a.a.a.c.a.c.dQtQtQtQtQt",
+"QtQtQtQtQt.c.a.a.a.a.a.a.a.a.a.a.#QtQtQtQtQt",
+"QtQtQtQtQt.d.b.f.g.g.g.g.g.g.h.g.i.i.jQtQtQt",
+"QtQtQt.a.k.l.#.h.b.h.b.h.b.h.g.g.m.n.o.p.#Qt",
+"QtQt.a.q.r.s.t.t.t.t.t.t.t.u.v.w.x.y.z.A.o.i",
+"Qt.a.k.B.C.D.B.E.E.E.E.F.G.H.I.J.K.o.L.L.M.y",
+".a.N.O.P.P.P.P.P.P.P.P.P.Q.R.S.R.b.v.T.A.U.L",
+".V.W.P.P.P.P.P.P.P.P.P.P.X.Y.Z.0.P.1.t.A.2.L",
+".3.E.4.5.4.h.E.E.g.6.D.B.D.E.7.F.4.5.8.M.2.A",
+".m.9.j.V.3#..3.K#.#..i#..K#.###a.q.8#b#c.2.L",
+".m.j.j#..3.K.K.K.N.K.N.N.N.N#a#d#d.w#b#c.2#e",
+"#f#.#..K.N.K.N.N.N#a.k#a#d#d#d#a.m#g#b.M.2#h",
+".m.3.K.K#a.k#a#d#a.k#a#d#a#d.q.m.8#i.x#c#e.d",
+"#f#g#i.w#j.w#i.8.w#i.8.8.m.8.m#k.8.w#b#e#fQt",
+".#.l.z.A#l.z#m#m#m#n#o#o#p#p#q#q#p#o#p#fQtQt",
+"QtQt.d#r#s#s#t#p.T.T.T#u#u.z#e#e#v.o.kQtQtQt"]
+
+
+class QtShellControl < Qt::MainWindow
+ attr_accessor :menubar, :fileMenu, :helpMenu, :toolBar, :fileName, :fileOpenAction
+ attr_accessor :fileSaveAction, :fileSaveAsAction, :filePrintAction, :fileExitAction
+ attr_accessor :helpExampleAction, :comboBox, :sessionLog, :executedLines, :printer
+ slots 'fileOpen()', 'fileOpen()', 'fileSave()', 'fileSaveAs()'
+ slots 'filePrint()', 'fileExit()', 'runSelection()', 'helpExample()'
+ signals 'fileNeedsEval(QString)', 'selection(QString)'
+
+ def initialize(*k)
+ super(*k)
+ image0 = Qt::Pixmap.new($image0_data)
+ image1 = Qt::Pixmap.new($image1_data)
+ image2 = Qt::Pixmap.new($image2_data)
+ image3 = Qt::Pixmap.new($image3_data)
+ box = VBox.new(self)
+ @sessionLog = TextEdit.new(box, "sessionLog")
+ @sessionLog.setTextFormat(Qt::RichText)
+ @sessionLog.setReadOnly(true)
+ @comboBox = ComboBox.new(box, "comboBox")
+ @comboBox.setEditable(true)
+ @comboBox.setAutoCompletion(true)
+ self.setCentralWidget(box)
+ @comboBox.setFocus
+ self.resize(500,300)
+ self.setCaption("QtRuby Shell")
+ def trUtf8(k)
+ return k
+ end
+ @fileOpenAction = Qt::Action.new(self, "fileOpenAction")
+ @fileOpenAction.setIconSet(Qt::IconSet.new(image1))
+ @fileOpenAction.setText(trUtf8("Open"))
+ @fileOpenAction.setMenuText(trUtf8("&Open..."))
+ @fileOpenAction.setAccel(KeySequence.new(trUtf8("Ctrl+O")))
+ @fileSaveAction = Qt::Action.new(self, "fileSaveAction")
+ @fileSaveAction.setIconSet(Qt::IconSet.new(image2))
+ @fileSaveAction.setText(trUtf8("Save"))
+ @fileSaveAction.setMenuText(trUtf8("&Save"))
+ @fileSaveAction.setAccel(KeySequence.new(trUtf8("Ctrl+S")))
+ @fileSaveAsAction = Qt::Action.new(self, "fileSaveAsAction")
+ @fileSaveAsAction.setText(trUtf8("Save As"))
+ @fileSaveAsAction.setMenuText(trUtf8("Save &As..."))
+ @fileSaveAsAction.setAccel(KeySequence.new(trUtf8("Ctrl+A")))
+ @filePrintAction = Qt::Action.new(self, "filePrintAction")
+ @filePrintAction.setIconSet(Qt::IconSet.new(image3))
+ @filePrintAction.setText(trUtf8("Print"))
+ @filePrintAction.setMenuText(trUtf8("&Print..."))
+ @filePrintAction.setAccel(KeySequence.new(trUtf8("Ctrl+P")))
+ @fileExitAction = Qt::Action.new(self, "fileExitAction")
+ @fileExitAction.setText(trUtf8("Exit"))
+ @fileExitAction.setMenuText(trUtf8("E&xit"))
+ @fileExitAction.setAccel(KeySequence.new(trUtf8("Ctrl+E")))
+
+ @runAction = Qt::Action.new(self, "runAction");
+ @runAction.setText(trUtf8("Run Selection"));
+ @runAction.setMenuText(trUtf8("&Run Selection"));
+ @runAction.setAccel(KeySequence.new(trUtf8("Ctrl+R")));
+
+ @helpExampleAction = Qt::Action.new(self, "helpExampleAction");
+ @helpExampleAction.setText(trUtf8("Example"));
+ @helpExampleAction.setMenuText(trUtf8("Examp&le"));
+ @helpExampleAction.setAccel(KeySequence.new(trUtf8("Ctrl+L")));
+
+ @toolBar = Qt::ToolBar.new("", self, DockTop)
+ @toolBar.setLabel(trUtf8("Tools"))
+
+ @fileOpenAction.addTo(toolBar)
+ @fileSaveAction.addTo(toolBar)
+ @filePrintAction.addTo(toolBar)
+
+ @menubar= Qt::MenuBar.new(self, "menubar")
+
+ @fileMenu= Qt::PopupMenu.new(self)
+ @fileOpenAction.addTo(fileMenu)
+ @fileSaveAction.addTo(fileMenu)
+ @fileSaveAsAction.addTo(fileMenu)
+ @fileMenu.insertSeparator
+ @filePrintAction.addTo(fileMenu)
+ @fileMenu.insertSeparator
+ @fileExitAction.addTo(fileMenu)
+ @menubar.insertItem(trUtf8("&File"), fileMenu)
+
+ @menubar.insertSeparator
+
+ @runMenu= Qt::PopupMenu.new(self)
+ @runAction.addTo(@runMenu)
+ @menubar.insertItem(trUtf8("Run"), @runMenu)
+
+ @menubar.insertSeparator
+
+ @helpMenu= Qt::PopupMenu.new(self)
+ @helpExampleAction.addTo(helpMenu)
+ @menubar.insertItem(trUtf8("&Help"), helpMenu)
+
+ connect(@fileOpenAction, SIGNAL('activated()'), self, SLOT('fileOpen()'))
+ connect(@fileSaveAction, SIGNAL('activated()'), self, SLOT('fileSave()'))
+ connect(@fileSaveAsAction, SIGNAL('activated()'), self, SLOT('fileSaveAs()'))
+ connect(@filePrintAction, SIGNAL('activated()'), self, SLOT('filePrint()'))
+ connect(@fileExitAction, SIGNAL('activated()'), self, SLOT('fileExit()'))
+ connect(@runAction, SIGNAL('activated()'), self, SLOT('runSelection()'))
+ connect(@helpExampleAction, SIGNAL('activated()'), self, SLOT('helpExample()'))
+
+ @executedLines = []
+ end
+
+ def fileOpen
+ fname = Qt::FileDialog::getOpenFileName(
+ ".",
+ "Rbqtsh Session (*.rbqts)",
+ self,
+ "open session",
+ "Choose a file to open")
+ return if fname.nil?
+ emit fileNeedsEval(fname)
+ end
+
+ def getFileName
+ @fileName = Qt::FileDialog::getSaveFileName(
+ ".",
+ "Rbqtsh Session (*.rbqts)",
+ self,
+ "save session",
+ "Choose a filename" )
+ unless @fileName =~ /\.rbqts$/
+ @fileName << ".rbqts"
+ end
+ @fileName
+ end
+
+ def save(fname)
+ file = File.new(fname, "w")
+ if file.nil
+ # TODO fix ": unknown" to give a reason
+ Qt::MessageBox::critical(
+ self,
+ "Error" ,
+ "Couldn't open #{fname} for writing: unknown",
+ Qt::MessageBox::Ok,
+ Qt::MessageBox::NoButton )
+ return
+ end
+ @executedLines.each {
+ |line|
+ next if line =~ /^\s*$/
+ line.chomp!
+ line << ";" unless line =~ /;\s*$/
+ file.puts(line)
+ }
+ file.close
+ end
+
+ def fileSave
+ return if emptySession
+ fname = @fileName || getFileName
+ return if fname.nil?
+ save fname
+ end
+
+ def fileSaveAs(cond = 0)
+ return if emptySession
+ fname = getFileName
+ return if fname.nil?
+ ret = nil
+ if File.exists(fname)
+ cond += 1
+ ret = Qt::MessageBox::warning(
+ self,
+ "Warning" ,
+ "File exists, overwrite ?",
+ Qt::MessageBox::Yes,
+ Qt::MessageBox::No )
+ else
+ cond = 0
+ end
+ fileSaveAs(cond) if (cond == 0) and ret == Qt::MessageBox::No
+ save(fname)
+ end
+
+ def filePrint()
+ margin = 10
+ pageNo = 1
+ emptySession() and return
+ printer = Qt::Printer.new()
+ if printer.setup(self)
+ statusBar().message( "Printing..." )
+ p = Qt::Painter.new()
+ if ! p.begin( printer )
+ statusBar().message( "An error occured..." )
+ return
+ end
+
+ p.setFont( sessionLog.font() )
+ yPos = 0
+ fm = p.fontMetrics
+ metrics = Qt::PaintDeviceMetrics.new( printer )
+
+ for i in 0..@executedLines.length-1
+ if margin + yPos > metrics.height() - margin
+ msg ="Printing (page "+ ++pageNo + ")..."
+ statusBar().message( msg )
+ printer.newPage()
+ yPos = 0
+ end
+ p.drawText( margin, margin + yPos,
+ metrics.width(), fm.lineSpacing(),
+ ExpandTabs | DontClip,
+ "#{@executedLines[ i ]}" )
+ yPos = yPos + fm.lineSpacing()
+ end
+ p.end()
+ statusBar().message( "Printing completed", 3000 )
+ else
+ statusBar().message( "Printing aborted", 3000 )
+ end
+ end
+
+ def fileExit
+ emit $qApp.quit if confirmExit
+ end
+
+ def closeEvent(e)
+ if confirmExit
+ e.accept
+ else
+ e.ignore
+ end
+ end
+
+ def confirmExit
+ ret = 0
+ return true if @executedLines.empty?
+ ret = Qt::MessageBox::warning(
+ self,
+ "Warning" ,
+ "A session is opened, quit anyway ?",
+ Qt::MessageBox::Yes,
+ Qt::MessageBox::No)
+ return ret != Qt::MessageBox::No
+ end
+
+ def emptySession
+ empty = @executedLines.empty?
+ statusBar.message("Session is empty...", 3000) if empty
+ empty
+ end
+
+ def runSelection
+ emit selection(@sessionLog.selectedText())
+ end
+
+ def helpExample
+ emit fileNeedsEval("__DATA__")
+ end
+
+end
+
+class QtShell < Qt::MainWindow
+ slots 'evalInput()', 'evalFile(QString)', 'evalSelection(QString)'
+ attr_accessor :shellWindow
+ @@binding = binding
+def bind
+@@binding
+end
+
+def initialize(*k)
+ super(*k)
+
+ @shellWindow = QtShellControl.new(nil, "shellWindow")
+ self.resize(350,350)
+ self.move(Point.new(10,10))
+ @shellWindow.move(Point.new(300,200))
+ self.show
+ @shellWindow.show
+
+ connect(@shellWindow.comboBox.lineEdit, SIGNAL('returnPressed()'), self, SLOT('evalInput()'))
+
+ @prompt = '<b><font color="blue">$&gt;</font></b>'
+ self.setCaption("MainWindow - this")
+ @shellWindow.sessionLog.setText("Ready.<br>")
+ connect(@shellWindow, SIGNAL('fileNeedsEval(QString)'), self, SLOT('evalFile(QString)'))
+ connect(@shellWindow, SIGNAL('selection(QString)'), self, SLOT('evalSelection(QString)'))
+end
+
+def logAppend(str)
+ tmp = @shellWindow.sessionLog.text << str
+ @shellWindow.sessionLog.setText tmp
+end
+
+def evalInput
+ evalOneLine @shellWindow.comboBox.currentText
+end
+
+=begin
+
+sub TIEHANDLE { my ( $classnm, $widg, $color) = @_;
+ my $h = { widg => $widg, color => $color};
+ bless $h, $classnm;
+}
+
+sub PRINT {
+ my $me = shift;
+ my $color = $me->{color};
+ my $printed = join $/, @_;
+ $printed =~ s/</&lt;/gs;
+ $printed =~ s/>/&gt;/gs;
+ $printed =~ s/\n/<br>/gs;
+ $me->{widg}->setText( $me->{widg}->text . "<font color=\"$color\">$printed</font>" );
+}
+
+#tie *STDOUT, 'Qt::TextHandle', $shw->sessionLog, 'black';
+#tie *STDERR, 'Qt::TextHandle', $shw->sessionLog, 'red';
+
+=end
+
+def evalOneLine(line)
+ prot = ln = line
+ prot.gsub('<', '&lt;') # /gs ???
+ prot.gsub('>', '&gt;') # /gs ???
+
+ logAppend( "#{@prompt}#{prot}" )
+
+ ostdout, ostderr = $stdout, $stderr
+ strio = StringIO.new
+ $stdout, $stderr = strio, strio
+ begin
+ if line =~ /^\$(.*)$/
+ eval $1, bind
+ else
+ eval line
+ end
+ rescue StandardError, ScriptError => e
+ prot = e.to_str
+ prot.gsub(/</, '&lt;') # /gs ???
+ prot.gsub(/>/, '&gt;') # /gs ???
+ c = @shellWindow.sessionLog.color
+ prot.gsub(/\n/, '<br>') # /gs ???
+ logAppend '<font color="red">' << prot << '</font><br>'
+ shellWindow.sessionLog.setColor c
+ end
+ logAppend '<font color="blue">' << strio.string << '</font><br>'
+ @shellWindow.executedLines << line
+ @shellWindow.comboBox.clearEdit
+ @shellWindow.comboBox.setFocus
+ $stdout, $stderr = ostdout, ostderr
+
+ @shellWindow.sessionLog.scrollToBottom
+end
+
+def evalFile(fname)
+ if fname == "__DATA__"
+ file = StringIO.new
+ file.string = $example
+ else
+ file = File.open(fname, "r")
+ if file.nil?
+ # TODO use $! -> error message!
+ Qt::MessageBox::warning(
+ self,
+ "Error" ,
+ "Couldn't open @{$fn}: $!",
+ Qt::MessageBox::Ok,
+ Qt::MessageBox::NoButton)
+ return
+ end
+ indata = file
+ end
+ file.each_line {
+ |line|
+ evalOneLine(line)
+ }
+ file.close
+end
+
+def evalSelection(selection)
+ evalOneLine(selection.sub(/.*span>/, "")) unless selection.nil?
+end
+
+end
+
+app = Qt::Application.new(ARGV)
+w = QtShell.new(nil, "mainWindow")
+app.setMainWidget(w.shellWindow)
+app.exec
+
+BEGIN {
+$example = <<EXAMPLE
+$ attr_accessor :datetime, :button, :textedit, :sample, :vbox
+statusBar.message("Hello World !")
+@vbox = VBox.new(self)
+@datetime = DateTimeEdit.new(vbox)
+@textedit = TextEdit.new(vbox)
+@button = PushButton.new("Hello World!", vbox)
+self.setCentralWidget(vbox)
+self.resize(220,240)
+@vbox.show
+@sample = Qt::PopupMenu.new(self)
+$ slots 'there()'
+@sample.insertItem("&There", self, SLOT('there()'))
+self.menuBar.insertItem("&Here", sample)
+$ def there; statusBar.message("There...", 2000); end
+EXAMPLE
+}
diff --git a/qtruby/rubylib/Makefile.am b/qtruby/rubylib/Makefile.am
new file mode 100644
index 00000000..1c60934e
--- /dev/null
+++ b/qtruby/rubylib/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = qtruby designer
diff --git a/qtruby/rubylib/designer/Makefile.am b/qtruby/rubylib/designer/Makefile.am
new file mode 100644
index 00000000..80ec1c71
--- /dev/null
+++ b/qtruby/rubylib/designer/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = rbuic uilib
diff --git a/qtruby/rubylib/designer/examples/colortool/Makefile b/qtruby/rubylib/designer/examples/colortool/Makefile
new file mode 100644
index 00000000..df79b963
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/Makefile
@@ -0,0 +1,30 @@
+RBUIC=rbuic
+
+RBUICIMPLS=mainform.rb optionsform.rb colornameform.rb \
+ findform.rb qmake_image_collection.rb
+
+all: $(RBUICIMPLS)
+
+mainform.rb:
+ $(RBUIC) mainform.ui -o mainform.rb
+
+optionsform.rb: optionsform.ui
+ $(RBUIC) optionsform.ui -o optionsform.rb
+
+colornameform.rb: colornameform.ui
+ $(RBUIC) colornameform.ui -o colornameform.rb
+
+findform.rb: findform.ui
+ $(RBUIC) findform.ui -o findform.rb
+
+qmake_image_collection.rb:
+ $(RBUIC) -embed colortool images/filenew.png images/fileopen.png \
+ images/filesave.png images/editcut.png images/editcopy.png \
+ images/searchfind.png images/tabwidget.png images/table.png \
+ images/iconview.png images/richtextedit.png images/widgetstack.png \
+ images/editraise.png -o qmake_image_collection.rb
+
+clean:
+ rm -f $(RBUICIMPLS)
+
+
diff --git a/qtruby/rubylib/designer/examples/colortool/README b/qtruby/rubylib/designer/examples/colortool/README
new file mode 100644
index 00000000..99d2174b
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/README
@@ -0,0 +1,8 @@
+This is the Qt Designer Tutorial 'Creating Dialogs' translated into QtRuby. It
+shows how you can combine ruby code generated from .ui files with the rbuic
+tool, with your own code.
+
+The .ui files and images are identical to the original C++ versions.
+
+It features a simple Makefile to run rbuic when you change the .ui files, and
+regenerate the ruby sources.
diff --git a/qtruby/rubylib/designer/examples/colortool/colornameform.ui b/qtruby/rubylib/designer/examples/colortool/colornameform.ui
new file mode 100644
index 00000000..50f2d6de
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/colornameform.ui
@@ -0,0 +1,168 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>ColorNameForm</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>ColorNameForm</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>348</width>
+ <height>105</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Color Tool - Color Name</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>colorLabel</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>80</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="pixmap">
+ <pixmap>editraise.png</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>colorLineEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>colorLineEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>11</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>okPushButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>cancelPushButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+</widget>
+<connections>
+ <connection>
+ <sender>cancelPushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>ColorNameForm</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>okPushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>ColorNameForm</receiver>
+ <slot>validate()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">colornameform.ui.h</include>
+</includes>
+<slots>
+ <slot>validate()</slot>
+</slots>
+<functions>
+ <function>setColors( const QMap&lt;QString, QColor&gt; &amp; colors )</function>
+</functions>
+<pixmapinproject/>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/qtruby/rubylib/designer/examples/colortool/colornameform.ui.rb b/qtruby/rubylib/designer/examples/colortool/colornameform.ui.rb
new file mode 100644
index 00000000..db671b77
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/colornameform.ui.rb
@@ -0,0 +1,19 @@
+class ColorNameForm
+
+@colors = {}
+
+def setColors( colors )
+ @colors = colors
+end
+
+def validate()
+ name = @colorLineEdit.text()
+ if ! name.empty? &&
+ ( @colors.empty? || ! @colors.has_key?( name ) )
+ accept()
+ else
+ @colorLineEdit.selectAll()
+ end
+end
+
+end
diff --git a/qtruby/rubylib/designer/examples/colortool/findform.ui b/qtruby/rubylib/designer/examples/colortool/findform.ui
new file mode 100644
index 00000000..3e627945
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/findform.ui
@@ -0,0 +1,141 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>FindForm</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>FindForm</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>301</width>
+ <height>99</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Color Tool - Find Color</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Look for:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>findLineEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>findLineEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout10</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>9</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>findPushButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Find</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>closePushButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Close</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>closePushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>FindForm</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>findPushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>FindForm</receiver>
+ <slot>find()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">findform.ui.h</include>
+</includes>
+<signals>
+ <signal>lookfor(const QString&amp;)</signal>
+</signals>
+<slots>
+ <slot>find()</slot>
+</slots>
+<functions>
+ <function>notfound()</function>
+</functions>
+<pixmapinproject/>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/qtruby/rubylib/designer/examples/colortool/findform.ui.rb b/qtruby/rubylib/designer/examples/colortool/findform.ui.rb
new file mode 100644
index 00000000..6bfb4f0a
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/findform.ui.rb
@@ -0,0 +1,11 @@
+class FindForm
+
+def find()
+ emit lookfor( @findLineEdit.text() )
+end
+
+def notfound()
+ @findLineEdit.selectAll()
+end
+
+end
diff --git a/qtruby/rubylib/designer/examples/colortool/images/editcopy b/qtruby/rubylib/designer/examples/colortool/images/editcopy
new file mode 100644
index 00000000..7b334ca4
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/editcopy
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/editcopy.png b/qtruby/rubylib/designer/examples/colortool/images/editcopy.png
new file mode 100644
index 00000000..abfe86e2
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/editcopy.png
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/editcut b/qtruby/rubylib/designer/examples/colortool/images/editcut
new file mode 100644
index 00000000..60abc586
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/editcut
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/editcut.png b/qtruby/rubylib/designer/examples/colortool/images/editcut.png
new file mode 100644
index 00000000..98efe27a
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/editcut.png
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/editraise.png b/qtruby/rubylib/designer/examples/colortool/images/editraise.png
new file mode 100644
index 00000000..02415689
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/editraise.png
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/filenew b/qtruby/rubylib/designer/examples/colortool/images/filenew
new file mode 100644
index 00000000..9de6e839
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/filenew
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/filenew.png b/qtruby/rubylib/designer/examples/colortool/images/filenew.png
new file mode 100644
index 00000000..8577f068
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/filenew.png
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/fileopen b/qtruby/rubylib/designer/examples/colortool/images/fileopen
new file mode 100644
index 00000000..a21f9466
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/fileopen
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/fileopen.png b/qtruby/rubylib/designer/examples/colortool/images/fileopen.png
new file mode 100644
index 00000000..85dab435
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/fileopen.png
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/filesave b/qtruby/rubylib/designer/examples/colortool/images/filesave
new file mode 100644
index 00000000..f6d9af92
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/filesave
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/filesave.png b/qtruby/rubylib/designer/examples/colortool/images/filesave.png
new file mode 100644
index 00000000..21309aa6
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/filesave.png
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/iconview.png b/qtruby/rubylib/designer/examples/colortool/images/iconview.png
new file mode 100644
index 00000000..d755399d
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/iconview.png
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/richtextedit.png b/qtruby/rubylib/designer/examples/colortool/images/richtextedit.png
new file mode 100644
index 00000000..9f75c258
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/richtextedit.png
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/searchfind b/qtruby/rubylib/designer/examples/colortool/images/searchfind
new file mode 100644
index 00000000..7aaefe22
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/searchfind
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/searchfind.png b/qtruby/rubylib/designer/examples/colortool/images/searchfind.png
new file mode 100644
index 00000000..8f7d8adb
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/searchfind.png
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/table.png b/qtruby/rubylib/designer/examples/colortool/images/table.png
new file mode 100644
index 00000000..663b32f0
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/table.png
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/tabwidget.png b/qtruby/rubylib/designer/examples/colortool/images/tabwidget.png
new file mode 100644
index 00000000..3a160446
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/tabwidget.png
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/images/widgetstack.png b/qtruby/rubylib/designer/examples/colortool/images/widgetstack.png
new file mode 100644
index 00000000..979409cf
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/images/widgetstack.png
Binary files differ
diff --git a/qtruby/rubylib/designer/examples/colortool/main.rb b/qtruby/rubylib/designer/examples/colortool/main.rb
new file mode 100644
index 00000000..9ebe84cb
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/main.rb
@@ -0,0 +1,20 @@
+require 'Qt'
+
+require 'mainform.rb'
+require 'mainform.ui.rb'
+
+require 'colornameform.rb'
+require 'colornameform.ui.rb'
+
+require 'optionsform.rb'
+
+require 'findform.rb'
+require 'findform.ui.rb'
+
+require 'qmake_image_collection.rb'
+
+a = Qt::Application.new(ARGV)
+w = MainForm.new
+a.mainWidget = w
+w.show
+a.exec
diff --git a/qtruby/rubylib/designer/examples/colortool/mainform.ui b/qtruby/rubylib/designer/examples/colortool/mainform.ui
new file mode 100644
index 00000000..6c89baca
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/mainform.ui
@@ -0,0 +1,601 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>MainForm</class>
+<widget class="QMainWindow">
+ <property name="name">
+ <cstring>MainForm</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Color Tool</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QWidgetStack">
+ <property name="name">
+ <cstring>colorWidgetStack</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tablePage</cstring>
+ </property>
+ <attribute name="id">
+ <number>0</number>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTable">
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Hex</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Web</string>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>colorTable</cstring>
+ </property>
+ <property name="numRows">
+ <number>0</number>
+ </property>
+ <property name="numCols">
+ <number>3</number>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>iconsPage</cstring>
+ </property>
+ <attribute name="id">
+ <number>1</number>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QIconView">
+ <property name="name">
+ <cstring>colorIconView</cstring>
+ </property>
+ <property name="gridX">
+ <number>100</number>
+ </property>
+ <property name="resizeMode">
+ <enum>Adjust</enum>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ </hbox>
+</widget>
+<menubar>
+ <property name="name">
+ <cstring>menubar</cstring>
+ </property>
+ <item text="&amp;File" name="fileMenu">
+ <action name="fileNewAction"/>
+ <action name="fileOpenAction"/>
+ <action name="fileSaveAction"/>
+ <action name="fileSaveAsAction"/>
+ <separator/>
+ <action name="fileExitAction"/>
+ </item>
+ <item text="&amp;Edit" name="editMenu">
+ <action name="editAddAction"/>
+ <action name="editCutAction"/>
+ <action name="editCopyAction"/>
+ <separator/>
+ <action name="editFindAction"/>
+ <separator/>
+ <action name="optionsAction"/>
+ </item>
+ <item text="&amp;View" name="viewMenu">
+ <action name="viewTableAction"/>
+ <action name="viewIconsAction"/>
+ </item>
+ <item text="&amp;Help" name="helpMenu">
+ <action name="helpContentsAction"/>
+ <action name="helpIndexAction"/>
+ <separator/>
+ <action name="helpAboutAction"/>
+ </item>
+</menubar>
+<toolbars>
+ <toolbar dock="2">
+ <property name="name">
+ <cstring>toolBar</cstring>
+ </property>
+ <property name="label">
+ <string>Tools</string>
+ </property>
+ <action name="fileNewAction"/>
+ <action name="fileOpenAction"/>
+ <action name="fileSaveAction"/>
+ <separator/>
+ <action name="editAddAction"/>
+ <action name="editCutAction"/>
+ <action name="editCopyAction"/>
+ <action name="editFindAction"/>
+ <separator/>
+ <action name="optionsAction"/>
+ <separator/>
+ <action name="viewTableAction"/>
+ <action name="viewIconsAction"/>
+ </toolbar>
+</toolbars>
+<actions>
+ <action>
+ <property name="name">
+ <cstring>fileNewAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>filenew.png</iconset>
+ </property>
+ <property name="text">
+ <string>New</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;New</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+N</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>fileOpenAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>fileopen.png</iconset>
+ </property>
+ <property name="text">
+ <string>Open</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Open...</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+O</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>fileSaveAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>filesave.png</iconset>
+ </property>
+ <property name="text">
+ <string>Save</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Save</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+S</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>fileSaveAsAction</cstring>
+ </property>
+ <property name="text">
+ <string>Save As</string>
+ </property>
+ <property name="menuText">
+ <string>Save &amp;As...</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>fileExitAction</cstring>
+ </property>
+ <property name="text">
+ <string>Exit</string>
+ </property>
+ <property name="menuText">
+ <string>E&amp;xit</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>editCutAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>editcut.png</iconset>
+ </property>
+ <property name="text">
+ <string>Delete</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Delete</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+X</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>editCopyAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>editcopy.png</iconset>
+ </property>
+ <property name="text">
+ <string>Copy</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Copy</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+C</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>editFindAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>searchfind.png</iconset>
+ </property>
+ <property name="text">
+ <string>Find</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Find...</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+F</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>helpContentsAction</cstring>
+ </property>
+ <property name="text">
+ <string>Contents</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Contents...</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>helpIndexAction</cstring>
+ </property>
+ <property name="text">
+ <string>Index</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Index...</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>helpAboutAction</cstring>
+ </property>
+ <property name="text">
+ <string>About</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;About</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>optionsAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>tabwidget.png</iconset>
+ </property>
+ <property name="text">
+ <string>Options</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Options...</string>
+ </property>
+ </action>
+ <actiongroup>
+ <property name="name">
+ <cstring>viewActionGroup</cstring>
+ </property>
+ <property name="text">
+ <string>View</string>
+ </property>
+ <property name="menuText">
+ <string>View</string>
+ </property>
+ <property name="usesDropDown">
+ <bool>false</bool>
+ </property>
+ <action>
+ <property name="name">
+ <cstring>viewTableAction</cstring>
+ </property>
+ <property name="toggleAction">
+ <bool>true</bool>
+ </property>
+ <property name="on">
+ <bool>true</bool>
+ </property>
+ <property name="iconSet">
+ <iconset>table.png</iconset>
+ </property>
+ <property name="text">
+ <string>View Table</string>
+ </property>
+ <property name="menuText">
+ <string>View &amp;Table</string>
+ </property>
+ <property name="toolTip">
+ <string>View Table (Ctrl+T)</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+T</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>viewIconsAction</cstring>
+ </property>
+ <property name="toggleAction">
+ <bool>true</bool>
+ </property>
+ <property name="iconSet">
+ <iconset>iconview.png</iconset>
+ </property>
+ <property name="text">
+ <string>View Icons</string>
+ </property>
+ <property name="menuText">
+ <string>View &amp;Icons</string>
+ </property>
+ <property name="toolTip">
+ <string>View Icons (Ctrl+I)</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+I</string>
+ </property>
+ </action>
+ </actiongroup>
+ <action>
+ <property name="name">
+ <cstring>editAddAction</cstring>
+ </property>
+ <property name="iconSet">
+ <iconset>widgetstack.png</iconset>
+ </property>
+ <property name="text">
+ <string>Add</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Add...</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+A</string>
+ </property>
+ </action>
+</actions>
+<connections>
+ <connection>
+ <sender>fileNewAction</sender>
+ <signal>activated()</signal>
+ <receiver>MainForm</receiver>
+ <slot>fileNew()</slot>
+ </connection>
+ <connection>
+ <sender>fileOpenAction</sender>
+ <signal>activated()</signal>
+ <receiver>MainForm</receiver>
+ <slot>fileOpen()</slot>
+ </connection>
+ <connection>
+ <sender>fileSaveAction</sender>
+ <signal>activated()</signal>
+ <receiver>MainForm</receiver>
+ <slot>fileSave()</slot>
+ </connection>
+ <connection>
+ <sender>fileSaveAsAction</sender>
+ <signal>activated()</signal>
+ <receiver>MainForm</receiver>
+ <slot>fileSaveAs()</slot>
+ </connection>
+ <connection>
+ <sender>fileExitAction</sender>
+ <signal>activated()</signal>
+ <receiver>MainForm</receiver>
+ <slot>fileExit()</slot>
+ </connection>
+ <connection>
+ <sender>editCutAction</sender>
+ <signal>activated()</signal>
+ <receiver>MainForm</receiver>
+ <slot>editCut()</slot>
+ </connection>
+ <connection>
+ <sender>editCopyAction</sender>
+ <signal>activated()</signal>
+ <receiver>MainForm</receiver>
+ <slot>editCopy()</slot>
+ </connection>
+ <connection>
+ <sender>editFindAction</sender>
+ <signal>activated()</signal>
+ <receiver>MainForm</receiver>
+ <slot>editFind()</slot>
+ </connection>
+ <connection>
+ <sender>helpIndexAction</sender>
+ <signal>activated()</signal>
+ <receiver>MainForm</receiver>
+ <slot>helpIndex()</slot>
+ </connection>
+ <connection>
+ <sender>helpContentsAction</sender>
+ <signal>activated()</signal>
+ <receiver>MainForm</receiver>
+ <slot>helpContents()</slot>
+ </connection>
+ <connection>
+ <sender>helpAboutAction</sender>
+ <signal>activated()</signal>
+ <receiver>MainForm</receiver>
+ <slot>helpAbout()</slot>
+ </connection>
+ <connection>
+ <sender>colorTable</sender>
+ <signal>currentChanged(int,int)</signal>
+ <receiver>MainForm</receiver>
+ <slot>changedTableColor(int,int)</slot>
+ </connection>
+ <connection>
+ <sender>colorIconView</sender>
+ <signal>currentChanged(QIconViewItem*)</signal>
+ <receiver>MainForm</receiver>
+ <slot>changedIconColor(QIconViewItem*)</slot>
+ </connection>
+ <connection>
+ <sender>viewActionGroup</sender>
+ <signal>selected(QAction*)</signal>
+ <receiver>MainForm</receiver>
+ <slot>changeView(QAction*)</slot>
+ </connection>
+ <connection>
+ <sender>editAddAction</sender>
+ <signal>activated()</signal>
+ <receiver>MainForm</receiver>
+ <slot>editAdd()</slot>
+ </connection>
+ <connection>
+ <sender>optionsAction</sender>
+ <signal>activated()</signal>
+ <receiver>MainForm</receiver>
+ <slot>editOptions()</slot>
+ </connection>
+ <connection>
+ <sender>colorWidgetStack</sender>
+ <signal>aboutToShow(int)</signal>
+ <receiver>MainForm</receiver>
+ <slot>aboutToShow()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in declaration">findform.h</include>
+ <include location="local" impldecl="in implementation">qsettings.h</include>
+ <include location="local" impldecl="in implementation">qradiobutton.h</include>
+ <include location="local" impldecl="in implementation">qcheckbox.h</include>
+ <include location="local" impldecl="in implementation">colornameform.h</include>
+ <include location="local" impldecl="in implementation">qcolordialog.h</include>
+ <include location="local" impldecl="in implementation">qregexp.h</include>
+ <include location="local" impldecl="in implementation">qfile.h</include>
+ <include location="local" impldecl="in implementation">qfiledialog.h</include>
+ <include location="local" impldecl="in implementation">qapplication.h</include>
+ <include location="local" impldecl="in implementation">qcolor.h</include>
+ <include location="local" impldecl="in implementation">qstring.h</include>
+ <include location="local" impldecl="in implementation">qpainter.h</include>
+ <include location="local" impldecl="in implementation">qstatusbar.h</include>
+ <include location="local" impldecl="in implementation">qmessagebox.h</include>
+ <include location="local" impldecl="in implementation">qclipboard.h</include>
+ <include location="local" impldecl="in implementation">qlabel.h</include>
+ <include location="local" impldecl="in implementation">qlineedit.h</include>
+ <include location="local" impldecl="in implementation">optionsform.h</include>
+ <include location="local" impldecl="in implementation">mainform.ui.h</include>
+</includes>
+<forwards>
+ <forward>class QString;</forward>
+ <forward>class QColor;</forward>
+</forwards>
+<variables>
+ <variable>QStringList m_comments;</variable>
+ <variable>QString m_filename;</variable>
+ <variable>bool m_changed;</variable>
+ <variable>bool m_table_dirty;</variable>
+ <variable>bool m_icons_dirty;</variable>
+ <variable>int m_clip_as;</variable>
+ <variable>bool m_show_web;</variable>
+ <variable>QClipboard *clipboard;</variable>
+ <variable>FindForm *findForm;</variable>
+ <variable>QMap&lt;QString,QColor&gt; m_colors;</variable>
+</variables>
+<slots>
+ <slot>fileNew()</slot>
+ <slot>fileOpen()</slot>
+ <slot>fileSave()</slot>
+ <slot>fileSaveAs()</slot>
+ <slot>closeEvent( QCloseEvent * )</slot>
+ <slot>fileExit()</slot>
+ <slot>editCut()</slot>
+ <slot>editCopy()</slot>
+ <slot>editFind()</slot>
+ <slot>lookfor( const QString &amp; text )</slot>
+ <slot>helpIndex()</slot>
+ <slot>helpContents()</slot>
+ <slot>helpAbout()</slot>
+ <slot>changedTableColor( int row, int )</slot>
+ <slot>changedIconColor( QIconViewItem * item )</slot>
+ <slot>changeView( QAction * action )</slot>
+ <slot>editAdd()</slot>
+ <slot>editOptions()</slot>
+ <slot>aboutToShow()</slot>
+</slots>
+<functions>
+ <function access="private">init()</function>
+ <function>clearData( bool fillWithDefaults )</function>
+ <function>populate()</function>
+ <function returnType="QPixmap">colorSwatch( const QColor color )</function>
+ <function>load( const QString &amp; filename )</function>
+ <function returnType="bool">okToClear()</function>
+ <function>changedColor( const QString &amp; name )</function>
+ <function returnType="bool">isWebColor( QColor color )</function>
+ <function>loadSettings()</function>
+ <function>saveSettings()</function>
+</functions>
+<pixmapinproject/>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/qtruby/rubylib/designer/examples/colortool/mainform.ui.rb b/qtruby/rubylib/designer/examples/colortool/mainform.ui.rb
new file mode 100644
index 00000000..471233bd
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/mainform.ui.rb
@@ -0,0 +1,530 @@
+class MainForm
+
+ CLIP_AS_HEX = 0
+ CLIP_AS_NAME = 1
+ CLIP_AS_RGB = 2
+ COL_NAME = 0
+ COL_HEX = 1
+ COL_WEB = 2
+ WINDOWS_REGISTRY = "/QtExamples"
+ APP_KEY = "/ColorTool/"
+
+def init()
+ @clipboard = Qt::Application.clipboard()
+ if @clipboard.supportsSelection()
+ @clipboard.selectionMode = true
+ end
+
+ findForm = 0
+ loadSettings()
+ @filename = nil
+ @changed = false
+ @table_dirty = true
+ @icons_dirty = true
+ @colors = {}
+ @comments = {}
+ clearData( true )
+end
+
+def clearData( fillWithDefaults )
+ setCaption( "Color Tool" )
+
+ @colors.clear()
+ @comments.clear()
+
+ if fillWithDefaults
+ @colors["black"] = Qt::black
+ @colors["blue"] = Qt::blue
+ @colors["cyan"] = Qt::cyan
+ @colors["darkblue"] = Qt::darkBlue
+ @colors["darkcyan"] = Qt::darkCyan
+ @colors["darkgray"] = Qt::darkGray
+ @colors["darkgreen"] = Qt::darkGreen
+ @colors["darkmagenta"] = Qt::darkMagenta
+ @colors["darkred"] = Qt::darkRed
+ @colors["darkyellow"] = Qt::darkYellow
+ @colors["gray"] = Qt::gray
+ @colors["green"] = Qt::green
+ @colors["lightgray"] = Qt::lightGray
+ @colors["magenta"] = Qt::magenta
+ @colors["red"] = Qt::red
+ @colors["white"] = Qt::white
+ @colors["yellow"] = Qt::yellow
+ end
+
+ populate()
+end
+
+def populate()
+ if @table_dirty
+ (0...@colorTable.numRows).each do |r|
+ (0...@colorTable.numCols).each do |c|
+ @colorTable.clearCell( r, c )
+ end
+ end
+
+ @colorTable.numRows = @colors.length
+ if ! @colors.empty?
+ pixmap = Qt::Pixmap.new( 22, 22 )
+ row = 0
+ @colors.sort.each do |pair|
+ key = pair[0]
+ color = pair[1]
+ pixmap.fill( color )
+ @colorTable.setText( row, COL_NAME, key )
+ @colorTable.setPixmap( row, COL_NAME, pixmap );
+ @colorTable.setText( row, COL_HEX, color.name().upcase() )
+ if @show_web
+ item = Qt::CheckTableItem.new( @colorTable, "" )
+ item.checked = webColor?( color )
+ @colorTable.setItem( row, COL_WEB, item )
+ end
+ row += 1
+ end
+ @colorTable.setCurrentCell( 0, 0 )
+ end
+ @colorTable.adjustColumn( COL_NAME )
+ @colorTable.adjustColumn( COL_HEX )
+ if @show_web
+ @colorTable.showColumn( COL_WEB )
+ @colorTable.adjustColumn( COL_WEB )
+ else
+ @colorTable.hideColumn( COL_WEB )
+ end
+ @table_dirty = FALSE;
+ end
+
+ if @icons_dirty
+ @colorIconView.clear()
+
+ @colors.each do |key, data|
+ Qt::IconViewItem.new( @colorIconView, key, colorSwatch(data) )
+ end
+ @icons_dirty = false
+ end
+end
+
+def colorSwatch( color )
+ pixmap = Qt::Pixmap.new( 80, 80 )
+ pixmap.fill( white )
+ painter = Qt::Painter.new
+ painter.begin( pixmap )
+ painter.pen = NoPen
+ painter.brush = color
+ painter.drawEllipse( 0, 0, 80, 80 )
+ painter.end()
+ return pixmap
+end
+
+def fileNew()
+ if okToClear()
+ @filename = nil
+ @changed = false
+ @table_dirty = true
+ @icons_dirty = true
+ clearData( false )
+ end
+end
+
+def fileOpen()
+ if ! okToClear()
+ return
+ end
+
+ filename = Qt::FileDialog.getOpenFileName(
+ nil, "Colors (*.txt)", self,
+ "file open", "Color Tool -- File Open" )
+ if ! filename.nil?
+ load( filename )
+ else
+ statusBar().message( "File Open abandoned", 2000 )
+ end
+end
+
+def fileSave()
+ if @filename.nil?
+ fileSaveAs()
+ return
+ end
+
+ file = Qt::File.new( @filename )
+ if file.open( Qt::IO_WriteOnly )
+ stream = Qt::TextStream.new( file )
+ if ! @comments.empty?
+ stream << @comments + "\n" << "\n"
+ end
+
+ @colors.each do |key, color|
+ stream << "%3d %3d %3d \t\t#{key}" % [color.red, color.green, color.blue] << "\n"
+ end
+ file.close()
+ setCaption( "Color Tool -- #{@filename}" )
+ statusBar().message( "Saved #{@colors.length} colors to '#{@filename}'", 3000 )
+ @changed = false;
+ else
+ statusBar().message( "Failed to save '#{@filename}'", 3000 )
+ end
+end
+
+def fileSaveAs()
+ filename = Qt::FileDialog.getSaveFileName(
+ nil, "Colors (*.txt)", self,
+ "file save as", "Color Tool -- File Save As" )
+ if ! filename.nil?
+ ans = 0
+ if Qt::File.exists( filename )
+ ans = Qt::MessageBox.warning(
+ self, "Color Tool -- Overwrite File",
+ "Overwrite\n'#{filename}'?" ,
+ "&Yes", "&No", nil, 1, 1 )
+ end
+ if ans == 0
+ @filename = filename
+ fileSave()
+ return
+ end
+ end
+ statusBar().message( "Saving abandoned", 2000 )
+end
+
+def load( filename )
+ clearData( false )
+ @filename = filename
+ regex = Regexp.new( "^\\s*(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\S+.*)$" )
+ file = Qt::File.new( filename )
+ if file.open( Qt::IO_ReadOnly )
+ statusBar().message( "Loading '#{filename}'..." )
+ stream = Qt::TextStream.new( file )
+ while ! stream.eof()
+ line = stream.readLine()
+ m = regex.match( line )
+ if m.nil?
+ @comments += line
+ else
+ @colors[m[4]] = Qt::Color.new(m[1].to_i,m[2].to_i,m[3].to_i )
+ end
+ end
+ file.close()
+ @filename = filename
+ setCaption( "Color Tool -- #{@filename}" )
+ statusBar().message( "Loaded '#{@filename}'", 3000 )
+ visible = @colorWidgetStack.visibleWidget()
+ @icons_dirty = ! ( @table_dirty = ( visible == @tablePage ) )
+ populate()
+ @icons_dirty = ! ( @table_dirty = ( visible != @tablePage ) )
+ @changed = false
+ else
+ statusBar().message( "Failed to load '#{@filename}'", 3000 )
+ end
+end
+
+
+def okToClear()
+ if @changed
+ if @filename.nil?
+ msg = "Unnamed colors "
+ else
+ msg = "Colors '#{@filename}'\n"
+ end
+ msg += "has been changed."
+ ans = Qt::MessageBox.information(
+ self,
+ "Color Tool -- Unsaved Changes",
+ msg, "&Save", "Cancel", "&Abandon",
+ 0, 1 )
+ if ans == 0
+ fileSave()
+ elsif ans == 1
+ return false
+ end
+ end
+
+ return true
+end
+
+def closeEvent( e )
+ fileExit()
+end
+
+def fileExit()
+ if okToClear()
+ saveSettings()
+ Qt::Application.exit( 0 )
+ end
+end
+
+def editCut()
+ visible = @colorWidgetStack.visibleWidget()
+ statusBar().message( "Deleting '#{name}'" )
+
+ if visible == @tablePage && @colorTable.numRows() > 0
+ row = @colorTable.currentRow()
+ name = @colorTable.text( row, 0 )
+ @colorTable.removeRow( @colorTable.currentRow() )
+ if row < @colorTable.numRows()
+ @colorTable.setCurrentCell( row, 0 )
+ elsif @colorTable.numRows() > 0
+ @colorTable.setCurrentCell( @colorTable.numRows() - 1, 0 )
+ end
+ @icons_dirty = true
+ elsif visible == @iconsPage && @colorIconView.currentItem()
+ item = colorIconView.currentItem()
+ name = item.text()
+ if @colorIconView.count() == 1
+ @colorIconView.clear()
+ else
+ current = item.nextItem()
+ if ! current
+ current = item.prevItem()
+ end
+ item.dispose
+ if current
+ @colorIconView.currentItem = current
+ end
+ @colorIconView.arrangeItemsInGrid()
+ end
+ @table_dirty = true
+ end
+
+ if ! name.nil?
+ @colors.delete( name )
+ @changed = true
+ statusBar().message( "Deleted '#{name}'", 5000 )
+ else
+ statusBar().message( "Failed to delete '#{name}'", 5000 )
+ end
+end
+
+def editCopy()
+ visible = @colorWidgetStack.visibleWidget()
+
+ if visible == @tablePage && @colorTable.numRows()
+ row = @colorTable.currentRow()
+ text = @colorTable.text( row, 0 )
+ elsif visible == @iconsPage && ! @colorIconView.currentItem().nil?
+ item = @colorIconView.currentItem()
+ text = item.text()
+ end
+ if ! text.nil?
+ color = @colors[text]
+ case @clip_as
+ when CLIP_AS_HEX then text = color.name()
+ when CLIP_AS_NAME then
+ when CLIP_AS_RGB
+ text = "#{color.red},#{color.green},#{color.blue}"
+ end
+ @clipboard.text = text
+ statusBar().message( "Copied '" + text + "' to the clipboard" )
+ end
+end
+
+def editFind()
+ if ! @findForm
+ @findForm = FindForm.new( self )
+ connect( @findForm, SIGNAL( 'lookfor(const QString&)' ),
+ self, SLOT( 'lookfor(const QString&)' ) )
+ end
+ @findForm.show()
+end
+
+def lookfor( text )
+ if text.empty?
+ return
+ end
+ ltext = text.downcase()
+ visible = colorWidgetStack.visibleWidget()
+ found = false
+
+ if visible == @tablePage && @colorTable.numRows() > 0
+ row = @colorTable.currentRow()
+ (row+1...@colorTable.numRows).each do |i|
+ if @colorTable.text( i, 0 ).downcase().include?( ltext )
+ @colorTable.setCurrentCell( i, 0 )
+ @colorTable.clearSelection()
+ @colorTable.selectRow( i )
+ found = true
+ break
+ end
+ end
+ if ! found
+ @colorTable.setCurrentCell( row, 0 )
+ end
+ elsif visible == @iconsPage
+ start = @colorIconView.currentItem()
+ item = start.nextItem() unless start.nil?
+ while !item.nil?
+ if item.text().downcase().include?( ltext )
+ @colorIconView.currentItem = item
+ @colorIconView.ensureItemVisible( item )
+ found = true
+ break
+ end
+ item = item.nextItem()
+ end
+ if ! found && !start.nil?
+ @colorIconView.currentItem = start
+ end
+ end
+ if ! found
+ statusBar().message( "Could not find '#{text}' after here" )
+ @findForm.notfound()
+ end
+end
+
+
+
+def helpIndex()
+end
+
+def helpContents()
+end
+
+def helpAbout()
+end
+
+
+def changedTableColor( row, i )
+ changedColor( @colorTable.text( row, COL_NAME ) )
+end
+
+def changedIconColor( item )
+ changedColor( item.text() )
+end
+
+def changedColor( name )
+ color = @colors[name]
+ r = color.red()
+ g = color.green()
+ b = color.blue()
+ statusBar().message( "%s \"%s\" (%d,%d,%d) %s {%.3f %.3f %.3f}" %
+ [name, color.name.upcase,
+ r, g, b, webColor?( color ) ? ' web' : '',
+ r / 255.0, g / 255.0, b / 255.0] )
+end
+
+def changeView(action)
+ if action == @viewTableAction
+ @colorWidgetStack.raiseWidget( @tablePage )
+ else
+ @colorWidgetStack.raiseWidget( @iconsPage )
+ end
+end
+
+def webColor?( color )
+ r = color.red()
+ g = color.green()
+ b = color.blue()
+
+ return ( ( r == 0 || r == 51 || r == 102 ||
+ r == 153 || r == 204 || r == 255 ) &&
+ ( g == 0 || g == 51 || g == 102 ||
+ g == 153 || g == 204 || g == 255 ) &&
+ ( b == 0 || b == 51 || b == 102 ||
+ b == 153 || b == 204 || b == 255 ) )
+end
+
+
+def editAdd()
+ color = Qt::white
+ if ! @colors.empty?
+ visible = @colorWidgetStack.visibleWidget()
+ if visible == @tablePage
+ color = Qt::Color.new(@colorTable.text( @colorTable.currentRow(),
+ @colorTable.currentColumn() ))
+ else
+ color = Qt::Color.new(@colorIconView.currentItem().text())
+ end
+ end
+ color = Qt::ColorDialog.getColor( color, self )
+ if color.valid?
+ pixmap = Qt::Pixmap.new( 80, 10 )
+ pixmap.fill( color )
+ colorForm = ColorNameForm.new( self, "color", true )
+ colorForm.setColors( @colors )
+ colorForm.colorLabel.setPixmap( pixmap )
+ if colorForm.exec()
+ name = colorForm.colorLineEdit.text()
+ @colors[name] = color
+ pixmap = Qt::Pixmap.new( 22, 22 )
+ pixmap.fill( color )
+ row = @colorTable.currentRow()
+ @colorTable.insertRows( row, 1 )
+ @colorTable.setText( row, COL_NAME, name )
+ @colorTable.setPixmap( row, COL_NAME, pixmap )
+ @colorTable.setText( row, COL_HEX, color.name().upcase() )
+ if @show_web
+ item = Qt::CheckTableItem.new( @colorTable, "" )
+ item.checked = webColor?( color )
+ @colorTable.setItem( row, COL_WEB, item )
+ end
+ @colorTable.setCurrentCell( row, 0 )
+
+ Qt::IconViewItem.new( @colorIconView, name,
+ colorSwatch( color ) )
+ @changed = true
+ end
+ end
+end
+
+def editOptions()
+ options = OptionsForm.new( self, "options", true )
+ case @clip_as
+ when CLIP_AS_HEX
+ options.hexRadioButton.checked = true
+ when CLIP_AS_NAME
+ options.nameRadioButton.checked = true
+ when CLIP_AS_RGB
+ options.rgbRadioButton.checked = true
+ end
+ options.webCheckBox.checked = @show_web
+
+ if options.exec()
+ if options.hexRadioButton.checked?
+ @clip_as = CLIP_AS_HEX
+ elsif options.nameRadioButton.checked?
+ @clip_as = CLIP_AS_NAME
+ elsif options.rgbRadioButton.checked?
+ @clip_as = CLIP_AS_RGB
+ end
+ @table_dirty = @show_web != options.webCheckBox.checked?
+ @show_web = options.webCheckBox.checked?
+ populate()
+ end
+end
+
+def loadSettings()
+ settings = Qt::Settings.new
+ settings.insertSearchPath( Qt::Settings::Windows, WINDOWS_REGISTRY )
+ windowWidth = settings.readNumEntry( APP_KEY + "WindowWidth", 550 )
+ windowHeight = settings.readNumEntry( APP_KEY + "WindowHeight", 500 )
+ windowX = settings.readNumEntry( APP_KEY + "WindowX", 0 )
+ windowY = settings.readNumEntry( APP_KEY + "WindowY", 0 )
+ @clip_as = settings.readNumEntry( APP_KEY + "ClipAs", CLIP_AS_HEX )
+ @show_web = settings.readBoolEntry( APP_KEY + "ShowWeb", true )
+ if ! settings.readBoolEntry( APP_KEY + "View", true )
+ @colorWidgetStack.raiseWidget( @iconsPage )
+ @viewIconsAction.on = true
+ end
+
+ resize( windowWidth, windowHeight )
+ move( windowX, windowY )
+end
+
+def saveSettings()
+ settings = Qt::Settings.new
+ settings.insertSearchPath( Qt::Settings::Windows, WINDOWS_REGISTRY )
+ settings.writeEntry( APP_KEY + "WindowWidth", width() )
+ settings.writeEntry( APP_KEY + "WindowHeight", height() )
+ settings.writeEntry( APP_KEY + "WindowX", x() )
+ settings.writeEntry( APP_KEY + "WindowY", y() )
+ settings.writeEntry( APP_KEY + "ClipAs", @clip_as )
+ settings.writeEntry( APP_KEY + "ShowWeb", @show_web )
+ settings.writeEntry( APP_KEY + "View", @colorWidgetStack.visibleWidget() == @tablePage )
+end
+
+
+def aboutToShow()
+ populate()
+end
+
+end
diff --git a/qtruby/rubylib/designer/examples/colortool/optionsform.ui b/qtruby/rubylib/designer/examples/colortool/optionsform.ui
new file mode 100644
index 00000000..1bb7e8ef
--- /dev/null
+++ b/qtruby/rubylib/designer/examples/colortool/optionsform.ui
@@ -0,0 +1,153 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>OptionsForm</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>OptionsForm</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>306</width>
+ <height>226</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Color Tool - Options</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Table View</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>webCheckBox</cstring>
+ </property>
+ <property name="text">
+ <string>Indicate &amp;Web colors</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Copy to Clipboard As</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>hexRadioButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Hex, e.g. #AB347F</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>nameRadioButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Name, e.g. light blue</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>rgbRadioButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;RGB, e.g. 51,255,102</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>okPushButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>cancelPushButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>okPushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>OptionsForm</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>cancelPushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>OptionsForm</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">optionsform.ui.h</include>
+</includes>
+<pixmapinproject/>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/qtruby/rubylib/designer/rbuic/LICENSE.GPL b/qtruby/rubylib/designer/rbuic/LICENSE.GPL
new file mode 100644
index 00000000..3e51afd8
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/LICENSE.GPL
@@ -0,0 +1,280 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/qtruby/rubylib/designer/rbuic/Makefile.am b/qtruby/rubylib/designer/rbuic/Makefile.am
new file mode 100644
index 00000000..a8eef55d
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/Makefile.am
@@ -0,0 +1,24 @@
+AM_CPPFLAGS = -DUIC -DQT_INTERNAL_XML
+AM_CXXFLAGS = $(KDE_CXXFLAGS)
+
+bin_PROGRAMS = rbuic
+noinst_LTLIBRARIES = librbuic.la
+
+INCLUDES = $(all_includes)
+
+METASOURCES = AUTO
+
+librbuic_la_SOURCES = widgetdatabase.cpp uic.cpp subclassing.cpp parser.cpp object.cpp form.cpp embed.cpp domtool.cpp
+librbuic_la_LIBADD = $(LIB_QT) $(LIBZ)
+
+rbuic_SOURCES = main.cpp
+rbuic_LDADD = librbuic.la $(all_libraries)
+rbuic_LDFLAGS =
+
+EXTRA_DIST = domtool.cpp domtool.h embed.cpp form.cpp globaldefs.h main.cpp object.cpp parser.cpp parser.h subclassing.cpp uic.cpp uic.h widgetdatabase.cpp widgetdatabase.h widgetinterface.h
+
+messages:
+ LIST=`find . -name \*.h -o -name \*.hh -o -name \*.H -o -name \*.hxx -o -name \*.hpp -o -name \*.cpp -o -name \*.cc -o -name \*.cxx -o -name \*.ecpp -o -name \*.C`; \
+ if test -n "$$LIST"; then \
+ $(XGETTEXT) $$LIST -o $(podir)/puic.pot; \
+ fi
diff --git a/qtruby/rubylib/designer/rbuic/TODO b/qtruby/rubylib/designer/rbuic/TODO
new file mode 100644
index 00000000..8e780973
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/TODO
@@ -0,0 +1,4 @@
+
+- Database code needs more testing?
+
+
diff --git a/qtruby/rubylib/designer/rbuic/domtool.cpp b/qtruby/rubylib/designer/rbuic/domtool.cpp
new file mode 100644
index 00000000..1c30486f
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/domtool.cpp
@@ -0,0 +1,453 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "domtool.h"
+
+#include <qsizepolicy.h>
+#include <qcolor.h>
+#include <qcursor.h>
+#include <qdatetime.h>
+#include <qrect.h>
+#include <qsize.h>
+#include <qfont.h>
+#include <qdom.h>
+
+/*!
+ \class DomTool domtool.h
+ \brief Tools for the dom
+
+ A collection of static functions used by Resource (part of the
+ designer) and Uic.
+
+*/
+
+/*!
+ Returns the contents of property \a name of object \a e as
+ variant or the variant passed as \a defValue if the property does
+ not exist.
+
+ \sa hasProperty()
+*/
+QVariant DomTool::readProperty( const QDomElement& e, const QString& name, const QVariant& defValue, QString& comment )
+{
+ QDomElement n;
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "property" ) {
+ if ( n.attribute( "name" ) != name )
+ continue;
+ return elementToVariant( n.firstChild().toElement(), defValue, comment );
+ }
+ }
+ return defValue;
+}
+
+
+/*!
+ \overload
+ */
+QVariant DomTool::readProperty( const QDomElement& e, const QString& name, const QVariant& defValue )
+{
+ QString comment;
+ return readProperty( e, name, defValue, comment );
+}
+
+/*!
+ Returns wheter object \a e defines property \a name or not.
+
+ \sa readProperty()
+ */
+bool DomTool::hasProperty( const QDomElement& e, const QString& name )
+{
+ QDomElement n;
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "property" ) {
+ if ( n.attribute( "name" ) != name )
+ continue;
+ return true;
+ }
+ }
+ return false;
+}
+
+QStringList DomTool::propertiesOfType( const QDomElement& e, const QString& type )
+{
+ QStringList result;
+ QDomElement n;
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "property" ) {
+ QDomElement n2 = n.firstChild().toElement();
+ if ( n2.tagName() == type )
+ result += n.attribute( "name" );
+ }
+ }
+ return result;
+}
+
+
+QVariant DomTool::elementToVariant( const QDomElement& e, const QVariant& defValue )
+{
+ QString dummy;
+ return elementToVariant( e, defValue, dummy );
+}
+
+/*!
+ Interprets element \a e as variant and returns the result of the interpretation.
+ */
+QVariant DomTool::elementToVariant( const QDomElement& e, const QVariant& defValue, QString &comment )
+{
+ QVariant v;
+ if ( e.tagName() == "rect" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ int x = 0, y = 0, w = 0, h = 0;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "x" )
+ x = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "y" )
+ y = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "width" )
+ w = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "height" )
+ h = n3.firstChild().toText().data().toInt();
+ n3 = n3.nextSibling().toElement();
+ }
+ v = QVariant( QRect( x, y, w, h ) );
+ } else if ( e.tagName() == "point" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ int x = 0, y = 0;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "x" )
+ x = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "y" )
+ y = n3.firstChild().toText().data().toInt();
+ n3 = n3.nextSibling().toElement();
+ }
+ v = QVariant( QPoint( x, y ) );
+ } else if ( e.tagName() == "size" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ int w = 0, h = 0;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "width" )
+ w = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "height" )
+ h = n3.firstChild().toText().data().toInt();
+ n3 = n3.nextSibling().toElement();
+ }
+ v = QVariant( QSize( w, h ) );
+ } else if ( e.tagName() == "color" ) {
+ v = QVariant( readColor( e ) );
+ } else if ( e.tagName() == "font" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ QFont f( defValue.toFont() );
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "family" )
+ f.setFamily( n3.firstChild().toText().data() );
+ else if ( n3.tagName() == "pointsize" )
+ f.setPointSize( n3.firstChild().toText().data().toInt() );
+ else if ( n3.tagName() == "bold" )
+ f.setBold( n3.firstChild().toText().data().toInt() );
+ else if ( n3.tagName() == "italic" )
+ f.setItalic( n3.firstChild().toText().data().toInt() );
+ else if ( n3.tagName() == "underline" )
+ f.setUnderline( n3.firstChild().toText().data().toInt() );
+ else if ( n3.tagName() == "strikeout" )
+ f.setStrikeOut( n3.firstChild().toText().data().toInt() );
+ n3 = n3.nextSibling().toElement();
+ }
+ v = QVariant( f );
+ } else if ( e.tagName() == "string" ) {
+ v = QVariant( e.firstChild().toText().data() );
+ QDomElement n = e;
+ n = n.nextSibling().toElement();
+ if ( n.tagName() == "comment" )
+ comment = n.firstChild().toText().data();
+ } else if ( e.tagName() == "cstring" ) {
+ v = QVariant( QCString( e.firstChild().toText().data() ) );
+ } else if ( e.tagName() == "number" ) {
+ bool ok = true;
+ v = QVariant( e.firstChild().toText().data().toInt( &ok ) );
+ if ( !ok )
+ v = QVariant( e.firstChild().toText().data().toDouble() );
+ } else if ( e.tagName() == "bool" ) {
+ QString t = e.firstChild().toText().data();
+ v = QVariant( t == "true" || t == "1", 0 );
+ } else if ( e.tagName() == "pixmap" ) {
+ v = QVariant( e.firstChild().toText().data() );
+ } else if ( e.tagName() == "iconset" ) {
+ v = QVariant( e.firstChild().toText().data() );
+ } else if ( e.tagName() == "image" ) {
+ v = QVariant( e.firstChild().toText().data() );
+ } else if ( e.tagName() == "enum" ) {
+ v = QVariant( e.firstChild().toText().data() );
+ } else if ( e.tagName() == "set" ) {
+ v = QVariant( e.firstChild().toText().data() );
+ } else if ( e.tagName() == "sizepolicy" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ QSizePolicy sp;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "hsizetype" )
+ sp.setHorData( (QSizePolicy::SizeType)n3.firstChild().toText().data().toInt() );
+ else if ( n3.tagName() == "vsizetype" )
+ sp.setVerData( (QSizePolicy::SizeType)n3.firstChild().toText().data().toInt() );
+ else if ( n3.tagName() == "horstretch" )
+ sp.setHorStretch( n3.firstChild().toText().data().toInt() );
+ else if ( n3.tagName() == "verstretch" )
+ sp.setVerStretch( n3.firstChild().toText().data().toInt() );
+ n3 = n3.nextSibling().toElement();
+ }
+ v = QVariant( sp );
+ } else if ( e.tagName() == "cursor" ) {
+ v = QVariant( QCursor( e.firstChild().toText().data().toInt() ) );
+ } else if ( e.tagName() == "stringlist" ) {
+ QStringList lst;
+ QDomElement n;
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() )
+ lst << n.firstChild().toText().data();
+ v = QVariant( lst );
+ } else if ( e.tagName() == "date" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ int y, m, d;
+ y = m = d = 0;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "year" )
+ y = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "month" )
+ m = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "day" )
+ d = n3.firstChild().toText().data().toInt();
+ n3 = n3.nextSibling().toElement();
+ }
+ v = QVariant( QDate( y, m, d ) );
+ } else if ( e.tagName() == "time" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ int h, m, s;
+ h = m = s = 0;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "hour" )
+ h = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "minute" )
+ m = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "second" )
+ s = n3.firstChild().toText().data().toInt();
+ n3 = n3.nextSibling().toElement();
+ }
+ v = QVariant( QTime( h, m, s ) );
+ } else if ( e.tagName() == "datetime" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ int h, mi, s, y, mo, d ;
+ h = mi = s = y = mo = d = 0;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "hour" )
+ h = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "minute" )
+ mi = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "second" )
+ s = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "year" )
+ y = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "month" )
+ mo = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "day" )
+ d = n3.firstChild().toText().data().toInt();
+ n3 = n3.nextSibling().toElement();
+ }
+ v = QVariant( QDateTime( QDate( y, mo, d ), QTime( h, mi, s ) ) );
+ }
+ return v;
+}
+
+
+/*! Returns the color which is returned in the dom element \a e.
+ */
+
+QColor DomTool::readColor( const QDomElement &e )
+{
+ QDomElement n = e.firstChild().toElement();
+ int r= 0, g = 0, b = 0;
+ while ( !n.isNull() ) {
+ if ( n.tagName() == "red" )
+ r = n.firstChild().toText().data().toInt();
+ else if ( n.tagName() == "green" )
+ g = n.firstChild().toText().data().toInt();
+ else if ( n.tagName() == "blue" )
+ b = n.firstChild().toText().data().toInt();
+ n = n.nextSibling().toElement();
+ }
+
+ return QColor( r, g, b );
+}
+
+/*!
+ Returns the contents of attribute \a name of object \a e as
+ variant or the variant passed as \a defValue if the attribute does
+ not exist.
+
+ \sa hasAttribute()
+ */
+QVariant DomTool::readAttribute( const QDomElement& e, const QString& name, const QVariant& defValue, QString& comment )
+{
+ QDomElement n;
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "attribute" ) {
+ if ( n.attribute( "name" ) != name )
+ continue;
+ return elementToVariant( n.firstChild().toElement(), defValue, comment );
+ }
+ }
+ return defValue;
+}
+
+/*!
+ \overload
+*/
+QVariant DomTool::readAttribute( const QDomElement& e, const QString& name, const QVariant& defValue )
+{
+ QString comment;
+ return readAttribute( e, name, defValue, comment );
+}
+
+/*!
+ Returns wheter object \a e defines attribute \a name or not.
+
+ \sa readAttribute()
+ */
+bool DomTool::hasAttribute( const QDomElement& e, const QString& name )
+{
+ QDomElement n;
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "attribute" ) {
+ if ( n.attribute( "name" ) != name )
+ continue;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool toBool( const QString& s )
+{
+ return s == "true" || s.toInt() != 0;
+}
+
+/*!
+ Convert Qt 2.x format to Qt 3.0 format if necessary
+*/
+void DomTool::fixDocument( QDomDocument& doc )
+{
+ QDomElement e;
+ QDomNode n;
+ QDomNodeList nl;
+ int i = 0;
+
+ e = doc.firstChild().toElement();
+ if ( e.tagName() != "UI" )
+ return;
+
+ // latest version, don't do anything
+ if ( e.hasAttribute("version") && e.attribute("version").toDouble() > 3.0 )
+ return;
+
+ nl = doc.elementsByTagName( "property" );
+
+ // in 3.0, we need to fix a spelling error
+ if ( e.hasAttribute("version") && e.attribute("version").toDouble() == 3.0 ) {
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ QDomElement el = nl.item(i).toElement();
+ QString s = el.attribute( "name" );
+ if ( s == "resizeable" ) {
+ el.removeAttribute( "name" );
+ el.setAttribute( "name", "resizable" );
+ }
+ }
+ return;
+ }
+
+
+ // in versions smaller than 3.0 we need to change more
+ e.setAttribute( "version", 3.0 );
+
+ e.setAttribute("stdsetdef", 1 );
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ e = nl.item(i).toElement();
+ QString name;
+ QDomElement n2 = e.firstChild().toElement();
+ if ( n2.tagName() == "name" ) {
+ name = n2.firstChild().toText().data();
+ if ( name == "resizeable" )
+ e.setAttribute( "name", "resizable" );
+ else
+ e.setAttribute( "name", name );
+ e.removeChild( n2 );
+ }
+ bool stdset = toBool( e.attribute( "stdset" ) );
+ if ( stdset || name == "toolTip" || name == "whatsThis" ||
+ name == "buddy" ||
+ e.parentNode().toElement().tagName() == "item" ||
+ e.parentNode().toElement().tagName() == "spacer" ||
+ e.parentNode().toElement().tagName() == "column"
+ )
+ e.removeAttribute( "stdset" );
+ else
+ e.setAttribute( "stdset", 0 );
+ }
+
+ nl = doc.elementsByTagName( "attribute" );
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ e = nl.item(i).toElement();
+ QString name;
+ QDomElement n2 = e.firstChild().toElement();
+ if ( n2.tagName() == "name" ) {
+ name = n2.firstChild().toText().data();
+ e.setAttribute( "name", name );
+ e.removeChild( n2 );
+ }
+ }
+
+ nl = doc.elementsByTagName( "image" );
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ e = nl.item(i).toElement();
+ QString name;
+ QDomElement n2 = e.firstChild().toElement();
+ if ( n2.tagName() == "name" ) {
+ name = n2.firstChild().toText().data();
+ e.setAttribute( "name", name );
+ e.removeChild( n2 );
+ }
+ }
+
+ nl = doc.elementsByTagName( "widget" );
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ e = nl.item(i).toElement();
+ QString name;
+ QDomElement n2 = e.firstChild().toElement();
+ if ( n2.tagName() == "class" ) {
+ name = n2.firstChild().toText().data();
+ e.setAttribute( "class", name );
+ e.removeChild( n2 );
+ }
+ }
+
+}
+
diff --git a/qtruby/rubylib/designer/rbuic/domtool.h b/qtruby/rubylib/designer/rbuic/domtool.h
new file mode 100644
index 00000000..61b4269a
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/domtool.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef DOMTOOL_H
+#define DOMTOOL_H
+
+#include <qvariant.h>
+#include <qnamespace.h>
+
+class QDomElement;
+class QDomDocument;
+
+class DomTool : public Qt
+{
+public:
+ static QVariant readProperty( const QDomElement& e, const QString& name, const QVariant& defValue );
+ static QVariant readProperty( const QDomElement& e, const QString& name, const QVariant& defValue, QString& comment );
+ static bool hasProperty( const QDomElement& e, const QString& name );
+ static QStringList propertiesOfType( const QDomElement& e, const QString& type );
+ static QVariant elementToVariant( const QDomElement& e, const QVariant& defValue );
+ static QVariant elementToVariant( const QDomElement& e, const QVariant& defValue, QString &comment );
+ static QVariant readAttribute( const QDomElement& e, const QString& name, const QVariant& defValue );
+ static QVariant readAttribute( const QDomElement& e, const QString& name, const QVariant& defValue, QString& comment );
+ static bool hasAttribute( const QDomElement& e, const QString& name );
+ static QColor readColor( const QDomElement &e );
+ static void fixDocument( QDomDocument& );
+};
+
+
+#endif // DOMTOOL_H
diff --git a/qtruby/rubylib/designer/rbuic/embed.cpp b/qtruby/rubylib/designer/rbuic/embed.cpp
new file mode 100644
index 00000000..89985968
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/embed.cpp
@@ -0,0 +1,297 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+** Copyright (c) 2001 Phil Thompson <phil@river-bank.demon.co.uk>
+** Copyright (c) 2002 Riverbank Computing Limited <info@riverbankcomputing.co.uk>
+** Copyright (c) 2002 Germain Garand <germain@ebooksfrance.com>
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+/*
+** 06/2002 : Initial release of puic, the PerlQt User Interface Compiler,
+** a work derivated from uic (the Qt User Interface Compiler)
+** and pyuic (the PyQt User Interface Compiler).
+**
+** G.Garand
+**
+** 08/2003 : Initial release of rbuic, the QtRuby User Interface Compiler,
+** a work derived from the PerlQt puic.
+**
+** Richard Dale
+**
+**********************************************************************/
+
+#include "uic.h"
+#include <qfile.h>
+#include <qimage.h>
+#include <qstringlist.h>
+#include <qdatetime.h>
+#include <qfileinfo.h>
+#define NO_STATIC_COLORS
+#include <globaldefs.h>
+#include <qregexp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+struct EmbedImage
+{
+ int width, height, depth;
+ int numColors;
+ QRgb* colorTable;
+ QString name;
+ QString cname;
+ bool alpha;
+};
+
+static QString convertToCIdentifier( const char *s )
+{
+ QString r = s;
+ int len = r.length();
+ if ( len > 0 && !isalpha( (char)r[0].latin1() ) )
+ r[0] = '_';
+ for ( int i=1; i<len; i++ ) {
+ if ( !isalnum( (char)r[i].latin1() ) )
+ r[i] = '_';
+ }
+ return r;
+}
+
+
+static ulong embedData( QTextStream& out, const uchar* input, int nbytes )
+{
+#ifndef QT_NO_IMAGE_COLLECTION_COMPRESSION
+ QByteArray bazip( qCompress( input, nbytes ) );
+ ulong len = bazip.size();
+#else
+ ulong len = nbytes;
+#endif
+ static const char hexdigits[] = "0123456789abcdef";
+ QString s;
+ for ( int i=0; i<(int)len; i++ ) {
+ if ( (i%14) == 0 ) {
+ s += "\n ";
+ out << (const char*)s;
+ s.truncate( 0 );
+ }
+ uint v = (uchar)
+#ifndef QT_NO_IMAGE_COLLECTION_COMPRESSION
+ bazip
+#else
+ input
+#endif
+ [i];
+ s += "0x";
+ s += hexdigits[(v >> 4) & 15];
+ s += hexdigits[v & 15];
+ if ( i < (int)len-1 )
+ s += ',';
+ }
+ if ( s.length() )
+ out << (const char*)s;
+ return len;
+}
+
+static void embedData( QTextStream& out, const QRgb* input, int n )
+{
+ out << hex;
+ const QRgb *v = input;
+ for ( int i=0; i<n; i++ ) {
+ if ( (i%14) == 0 )
+ out << "\n ";
+ out << "0x";
+ out << hex << *v++;
+ if ( i < n-1 )
+ out << ',';
+ }
+ out << dec; // back to decimal mode
+}
+
+void Uic::embed( QTextStream& out, const char* project, const QStringList& images )
+{
+
+ QString cProject = convertToCIdentifier( project );
+
+ QStringList::ConstIterator it;
+ out << "# Image collection for project '" << project << "'." << endl;
+ out << "#" << endl;
+ out << "# Generated from reading image files: " << endl;
+ for ( it = images.begin(); it != images.end(); ++it )
+ out << "# " << *it << endl;
+ out << "#" << endl;
+ out << "# Created: " << QDateTime::currentDateTime().toString() << endl;
+ out << "# by: The QtRuby User Interface Compiler (rbuic)" << endl;
+ out << "#" << endl;
+ out << "# WARNING! All changes made in this file will be lost!" << endl;
+ out << endl;
+ if (hasKDEwidget) {
+ out << "require 'Korundum'" << endl;
+ } else {
+ out << "require 'Qt'" << endl;
+ }
+ out << endl;
+
+ out << indent << "class MimeSourceFactory_" << cProject << " < Qt::MimeSourceFactory" << endl;
+ out << endl;
+
+ QPtrList<EmbedImage> list_image;
+ int image_count = 0;
+ for ( it = images.begin(); it != images.end(); ++it ) {
+ QImage img;
+ if ( !img.load( *it ) ) {
+ fprintf( stderr, "rbuic: cannot load image file %s\n", (*it).latin1() );
+ continue;
+ }
+ EmbedImage *e = new EmbedImage;
+ e->width = img.width();
+ e->height = img.height();
+ e->depth = img.depth();
+ e->numColors = img.numColors();
+ e->colorTable = new QRgb[e->numColors];
+ e->alpha = img.hasAlphaBuffer();
+ memcpy(e->colorTable, img.colorTable(), e->numColors*sizeof(QRgb));
+ QFileInfo fi( *it );
+ e->name = fi.fileName();
+ e->cname = QString("@@image_%1").arg( image_count++);
+ list_image.append( e );
+ out << "# " << *it << endl;
+ QString imgname = (const char *)e->cname;
+
+ QString s;
+ if ( e->depth == 1 )
+ img = img.convertBitOrder(QImage::BigEndian);
+ out << indent << imgname << "_data = [";
+ embedData( out, img.bits(), img.numBytes() );
+ out << "]\n\n";
+ if ( e->numColors ) {
+ out << indent << imgname << "_ctable = [";
+ embedData( out, e->colorTable, e->numColors );
+ out << "]\n\n";
+ }
+ }
+
+ ++indent;
+ if ( !list_image.isEmpty() ) {
+ out << indent << "@@embed_images = {\n";
+ ++indent;
+ EmbedImage *e = list_image.first();
+ while ( e )
+ {
+ out << indent << "\"" << e->name << "\"" << " => [" << e->cname << "_data, "
+ << e->width << ", " << e->height << ", " << e->depth << ", "
+ << (e->numColors ? e->cname + "_ctable" : QString::fromLatin1( "[]" ) ) << ", "
+ << (e->alpha ? "true" : "false") << "]," << endl;
+ e = list_image.next();
+ }
+ --indent;
+ out << indent << "}" << endl;
+
+ out << endl;
+ out << indent << "@@images = Hash.new" << endl;
+ out << endl;
+ out << indent << "def uic_findImage( name )" << endl;
+ ++indent;
+ out << indent << "if !@@images[name].nil?" << endl;
+ ++indent;
+ out << indent << "return @@images[name]" << endl;
+ --indent;
+ out << indent << "end" << endl;
+
+ out << indent << "if @@embed_images[name].nil?" << endl;
+ ++indent;
+ out << indent << "return Qt::Image.new()" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ out << indent << endl;
+#ifndef QT_NO_IMAGE_COLLECTION_COMPRESSION
+ out << indent << "baunzip = qUncompress( @@embed_images[name][0].pack(\"C*\")," << endl;
+ out << indent << " @@embed_images[name][0].length )" << endl;
+ out << indent << "img = Qt::Image.new( baunzip.data," << endl;
+ out << indent << " @@embed_images[name][1]," << endl;
+ out << indent << " @@embed_images[name][2]," << endl;
+ out << indent << " @@embed_images[name][3]," << endl;
+ out << indent << " @@embed_images[name][4]," << endl;
+ out << indent << " @@embed_images[name][4].length," << endl;
+ out << indent << " Qt::Image::BigEndian )" << endl;
+#else
+ out << indent << "img = Qt::Image.new( @@embed_images[name][0].pack(\"C*\")," << endl;
+ out << indent << " @@embed_images[name][1]," << endl;
+ out << indent << " @@embed_images[name][2]," << endl;
+ out << indent << " @@embed_images[name][3]," << endl;
+ out << indent << " @@embed_images[name][4]," << endl;
+ out << indent << " @@embed_images[name][4].length," << endl;
+ out << indent << " Qt::Image::BigEndian )" << endl;
+#endif
+ out << indent << "if @@embed_images[name][5]" << endl;
+ ++indent;
+ out << indent << "img.setAlphaBuffer(true)" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ out << indent << "@@images[name] = img" << endl;
+ out << indent << "return img" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ out << endl;
+ out << indent << "def data( abs_name )" << endl;
+ ++indent;
+ out << indent << "img = uic_findImage(abs_name)" << endl;
+ out << indent << "if img.nil?" << endl;
+ ++indent;
+ out << indent << "Qt::MimeSourceFactory.removeFactory(self)" << endl;
+ out << indent << "s = Qt::MimeSourceFactory.defaultFactory().data(abs_name);" << endl;
+ out << indent << "Qt::MimeSourceFactory.addFactory(self)" << endl;
+ out << indent << "return s" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ out << indent << "Qt::MimeSourceFactory.defaultFactory().setImage(abs_name, img)" << endl;
+ out << indent << "return Qt::MimeSourceFactory.defaultFactory().data(abs_name)" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ --indent;
+ out << indent << "end" << endl;
+
+ out << endl;
+ out << endl;
+
+ out << indent << "module StaticInitImages_" << cProject << endl;
+ ++indent;
+ out << indent << "@@factories = Hash.new" << endl;
+ out << indent << endl;
+ out << indent << "def StaticInitImages_" << cProject << ".qInitImages" << endl;
+ ++indent;
+ out << indent << "factory = MimeSourceFactory_" << cProject << ".new()" << endl;
+ out << indent << "Qt::MimeSourceFactory.defaultFactory().addFactory(factory)" << endl;
+ out << indent << "@@factories['MimeSourceFactory_" << cProject << "'] = factory" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ out << endl;
+ out << indent << "def StaticInitImages_" << cProject << ".qCleanupImages" << endl;
+ ++indent;
+ out << indent << "for values in @@factories" << endl;
+ ++indent;
+ out << indent << "Qt::MimeSourceFactory.defaultFactory().removeFactory(values)" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ out << indent << "@@factories = nil" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ out << endl;
+ out << indent << "StaticInitImages_" << cProject << ".qInitImages" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ out << endl;
+ }
+}
diff --git a/qtruby/rubylib/designer/rbuic/form.cpp b/qtruby/rubylib/designer/rbuic/form.cpp
new file mode 100644
index 00000000..7efbacd1
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/form.cpp
@@ -0,0 +1,1017 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+** Copyright (c) 2002 Germain Garand <germain@ebooksfrance.com>
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+/*
+** 06/2002 : Initial release of puic, the PerlQt User Interface Compiler,
+** a work derivated from uic (the Qt User Interface Compiler)
+** and pyuic (the PyQt User Interface Compiler).
+**
+** G.Garand
+**
+**********************************************************************/
+
+#include "uic.h"
+#include "parser.h"
+#include "widgetdatabase.h"
+#include "domtool.h"
+
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+
+#define NO_STATIC_COLORS
+#include <globaldefs.h>
+
+#include <zlib.h>
+
+static QByteArray unzipXPM( QString data, ulong& length )
+{
+ const int lengthOffset = 4;
+ int baSize = data.length() / 2 + lengthOffset;
+ uchar *ba = new uchar[ baSize ];
+ for ( int i = lengthOffset; i < baSize; ++i ) {
+ char h = data[ 2 * (i-lengthOffset) ].latin1();
+ char l = data[ 2 * (i-lengthOffset) + 1 ].latin1();
+ uchar r = 0;
+ if ( h <= '9' )
+ r += h - '0';
+ else
+ r += h - 'a' + 10;
+ r = r << 4;
+ if ( l <= '9' )
+ r += l - '0';
+ else
+ r += l - 'a' + 10;
+ ba[ i ] = r;
+ }
+ // qUncompress() expects the first 4 bytes to be the expected length of the
+ // uncompressed data
+ ba[0] = ( length & 0xff000000 ) >> 24;
+ ba[1] = ( length & 0x00ff0000 ) >> 16;
+ ba[2] = ( length & 0x0000ff00 ) >> 8;
+ ba[3] = ( length & 0x000000ff );
+ QByteArray baunzip = qUncompress( ba, baSize );
+ delete[] ba;
+ return baunzip;
+}
+
+static QString imageDataName(QString name) {
+ QString result = name + "_data";
+ result.replace("@", "@@");
+ return result;
+}
+
+/*!
+ Creates an implementation ( cpp-file ) for the form given in \a e
+
+ \sa createFormDecl(), createObjectImpl()
+ */
+void Uic::createFormImpl( const QDomElement &e )
+{
+ QDomElement n;
+ QDomNodeList nl;
+ int i;
+ QString objClass = getClassName( e );
+ if ( objClass.isEmpty() )
+ return;
+ QString objName = getObjectName( e );
+
+ if (hasKDEwidget) {
+ out << indent << "require 'Korundum'" << endl << endl;
+ } else {
+ out << indent << "require 'Qt'" << endl << endl;
+ }
+
+ // generate local and local includes required
+ QStringList globalIncludes, localIncludes;
+ QStringList::Iterator it;
+ QStringList sqlClasses;
+
+ QMap<QString, CustomInclude> customWidgetIncludes;
+ QMap<QString, QString> functionImpls;
+
+ // find additional slots
+ QStringList extraSlots;
+ QStringList extraSlotTypes;
+ nl = e.parentNode().toElement().elementsByTagName( "slot" );
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ n = nl.item(i).toElement();
+ if ( n.parentNode().toElement().tagName() != "slots"
+ && n.parentNode().toElement().tagName() != "connections" )
+ continue;
+ if ( n.attribute( "language", "C++" ) != "C++" )
+ continue;
+ QString slotName = n.firstChild().toText().data().stripWhiteSpace();
+ if ( slotName.endsWith( ";" ) )
+ slotName = slotName.left( slotName.length() - 1 );
+
+ extraSlots += Parser::cleanArgs(slotName);
+ extraSlotTypes += n.attribute( "returnType", "void" );
+ }
+
+ // find signals
+ QStringList extraSignals;
+ nl = e.parentNode().toElement().elementsByTagName( "signal" );
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ n = nl.item(i).toElement();
+ if ( n.parentNode().toElement().tagName() != "signals"
+ && n.parentNode().toElement().tagName() != "connections" )
+ continue;
+ if ( n.attribute( "language", "C++" ) != "C++" )
+ continue;
+ QString sigName = n.firstChild().toText().data().stripWhiteSpace();
+ if ( sigName.endsWith( ";" ) )
+ sigName = sigName.left( sigName.length() - 1 );
+ extraSignals += sigName;
+ }
+
+ //find additional functions
+ QStringList extraFunctions;
+ for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "functions" ) { // compatibility
+ for ( QDomElement n2 = n.firstChild().toElement(); !n2.isNull(); n2 = n2.nextSibling().toElement() ) {
+ if ( n2.tagName() == "function" ) {
+ QString fname;
+ if( !n2.attribute("name").isNull() )
+ {
+ fname = n2.attribute( "name" );
+ fname = Parser::cleanArgs( fname );
+ functionImpls.insert( fname, n2.firstChild().toText().data() );
+ }
+ else
+ {
+ fname = n2.text();
+ fname = Parser::cleanArgs( fname );
+ }
+ extraFunctions += fname;
+ }
+ }
+ } else if ( n.tagName() == "customwidgets" ) {
+ QDomElement n2 = n.firstChild().toElement();
+ while ( !n2.isNull() ) {
+ if ( n2.tagName() == "customwidget" ) {
+ QDomElement n3 = n2.firstChild().toElement();
+ QString cl, header;
+ WidgetDatabaseRecord *r = new WidgetDatabaseRecord;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "class" ) {
+ cl = n3.firstChild().toText().data();
+ r->name = cl;
+ } else if ( n3.tagName() == "header" ) {
+ CustomInclude ci;
+ ci.header = n3.firstChild().toText().data();
+ ci.location = n3.attribute( "location", "global" );
+ r->includeFile = ci.header;
+ header = ci.header;
+ customWidgetIncludes.insert( cl, ci );
+ }
+ WidgetDatabase::append( r );
+ n3 = n3.nextSibling().toElement();
+ }
+
+ if (cl.isEmpty())
+ cl = "UnnamedCustomClass";
+
+ int ext = header.findRev('.');
+
+ if (ext >= 0)
+ header.truncate(ext);
+
+ if (header.isEmpty())
+ header = cl.lower();
+
+// if (!nofwd)
+// out << "use " << cl << ";" << endl; // FIXME: what about header ?
+ }
+ n2 = n2.nextSibling().toElement();
+ }
+ }
+ }
+
+ out << "class " << nameOfClass << " < " << objClass << endl << endl;
+
+ // QtRuby sig/slot declaration
+
+ ++indent;
+
+ if ( !extraSlots.isEmpty() ) {
+ out << indent << "slots 'languageChange()'";
+ for ( it = extraSlots.begin(); it != extraSlots.end(); ++it ) {
+ if (it == extraSlots.begin()) {
+ out << "," << endl;
+ }
+ rubySlot( it );
+ out << ( ((*it) == extraSlots.last()) ? "":",") << endl;
+ }
+ out << endl;
+ }
+
+ // create signals
+ if ( !extraSignals.isEmpty() ) {
+ out << indent << "signals ";
+ --indent;
+ for ( it = extraSignals.begin(); it != extraSignals.end(); ++it ) {
+ rubySlot( it );
+ if (it == extraSignals.begin()) {
+ ++indent;
+ }
+ out << ( ((*it) == extraSignals.last()) ? "":",") << endl;
+ }
+ out << endl;
+ }
+
+
+ // children
+ if( !objectNames.isEmpty() )
+ qWarning("WARNING : objectNames should be empty at "__FILE__" line %d\n", __LINE__);
+ nl = e.parentNode().toElement().elementsByTagName( "widget" );
+ for ( i = 1; i < (int) nl.length(); i++ )
+ { // start at 1, 0 is the toplevel widget
+ n = nl.item(i).toElement();
+ createAttrDecl( n );
+ }
+ objectNames.clear();
+
+ ++indent;
+
+ // additional attributes (from Designer)
+ QStringList publicVars, protectedVars, privateVars;
+ nl = e.parentNode().toElement().elementsByTagName( "variable" );
+ for ( i = 0; i < (int)nl.length(); i++ ) {
+ n = nl.item( i ).toElement();
+ // Because of compatibility the next lines have to be commented out.
+ // Someday it should be uncommented.
+ //if ( n.parentNode().toElement().tagName() != "variables" )
+ // continue;
+ QString access = n.attribute( "access", "protected" );
+ QString var = n.firstChild().toText().data().stripWhiteSpace();
+ if ( var.endsWith( ";" ) )
+ var.truncate(var.length() - 1);
+ if ( access == "public" )
+ publicVars += var;
+ else if ( access == "private" )
+ privateVars += var;
+ else
+ protectedVars += var;
+ }
+
+ // Databases Connection holders
+
+ registerDatabases( e );
+ dbConnections = unique( dbConnections );
+ for ( it = dbConnections.begin(); it != dbConnections.end(); ++it ) {
+ if ( !(*it).isEmpty() && (*it) != "(default)") {
+ out << indent << (*it) << "Connection" << endl;
+ }
+ }
+
+ --indent;
+
+ // additional includes (local or global ) and forward declaractions
+ nl = e.parentNode().toElement().elementsByTagName( "include" );
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ QDomElement n2 = nl.item(i).toElement();
+ QString s = n2.firstChild().toText().data();
+ if ( n2.attribute( "location" ) != "local" ) {
+ if ( s.right( 5 ) == ".ui.h" && !QFile::exists( s ) )
+ continue;
+ if ( n2.attribute( "impldecl", "in implementation" ) != "in implementation" )
+ continue;
+ globalIncludes += s;
+ }
+ }
+
+ // do the local includes afterwards, since global includes have priority on clashes
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ QDomElement n2 = nl.item(i).toElement();
+ QString s = n2.firstChild().toText().data();
+ if ( n2.attribute( "location" ) == "local" &&!globalIncludes.contains( s ) ) {
+ if ( s.right( 5 ) == ".ui.h" && !QFile::exists( s ) )
+ continue;
+ if ( n2.attribute( "impldecl", "in implementation" ) != "in implementation" )
+ continue;
+ localIncludes += s;
+ }
+ }
+
+ // additional custom widget headers
+ nl = e.parentNode().toElement().elementsByTagName( "header" );
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ QDomElement n2 = nl.item(i).toElement();
+ QString s = n2.firstChild().toText().data();
+ if ( n2.attribute( "location" ) != "local" )
+ globalIncludes += s;
+ else
+ localIncludes += s;
+ }
+
+
+ // grab slots/funcs defined in ui.h files
+ for(QStringList::Iterator it = localIncludes.begin(); it != localIncludes.end(); ++it)
+ {
+ if((*it).right( 5 ) == ".ui.h")
+ {
+ QFile f((*it));
+ if( f.open( IO_ReadOnly ) )
+ {
+ QRegExp re("^def\\s+([a-zA-Z0-9_]+)\\s.*$");
+ QRegExp re2("^end\\s*$");
+ QTextStream t( &f );
+ QString s, s2, s3;
+ while ( !t.eof() )
+ {
+ s = t.readLine();
+ int pos = re.search(s);
+ if(pos == -1)
+ continue;
+ s2 = re.cap(1);
+ s2 += "()";
+// s2 = Parser::cleanArgs(s2);
+ s3 = "{";
+ while( !t.eof() )
+ {
+ s = t.readLine();
+ if(re2.search(s) != -1)
+ break;
+ s3 += s + "\n";
+ }
+ s3 += "}";
+ functionImpls.insert( s2, s3 );
+ if( t.eof() ) break;
+ }
+ f.close();
+ }
+ }
+ }
+
+ // includes for child widgets
+ for ( it = tags.begin(); it != tags.end(); ++it ) {
+ nl = e.parentNode().toElement().elementsByTagName( *it );
+ for ( i = 1; i < (int) nl.length(); i++ ) { // start at 1, 0 is the toplevel widget
+ QString name = getClassName( nl.item(i).toElement() );
+ if ( name == "Spacer" ) {
+ globalIncludes += "qlayout.h";
+ globalIncludes += "qapplication.h";
+ continue;
+ }
+ if ( name.mid( 4 ) == "ListView" )
+ globalIncludes += "qheader.h";
+ if ( name != objClass ) {
+ int wid = WidgetDatabase::idFromClassName( name.replace( QRegExp("^Qt::"), "Q" ) );
+ QMap<QString, CustomInclude>::Iterator it = customWidgetIncludes.find( name );
+ if ( it == customWidgetIncludes.end() )
+ globalIncludes += WidgetDatabase::includeFile( wid );
+ }
+ }
+ }
+
+ dbConnections = unique( dbConnections );
+ if ( dbConnections.count() )
+ sqlClasses += "Qt::SqlDatabase";
+ if ( dbCursors.count() )
+ sqlClasses += "Qt::SqlCursor";
+ bool dbForm = false;
+ if ( dbForms[ "(default)" ].count() )
+ dbForm = true;
+ bool subDbForms = false;
+ for ( it = dbConnections.begin(); it != dbConnections.end(); ++it ) {
+ if ( !(*it).isEmpty() && (*it) != "(default)" ) {
+ if ( dbForms[ (*it) ].count() ) {
+ subDbForms = true;
+ break;
+ }
+ }
+ }
+ if ( dbForm || subDbForms ) {
+ sqlClasses += "Qt::SqlForm";
+ sqlClasses += "Qt::SqlRecord";
+ }
+
+ if (globalIncludes.findIndex("qdatatable.h") >= 0)
+ sqlClasses += "Qt::DataTable";
+
+ if (globalIncludes.findIndex("qtableview.h") >= 0)
+ sqlClasses += "Qt::TableView";
+
+ if (globalIncludes.findIndex("qdatabrowser.h") >= 0)
+ sqlClasses += "Qt::DataBrowser";
+
+ out << endl;
+
+ // find out what images are required
+ QStringList requiredImages;
+ static const char *imgTags[] = { "pixmap", "iconset", 0 };
+ for ( i = 0; imgTags[i] != 0; i++ ) {
+ nl = e.parentNode().toElement().elementsByTagName( imgTags[i] );
+ for ( int j = 0; j < (int) nl.length(); j++ ) {
+ QString img = "@";
+ requiredImages += (img + nl.item(j).firstChild().toText().data());
+ }
+ }
+
+ // register the object and unify its name
+ QString loadFunction(objName);
+ objName = registerObject( objName );
+
+ QStringList images;
+ QStringList xpmImages;
+ if ( pixmapLoaderFunction.isEmpty() && !externPixmaps )
+ {
+ // create images
+ for ( n = e; !n.isNull(); n = n.nextSibling().toElement() )
+ {
+ if ( n.tagName() == "images" )
+ {
+ nl = n.elementsByTagName( "image" );
+ for ( i = 0; i < (int) nl.length(); i++ )
+ {
+ QString img = registerObject( nl.item(i).toElement().attribute( "name" ) );
+ if ( !requiredImages.contains( img ) )
+ continue;
+ QDomElement tmp = nl.item(i).firstChild().toElement();
+ if ( tmp.tagName() != "data" )
+ continue;
+ QString format = tmp.attribute("format", "PNG" );
+ QString data = tmp.firstChild().toText().data();
+ if ( format == "XPM.GZ" )
+ {
+ xpmImages += img;
+ ulong length = tmp.attribute("length").toULong();
+ QByteArray baunzip = unzipXPM( data, length );
+ // shouldn't we test the initial `length' against the
+ // resulting `length' to catch corrupt UIC files?
+ int a = 0;
+ out << indent << imageDataName(img) << " =\n[";
+
+ while ( baunzip[a] != '\"' )
+ a++;
+ for ( ; a < (int) length; a++ )
+ {
+ char ch;
+
+ if ((ch = baunzip[a]) == '}')
+ {
+ out << "]\n" << endl;
+
+ break;
+ }
+
+ out << ch;
+ }
+ }
+ else
+ {
+ images += img;
+ out << indent << imageDataName(img) << " = [ " << endl;
+ ++indent;
+ int a ;
+ for ( a = 0; a < (int) (data.length()/2)-1; a++ ) {
+ out << "0x" << QString(data[2*a]) << QString(data[2*a+1]) << ",";
+ if ( a % 12 == 11 )
+ out << endl << " ";
+ else
+ out << " ";
+ }
+ out << "0x" << QString(data[2*a]) << QString(data[2*a+1]) << " ].pack \"C*\"" << endl;
+ --indent;
+ out << endl;
+ }
+ }
+ }
+ }
+ out << endl;
+ }
+ else if ( externPixmaps )
+ {
+ /*
+ out << indent << "def uic_load_pixmap_" << loadFunction << "( data )" << endl;
+ ++indent;
+ out << indent << "pix = Qt::Pixmap.new()" << endl;
+ out << indent << "m = Qt::MimeSourceFactory.defaultFactory().data(data)" << endl;
+ out << endl;
+ out << indent << "if ! m.nil?" << endl;
+ ++indent;
+ out << indent << "Qt::ImageDrag.decode(m, pix)" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ out << endl;
+ out << indent << "return pix" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ out << endl;
+ out << endl;
+ pixmapLoaderFunction = "uic_load_pixmap_" + loadFunction;
+ */
+ pixmapLoaderFunction = "Qt::Pixmap.fromMimeSource";
+ }
+
+
+ // constructor(s)
+ if ( objClass == "Qt::Dialog" || objClass == "Qt::Wizard" ) {
+ out << indent << "def initialize(parent = nil, name = nil, modal = false, fl = 0)" << endl;
+ ++indent;
+ out << indent << "super" << endl;
+ } else if ( objClass == "Qt::Widget") {
+ out << indent << "def initialize(parent = nil, name = nil, fl = 0)" << endl;
+ ++indent;
+ out << indent << "super" << endl;
+ } else if ( objClass == "Qt::MainWindow" ) {
+ out << indent << "def initialize(parent = nil, name = nil, fl = WType_TopLevel)" << endl;
+ ++indent;
+ out << indent << "super" << endl;
+ isMainWindow = true;
+ } else {
+ out << indent << "def initialize(parent = nil, name = nil)" << endl;
+ ++indent;
+ out << indent << "super" << endl;
+ }
+
+ out << endl;
+
+ // create pixmaps for all images
+ if ( !images.isEmpty() ) {
+ QStringList::Iterator it;
+ for ( it = images.begin(); it != images.end(); ++it ) {
+ out << indent << (*it) << " = Qt::Pixmap.new()" << endl;
+ out << indent << (*it) << ".loadFromData(" << imageDataName(*it) << ", " << imageDataName(*it) << ".length, \"PNG\")" << endl;
+ }
+ out << endl;
+ }
+ // create pixmaps for all images
+ if ( !xpmImages.isEmpty() ) {
+ for ( it = xpmImages.begin(); it != xpmImages.end(); ++it ) {
+ out << indent << (*it) << " = Qt::Pixmap.new(" << imageDataName(*it) << ")" << endl;
+ }
+ out << endl;
+ }
+
+ if ( isMainWindow )
+ out << indent << "statusBar()" << endl;
+
+ // set the properties
+ QSize geometry( 0, 0 );
+
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "property" ) {
+ bool stdset = stdsetdef;
+ if ( n.hasAttribute( "stdset" ) )
+ stdset = toBool( n.attribute( "stdset" ) );
+ QString prop = n.attribute("name");
+ QDomElement n2 = n.firstChild().toElement();
+ QString value = setObjectProperty( objClass, QString::null, prop, n2, stdset );
+ if ( value.isEmpty() )
+ continue;
+
+ if ( prop == "geometry" && n2.tagName() == "rect") {
+ QDomElement n3 = n2.firstChild().toElement();
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "width" )
+ geometry.setWidth( n3.firstChild().toText().data().toInt() );
+ else if ( n3.tagName() == "height" )
+ geometry.setHeight( n3.firstChild().toText().data().toInt() );
+ n3 = n3.nextSibling().toElement();
+ }
+ } else {
+ QString call;
+ if ( stdset ) {
+ call = mkStdSet( prop ) + "(" + value + ")";
+ } else {
+ call = "setProperty(\"" + prop + "\", Qt::Variant.new(" + value + "))";
+ }
+
+ if ( n2.tagName() == "string" ) {
+ trout << indent << call << endl;
+ } else if ( prop == "name" ) {
+ out << indent << "if name.nil?" << endl;
+ out << indent << "\t" << call << endl;
+ out << indent << "end" << endl;
+ } else {
+ out << indent << call << endl;
+ }
+ }
+ }
+ }
+
+ out << endl;
+
+ // create all children, some forms have special requirements
+
+ if ( objClass == "Qt::Wizard" )
+ {
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() )
+ {
+ if ( tags.contains( n.tagName() ) )
+ {
+ QString page = createObjectImpl( n, objClass, "self" );
+ QString comment;
+ QString label = DomTool::readAttribute( n, "title", "", comment ).toString();
+ out << indent << "addPage(" << page << ", "<< trcall( label ) << ")" << endl;
+ trout << indent << "setTitle( " << page << ", " << trcall( label, comment ) << " )" << endl;
+ QVariant def( false, 0 );
+ if ( DomTool::hasAttribute( n, "backEnabled" ) )
+ out << indent << "setBackEnabled(" << page << "," << mkBool( DomTool::readAttribute( n, "backEnabled", def).toBool() ) << ");" << endl;
+ if ( DomTool::hasAttribute( n, "nextEnabled" ) )
+ out << indent << "setNextEnabled(" << page << "," << mkBool( DomTool::readAttribute( n, "nextEnabled", def).toBool() ) << ");" << endl;
+ if ( DomTool::hasAttribute( n, "finishEnabled" ) )
+ out << indent << "setFinishEnabled(" << page << "," << mkBool( DomTool::readAttribute( n, "finishEnabled", def).toBool() ) << ");" << endl;
+ if ( DomTool::hasAttribute( n, "helpEnabled" ) )
+ out << indent << "setHelpEnabled(" << page << "," << mkBool( DomTool::readAttribute( n, "helpEnabled", def).toBool() ) << ");" << endl;
+ if ( DomTool::hasAttribute( n, "finish" ) )
+ out << indent << "setFinish( " << page << "," << mkBool( DomTool::readAttribute( n, "finish", def).toBool() ) << ");" << endl;
+ }
+ }
+ }
+ else
+ { // standard widgets
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() )
+ {
+ if ( tags.contains( n.tagName() ) )
+ createObjectImpl( n, objName, "self" );
+ }
+ }
+
+ // database support
+ dbConnections = unique( dbConnections );
+ if ( dbConnections.count() )
+ out << endl;
+ for ( it = dbConnections.begin(); it != dbConnections.end(); ++it ) {
+ if ( !(*it).isEmpty() && (*it) != "(default)") {
+ out << indent << (*it) << "Connection = Qt::SqlDatabase.database(\"" <<(*it) << "\");" << endl;
+ }
+ }
+
+ nl = e.parentNode().toElement().elementsByTagName( "widget" );
+ for ( i = 1; i < (int) nl.length(); i++ ) { // start at 1, 0 is the toplevel widget
+ n = nl.item(i).toElement();
+ QString s = getClassName( n );
+ if ( s == "Qt::DataBrowser" || s == "Qt::DataView" ) {
+ QString objName = getObjectName( n );
+ QString tab = getDatabaseInfo( n, "table" );
+ QString con = getDatabaseInfo( n, "connection" );
+ out << indent << objName << "Form = Qt::SqlForm.new(self, \"" << objName << "Form\")" << endl;
+ QDomElement n2;
+ for ( n2 = n.firstChild().toElement(); !n2.isNull(); n2 = n2.nextSibling().toElement() )
+ createFormImpl( n2, objName, con, tab );
+ out << indent << objName << ".setForm(" << objName << "Form)" << endl;
+ }
+ }
+
+ // actions, toolbars, menubar
+ bool needEndl = false;
+ for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "actions" ) {
+ if ( !needEndl )
+ out << endl;
+ createActionImpl( n.firstChild().toElement(), "self" );
+ needEndl = true;
+ }
+ }
+ if ( needEndl )
+ out << endl;
+ needEndl = false;
+ for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "toolbars" ) {
+ if ( !needEndl )
+ out << endl;
+ createToolbarImpl( n, objClass, objName );
+ needEndl = true;
+ }
+ }
+ if ( needEndl )
+ out << endl;
+ needEndl = false;
+ for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "menubar" ) {
+ if ( !needEndl )
+ out << endl;
+ createMenuBarImpl( n, objClass, objName );
+ needEndl = true;
+ }
+ }
+ if ( needEndl )
+ out << endl;
+
+ out << indent << "languageChange()" << endl;
+
+ // take minimumSizeHint() into account, for height-for-width widgets
+ if ( !geometry.isNull() ) {
+ out << indent << "resize( Qt::Size.new(" << geometry.width() << ", "
+ << geometry.height() << ").expandedTo(minimumSizeHint()) )" << endl;
+ out << indent << "clearWState( WState_Polished )" << endl;
+ }
+
+ for ( n = e; !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "connections" ) {
+ // setup signals and slots connections
+ out << endl;
+ nl = n.elementsByTagName( "connection" );
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ QString sender, receiver, signal, slot;
+ for ( QDomElement n2 = nl.item(i).firstChild().toElement(); !n2.isNull(); n2 = n2.nextSibling().toElement() ) {
+ if ( n2.tagName() == "sender" )
+ sender = n2.firstChild().toText().data();
+ else if ( n2.tagName() == "receiver" )
+ receiver = n2.firstChild().toText().data();
+ else if ( n2.tagName() == "signal" )
+ signal = n2.firstChild().toText().data();
+ else if ( n2.tagName() == "slot" )
+ slot = n2.firstChild().toText().data();
+ }
+ if ( sender.isEmpty() || receiver.isEmpty() || signal.isEmpty() || slot.isEmpty() )
+ continue;
+ else if ( sender[0] == '<' ||
+ receiver[0] == '<' ||
+ signal[0] == '<' ||
+ slot[0] == '<' )
+ continue;
+ sender = registeredName( sender );
+ receiver = registeredName( receiver );
+
+ if ( sender == objName )
+ sender = "self";
+ if ( receiver == objName )
+ receiver = "self";
+
+ out << indent << "Qt::Object.connect(" << sender
+ << ", SIGNAL(\"" << signal << "\"), "<< receiver << ", SLOT(\"" << slot << "\") )" << endl;
+ }
+ } else if ( n.tagName() == "tabstops" ) {
+ // setup tab order
+ out << endl;
+ QString lastName;
+ QDomElement n2 = n.firstChild().toElement();
+ while ( !n2.isNull() ) {
+ if ( n2.tagName() == "tabstop" ) {
+ QString name = n2.firstChild().toText().data();
+ name = registeredName( name );
+ if ( !lastName.isEmpty() )
+ out << indent << "setTabOrder(" << lastName << ", " << name << ")" << endl;
+ lastName = name;
+ }
+ n2 = n2.nextSibling().toElement();
+ }
+ }
+ }
+
+// QtRuby - FIXME: what the heck is this ?
+ // buddies
+ bool firstBuddy = true;
+ for ( QValueList<Buddy>::Iterator buddy = buddies.begin(); buddy != buddies.end(); ++buddy ) {
+ if ( isObjectRegistered( (*buddy).buddy ) ) {
+ if ( firstBuddy ) {
+ out << endl;
+ }
+ out << indent << (*buddy).key << ".setBuddy(" << registeredName( (*buddy).buddy ) << ")" << endl;
+ firstBuddy = false;
+ }
+
+ }
+ if ( extraSlots.find( "init()" ) != extraSlots.end() ||
+ extraFunctions.find( "init()" ) != extraFunctions.end())
+ out << endl << indent << "init()" << endl;
+
+ // end of constructor
+ --indent;
+ out << indent << "end" << endl;
+ out << endl;
+
+
+
+ // handle application events if required
+ bool needFontEventHandler = false;
+ bool needSqlTableEventHandler = false;
+ bool needSqlDataBrowserEventHandler = false;
+ nl = e.elementsByTagName( "widget" );
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ if ( !DomTool::propertiesOfType( nl.item(i).toElement() , "font" ).isEmpty() )
+ needFontEventHandler = true;
+ QString s = getClassName( nl.item(i).toElement() );
+ if ( s == "Qt::DataTable" || s == "Qt::DataBrowser" ) {
+ if ( !isFrameworkCodeGenerated( nl.item(i).toElement() ) )
+ continue;
+ if ( s == "Qt::DataTable" )
+ needSqlTableEventHandler = true;
+ if ( s == "Qt::DataBrowser" )
+ needSqlDataBrowserEventHandler = true;
+ }
+ if ( needFontEventHandler && needSqlTableEventHandler && needSqlDataBrowserEventHandler )
+ break;
+ }
+
+// PerlQt - TODO: is this needed ?
+// Seems not.. let's ifzero for now...
+
+ if ( 0 && needFontEventHandler) {
+ // indent = "\t"; // increase indentation for if-clause below
+ out << endl;
+ out << "# Main event handler. Reimplemented to handle" << endl;
+ out << "# application font changes" << endl;
+ out << endl;
+ out << "def event( ev )" << endl;
+ out << " ret = super( ev ) " << endl;
+ if ( needFontEventHandler ) {
+ ++indent;
+ out << " if ev.type() == Qt::Event::ApplicationFontChange " << endl;
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ n = nl.item(i).toElement();
+ QStringList list = DomTool::propertiesOfType( n, "font" );
+ for ( it = list.begin(); it != list.end(); ++it )
+ createExclusiveProperty( n, *it );
+ }
+ out << " end" << endl;
+ --indent;
+ }
+ out << "end" << endl;
+ out << endl;
+ }
+
+ if ( needSqlTableEventHandler || needSqlDataBrowserEventHandler ) {
+ out << endl;
+ out << indent << "# Widget polish. Reimplemented to handle default data" << endl;
+ if ( needSqlTableEventHandler )
+ out << indent << "# table initialization." << endl;
+ if ( needSqlDataBrowserEventHandler )
+ out << indent << "# browser initialization." << endl;
+ out << indent << "def polish" << endl;
+ ++indent;
+ if ( needSqlTableEventHandler ) {
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ QString s = getClassName( nl.item(i).toElement() );
+ if ( s == "Qt::DataTable" ) {
+ n = nl.item(i).toElement();
+ QString c = QString("@") + getObjectName( n );
+ QString conn = getDatabaseInfo( n, "connection" );
+ QString tab = getDatabaseInfo( n, "table" );
+ if ( !( conn.isEmpty() || tab.isEmpty() ) ) {
+ out << indent << "if " << "!" << c << ".nil?" << endl;
+ ++indent;
+ out << indent << "cursor = " << c << ".sqlCursor()" << endl;
+ out << endl;
+ out << indent << "if !cursor.nil?" << endl;
+ ++indent;
+ if ( conn == "(default)" )
+ out << indent << "cursor = Qt::SqlCursor.new(\"" << tab << "\")" << endl;
+ else
+ out << indent << "cursor = Qt::SqlCursor.new(\"" << tab << "\", true, " << conn << "Connection)" << endl;
+ out << indent << "if " << c << ".readOnly? " << endl;
+ ++indent;
+ out << indent << "cursor.mode = Qt::SqlCursor::ReadOnly" << endl;
+ --indent;
+ out << indent << "end " << endl;
+ out << indent << c << ".setSqlCursor(cursor, false, true)" << endl;
+ --indent;
+ out << endl;
+ out << indent << "end" << endl;
+ out << indent << "if !cursor.active?" << endl;
+ ++indent;
+ out << indent << c << ".refresh(Qt::DataTable::RefreshAll)" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ }
+ }
+ }
+ }
+ if ( needSqlDataBrowserEventHandler ) {
+ nl = e.elementsByTagName( "widget" );
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ QString s = getClassName( nl.item(i).toElement() );
+ if ( s == "Qt::DataBrowser" ) {
+ QString obj = getObjectName( nl.item(i).toElement() );
+ QString tab = getDatabaseInfo( nl.item(i).toElement(),
+ "table" );
+ QString conn = getDatabaseInfo( nl.item(i).toElement(),
+ "connection" );
+ if ( !(tab).isEmpty() ) {
+ out << indent << "if " << obj << endl;
+ ++indent;
+ out << indent << "if !" << obj << ".sqlCursor()" << endl;
+ ++indent;
+ if ( conn == "(default)" )
+ out << indent << "cursor = Qt::SqlCursor.new(\"" << tab << "\")" << endl;
+ else
+ out << indent << "cursor = Qt::SqlCursor.new(\"" << tab << "\", true, " << conn << "Connection)" << endl;
+ out << indent << obj << ".setSqlCursor(cursor, true)" << endl;
+ out << indent << obj << ".refresh()" << endl;
+ out << indent << obj << ".first()" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ }
+ }
+ }
+ }
+ out << indent << "super()" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ }
+
+ out << indent << "#" << endl;
+ out << indent << "# Sets the strings of the subwidgets using the current" << endl;
+ out << indent << "# language." << endl;
+ out << indent << "#" << endl;
+ out << indent << "def " << "languageChange()" << endl;
+ out << languageChangeBody;
+ out << indent << "end" << endl;
+ out << indent << "protected :languageChange" << endl;
+ out << endl;
+
+ if ( !extraSlots.isEmpty() && writeSlotImpl ) {
+ for ( it = extraSlots.begin(); it != extraSlots.end(); ++it ) {
+ out << endl;
+ int astart = (*it).find('(');
+ out << indent << "def " << (*it).left(astart) << "(*k)" << endl;
+ bool createWarning = true;
+ QString fname = Parser::cleanArgs( *it );
+ QMap<QString, QString>::Iterator fit = functionImpls.find( fname );
+ if ( fit != functionImpls.end() ) {
+ int begin = (*fit).find( "{" );
+ QString body = (*fit).mid( begin + 1, (*fit).findRev( "}" ) - begin - 1 );
+ createWarning = body.simplifyWhiteSpace().isEmpty();
+ if ( !createWarning )
+ out << body << endl;
+ }
+ if ( createWarning ) {
+ ++indent;
+ if ( *it != "init()" && *it != "destroy()" )
+ out << indent << "print(\"" << nameOfClass << "." << (*it) << ": Not implemented yet.\\n\")" << endl;
+ --indent;
+ }
+ out << indent << "end" << endl;
+
+ }
+ }
+
+ if ( !extraFunctions.isEmpty() ) {
+ for ( it = extraFunctions.begin(); it != extraFunctions.end(); ++it ) {
+ out << endl;
+ int astart = (*it).find('(');
+ out << indent << "def " << (*it).left(astart) << "(*k)" << endl;
+ QString fname = Parser::cleanArgs( *it );
+ QMap<QString, QString>::Iterator fit = functionImpls.find( fname );
+ if ( fit != functionImpls.end() ) {
+ int begin = (*fit).find( "{" );
+ QString body = (*fit).mid( begin + 1, (*fit).findRev( "}" ) - begin - 1 );
+ body.simplifyWhiteSpace().isEmpty();
+ out << body << endl;
+ }
+ out << indent << "end" << endl;
+
+ }
+ }
+
+
+ out << endl;
+ out << "end" << endl;
+}
+
+
+/*! Creates form support implementation code for the widgets given
+ in \a e.
+
+ Traverses recursively over all children.
+ */
+
+void Uic::createFormImpl( const QDomElement& e, const QString& form, const QString& connection, const QString& table )
+{
+ if ( e.tagName() == "widget" &&
+ e.attribute( "class" ) != "Qt::DataTable" ) {
+ QString field = getDatabaseInfo( e, "field" );
+ if ( !field.isEmpty() ) {
+ if ( isWidgetInTable( e, connection, table ) )
+ out << indent << form << "Form.insert(" << getObjectName( e ) << ", " << fixString( field ) << ")" << endl;
+ }
+ }
+ QDomElement n;
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ createFormImpl( n, form, connection, table );
+ }
+}
+
+
+// Generate a QtRuby signal/slot definition.
+
+void Uic::rubySlot(QStringList::Iterator &it)
+{
+ out << indent << "'" << (*it) << "'";
+}
diff --git a/qtruby/rubylib/designer/rbuic/globaldefs.h b/qtruby/rubylib/designer/rbuic/globaldefs.h
new file mode 100644
index 00000000..cc6ed400
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/globaldefs.h
@@ -0,0 +1,45 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef GLOBALDEFS_H
+#define GLOBALDEFS_H
+
+#include <qcolor.h>
+
+#define BOXLAYOUT_DEFAULT_MARGIN 11
+#define BOXLAYOUT_DEFAULT_SPACING 6
+
+#ifndef NO_STATIC_COLORS
+static QColor *backColor1 = 0;
+static QColor *backColor2 = 0;
+static QColor *selectedBack = 0;
+
+static void init_colors()
+{
+ if ( backColor1 )
+ return;
+ backColor1 = new QColor( 236, 245, 255 );
+ backColor2 = new QColor( 250, 250, 250 );
+ selectedBack = new QColor( 221, 221, 221 );
+}
+
+#endif
+
+#endif
diff --git a/qtruby/rubylib/designer/rbuic/main.cpp b/qtruby/rubylib/designer/rbuic/main.cpp
new file mode 100644
index 00000000..a80d8785
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/main.cpp
@@ -0,0 +1,293 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+** Copyright (c) 2001 Phil Thompson <phil@river-bank.demon.co.uk>
+** Copyright (c) 2002 Germain Garand <germain@ebooksfrance.com>
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+/*
+** 06/2002 : Initial release of puic, the PerlQt User Interface Compiler,
+** a work derivated from uic (the Qt User Interface Compiler)
+** and pyuic (the PyQt User Interface Compiler).
+**
+** G.Garand
+**
+** 08/2003 : Initial release of rbuic, the QtRuby User Interface Compiler,
+** a work derived from the PerlQt puic.
+**
+** Richard Dale
+**
+**********************************************************************/
+#include "uic.h"
+#include "parser.h"
+#include "widgetdatabase.h"
+#include "domtool.h"
+#include <qapplication.h>
+#include <qfile.h>
+#include <qstringlist.h>
+#include <qdatetime.h>
+#define NO_STATIC_COLORS
+#include <globaldefs.h>
+#include <qregexp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <zlib.h>
+#define RBUIC_VERSION "0.9"
+
+void getDBConnections( Uic& uic, QString& s);
+
+int main( int argc, char * argv[] )
+{
+ RubyIndent indent;
+ bool execCode = false;
+ bool subcl = false;
+ bool imagecollection = false;
+ QStringList images;
+ const char *error = 0;
+ const char* fileName = 0;
+ const char* className = 0;
+ const char* outputFile = 0;
+ const char* projectName = 0;
+ const char* trmacro = 0;
+ bool nofwd = false;
+ bool useKDE = false;
+ bool fix = false;
+ QApplication app(argc, argv, false);
+ QString uicClass;
+
+
+ for ( int n = 1; n < argc && error == 0; n++ ) {
+ QCString arg = argv[n];
+ if ( arg[0] == '-' ) { // option
+ QCString opt = &arg[1];
+ if ( opt[0] == 'o' ) { // output redirection
+ if ( opt[1] == '\0' ) {
+ if ( !(n < argc-1) ) {
+ error = "Missing output-file name";
+ break;
+ }
+ outputFile = argv[++n];
+ } else
+ outputFile = &opt[1];
+ } else if ( opt[0] == 'e' || opt == "embed" ) {
+ imagecollection = true;
+ if ( opt == "embed" || opt[1] == '\0' ) {
+ if ( !(n < argc-1) ) {
+ error = "Missing name of project.";
+ break;
+ }
+ projectName = argv[++n];
+ } else
+ projectName = &opt[1];
+ } else if ( opt == "nofwd" ) {
+ nofwd = true;
+ } else if ( opt == "kde" ) {
+ useKDE = true;
+ } else if ( opt == "subimpl" ) {
+ subcl = true;
+ if ( !(n < argc-1) ) {
+ error = "Missing class name.";
+ break;
+ }
+ className = argv[++n];
+ } else if ( opt == "tr" ) {
+ if ( opt == "tr" || opt[1] == '\0' ) {
+ if ( !(n < argc-1) ) {
+ error = "Missing tr macro.";
+ break;
+ }
+ trmacro = argv[++n];
+ } else {
+ trmacro = &opt[1];
+ }
+ } else if ( opt == "version" ) {
+ fprintf( stderr,
+ "QtRuby User Interface Compiler v%s for Qt version %s\n", RBUIC_VERSION,
+ QT_VERSION_STR );
+ exit( 1 );
+ } else if ( opt == "help" ) {
+ break;
+ } else if ( opt == "fix" ) {
+ fix = true;
+ } else if ( opt[0] == 'p' ) {
+ uint tabstop;
+ bool ok;
+
+ if ( opt[1] == '\0' ) {
+ if ( !(n < argc-1) ) {
+ error = "Missing indent";
+ break;
+ }
+ tabstop = QCString(argv[++n]).toUInt(&ok);
+ } else
+ tabstop = opt.mid(1).toUInt(&ok);
+
+ if (ok)
+ indent.setTabStop(tabstop);
+ else
+ error = "Invalid indent";
+ } else if ( opt == "x" ) {
+ execCode = true;
+ } else {
+ error = "Unrecognized option";
+ }
+ } else {
+ if ( imagecollection )
+ images << argv[n];
+ else if ( fileName ) // can handle only one file
+ error = "Too many input files specified";
+ else
+ fileName = argv[n];
+ }
+ }
+
+ if ( argc < 2 || error || (!fileName && !imagecollection ) ) {
+ fprintf( stderr, "QtRuby user interface compiler.\n" );
+ if ( error )
+ fprintf( stderr, "rbuic: %s\n", error );
+
+ fprintf( stderr, "Usage: %s [options] [mode] <uifile>\n"
+ "\nGenerate implementation:\n"
+ " %s [options] <uifile>\n"
+ "Generate image collection:\n"
+ " %s [options] -embed <project> <image1> <image2> <image3> ...\n"
+ "\t<project>\tproject name\n"
+ "\t<image[0..n]>\timage files\n"
+ "Generate subclass implementation:\n"
+ " %s [options] -subimpl <classname> <uifile>\n"
+ "\t<classname>\tname of the subclass to generate\n"
+ "Options:\n"
+ "\t-o file\t\tWrite output to file rather than stdout\n"
+ "\t-p indent\tSet the indent in spaces (0 to use a tab)\n"
+ "\t-nofwd\t\tOmit imports of custom widgets\n"
+ "\t-kde\t\tUse kde widgets, require 'Korundum' extension\n"
+ "\t-tr func\tUse func(...) rather than trUtf8(...) for i18n\n"
+ "\t-x\t\tGenerate extra code to test the class\n"
+ "\t-version\tDisplay version of rbuic\n"
+ "\t-help\t\tDisplay this information\n"
+ , argv[0], argv[0], argv[0], argv[0]);
+ exit( 1 );
+ }
+
+ Uic::setIndent(indent);
+
+ QFile fileOut;
+ if ( outputFile ) {
+ fileOut.setName( outputFile );
+ if (!fileOut.open( IO_WriteOnly ) )
+ qFatal( "rbuic: Could not open output file '%s'", outputFile );
+ } else {
+ fileOut.open( IO_WriteOnly, stdout );
+ }
+ QTextStream out( &fileOut );
+
+ if ( imagecollection ) {
+ out.setEncoding( QTextStream::Latin1 );
+ Uic::embed( out, projectName, images );
+ return 0;
+ }
+
+
+ out.setEncoding( QTextStream::UnicodeUTF8 );
+ QFile file( fileName );
+ if ( !file.open( IO_ReadOnly ) )
+ qFatal( "rbuic: Could not open file '%s' ", fileName );
+
+ QDomDocument doc;
+ QString errMsg;
+ int errLine;
+ if ( !doc.setContent( &file, &errMsg, &errLine ) )
+ qFatal( QString("rbuic: Failed to parse %s: ") + errMsg + QString (" in line %d\n"), fileName, errLine );
+
+ DomTool::fixDocument( doc );
+
+ if ( fix ) {
+ out << doc.toString();
+ return 0;
+ }
+
+ if ( !subcl ) {
+ out << "# Form implementation generated from reading ui file '" << fileName << "'" << endl;
+ out << "#" << endl;
+ out << "# Created: " << QDateTime::currentDateTime().toString() << endl;
+ out << "# by: The QtRuby User Interface Compiler (rbuic)" << endl;
+ out << "#" << endl;
+ out << "# WARNING! All changes made in this file will be lost!" << endl;
+ out << endl;
+ }
+ out << endl;
+
+ Uic uic( fileName, out, doc, subcl, trmacro ? trmacro : "trUtf8", className, nofwd, uicClass, useKDE );
+
+ if (execCode) {
+ out << endl;
+ out << indent << "if $0 == __FILE__" << endl;
+ ++indent;
+ if (uic.hasKDEwidget) {
+ out << indent << "about = KDE::AboutData.new(\"" << uicClass.lower() << "\", \"" << uicClass << "\", \"0.1\")" << endl;
+ out << indent << "KDE::CmdLineArgs.init(ARGV, about)" << endl;
+ out << indent << "a = KDE::Application.new" << endl;
+ } else {
+ out << indent << "a = Qt::Application.new(ARGV)" << endl;
+ }
+ QString s;
+ getDBConnections( uic, s);
+ out << s;
+ out << indent << "w = " << (subcl? QString::fromLatin1(className) : uicClass) << ".new" << endl;
+ out << indent << "a.mainWidget = w" << endl;
+ out << indent << "w.show" << endl;
+ out << indent << "a.exec" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ }
+
+ return 0;
+}
+
+void getDBConnections( Uic& uic, QString& s)
+{
+ int num = 0;
+ for ( QStringList::Iterator it = uic.dbConnections.begin(); it != uic.dbConnections.end(); ++it ) {
+ if ( !(*it).isEmpty()) {
+ QString inc = (num ? QString::number(num+1) : QString::null);
+ s += "\n # Connection to database " + (*it) + "\n\n";
+ s += " DRIVER" + inc + " =\t\t'QMYSQL3'" + (inc?"":" # appropriate driver") + "\n";
+ s += " DATABASE" + inc + " =\t\t'foo'" + (inc?"":" # name of your database") + "\n";
+ s += " USER" + inc + "=\t\t'john'" + (inc?"":" # username") + "\n";
+ s += " PASSWORD" + inc + "=\t\t'ZxjGG34s'" + (inc?"":" # password for USER") + "\n";
+ s += " HOST" + inc + "=\t\t'localhost'" + (inc?"":" # host on which the database is running") + "\n";
+ s += "\n";
+ s += " $db" + inc + " = Qt::SqlDatabase.addDatabase( DRIVER" + inc;
+ if (inc)
+ s+= ", '" + (*it) + "'";
+ s += " )\n";
+ s += " $db" + inc + ".databaseName = DATABASE" + inc + "\n";
+ s += " $db" + inc + ".userName = USER" + inc + "\n";
+ s += " $db" + inc + ".password = PASSWORD" + inc + "\n";
+ s += " $db" + inc + ".hostName = HOST" + inc + "\n";
+ s += "\n";
+ s += " if !$db" + inc + ".open\n";
+ s += " Qt::MessageBox.information( nil, 'Unable to open database',\n";
+ s += " $db" + inc + ".lastError().databaseText() + \"\\n\")\n";
+ s += " exit 1\n";
+ s += " end\n";
+ s += "\n";
+ num++;
+ }
+ }
+}
+
diff --git a/qtruby/rubylib/designer/rbuic/object.cpp b/qtruby/rubylib/designer/rbuic/object.cpp
new file mode 100644
index 00000000..ba8e38b7
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/object.cpp
@@ -0,0 +1,750 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+** 08/2003 : Initial release of rbuic, the QtRuby User Interface Compiler,
+** a work derived from the PerlQt puic.
+**
+** Richard Dale
+**
+**********************************************************************/
+
+#include "uic.h"
+#include "parser.h"
+#include "widgetdatabase.h"
+#include "domtool.h"
+#include <qregexp.h>
+#include <qsizepolicy.h>
+#include <qstringlist.h>
+#define NO_STATIC_COLORS
+#include <globaldefs.h>
+#include <zlib.h>
+
+/*!
+ Creates a declaration for the object given in \a e.
+
+ Children are not traversed recursively.
+
+ \sa createObjectImpl()
+ */
+void Uic::createObjectDecl( const QDomElement& e )
+{
+ if ( e.tagName() == "vbox" || e.tagName() == "hbox" || e.tagName() == "grid" ) {
+ out << indent << registerObject(getLayoutName(e) ) << endl;
+ } else {
+ QString objClass = getClassName( e );
+ if ( objClass.isEmpty() )
+ return;
+ QString objName = getObjectName( e );
+ if ( objName.isEmpty() )
+ return;
+ // ignore QLayoutWidgets
+ if ( objClass == "Qt::LayoutWidget" )
+ return;
+
+ // register the object and unify its name
+ objName = registerObject( objName );
+ out << indent << objName << endl;
+ }
+}
+
+/*!
+ Creates a QtRuby attribute declaration for the object given in \a e.
+
+ Children are not traversed recursively.
+
+ */
+void Uic::createAttrDecl( const QDomElement& e )
+{
+ if ( e.tagName() == "vbox" || e.tagName() == "hbox" || e.tagName() == "grid" ) {
+// out << indent << registerObject(getLayoutName(e) ) << endl;
+ } else {
+ QString objClass = getClassName( e );
+ if ( objClass.isEmpty() )
+ return;
+ QString objName = getObjectName( e );
+ if ( objName.isEmpty() )
+ return;
+ // ignore QLayoutWidgets
+ if ( objClass == "Qt::LayoutWidget" )
+ return;
+ // register the object and unify its name
+ objName = registerObject( objName );
+ QString attr(objName);
+ attr.replace(QChar('@'), "attr_reader :");
+
+ out << indent << attr << endl;
+ QDomElement n = getObjectProperty( e, "font");
+// if ( !n.isNull() )
+// out << indent << objName + "_font" << endl;
+ }
+}
+
+
+/*!
+ Creates an implementation for the object given in \a e.
+
+ Traverses recursively over all children.
+
+ Returns the name of the generated child object.
+
+ \sa createObjectDecl()
+ */
+
+static bool createdCentralWidget = false;
+
+QString Uic::createObjectImpl( const QDomElement &e, const QString& parentClass, const QString& par, const QString& layout )
+{
+ QString parent( par );
+ if ( parent == "self" && isMainWindow ) {
+ if ( !createdCentralWidget )
+ out << indent << "setCentralWidget(Qt::Widget.new(self, \"qt_central_widget\"))" << endl;
+ createdCentralWidget = true;
+ parent = "centralWidget()";
+ }
+ QDomElement n;
+ QString objClass, objName, fullObjName;
+ int numItems = 0;
+ int numColumns = 0;
+ int numRows = 0;
+
+ if ( layouts.contains( e.tagName() ) )
+ return createLayoutImpl( e, parentClass, parent, layout );
+
+ objClass = getClassName( e );
+ if ( objClass.isEmpty() )
+ return objName;
+ objName = getObjectName( e );
+
+ QString definedName = objName;
+ bool isTmpObject = objName.isEmpty() || objClass == "Qt::LayoutWidget";
+ if ( isTmpObject ) {
+ if ( objClass[0] == 'Q' )
+ objName = objClass.mid( 4 );
+ else
+ objName = objClass.lower();
+ }
+
+ bool isLine = objClass == "Line";
+ if ( isLine )
+ objClass = "Qt::Frame";
+
+ out << endl;
+ if ( objClass == "Qt::LayoutWidget" ) {
+ if ( layout.isEmpty() ) {
+ // register the object and unify its name
+ objName = registerObject( objName );
+ out << indent << (isTmpObject ? QString::fromLatin1("") : QString::null) << objName << " = Qt::Widget.new(" << parent << ", '" << objName << "')" << endl;
+ } else {
+ // the layout widget is not necessary, hide it by creating its child in the parent
+ QString result;
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if (tags.contains( n.tagName() ) )
+ result = createObjectImpl( n, parentClass, parent, layout );
+ }
+ return result;
+ }
+
+ // Layouts don't go into the class instance dictionary.
+ // FIXME PerlQt: fullObjName isn't used anymore => remove
+ fullObjName = objName;
+ } else if ( objClass != "Qt::ToolBar" && objClass != "Qt::MenuBar" ) {
+ // register the object and unify its name
+ objName = registerObject( objName );
+
+ // Temporary objects don't go into the class instance dictionary.
+ fullObjName = objName;
+
+ out << indent << fullObjName << " = " << createObjectInstance( objClass, parent, objName ) << endl;
+ }
+ else
+ fullObjName = objName;
+
+ if ( objClass == "Qt::AxWidget" ) {
+ QString controlId;
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "property" && n.attribute( "name" ) == "control" ) {
+ controlId = n.firstChild().toElement().text();
+ }
+ }
+ out << " ";
+ out << fullObjName << ".setControl(\"" << controlId << "\")" << endl;
+ }
+
+ lastItem = "nil";
+ // set the properties and insert items
+ bool hadFrameShadow = false;
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "property" ) {
+ bool stdset = stdsetdef;
+ if ( n.hasAttribute( "stdset" ) )
+ stdset = toBool( n.attribute( "stdset" ) );
+ QString prop = n.attribute("name");
+ if ( prop == "database" )
+ continue;
+ QString value = setObjectProperty( objClass, objName, prop, n.firstChild().toElement(), stdset );
+ if ( value.isEmpty() )
+ continue;
+ if ( prop == "name" )
+ continue;
+ if ( isLine && prop == "frameShadow" )
+ hadFrameShadow = true;
+ if ( prop == "buddy" && value[0] == '\"' && value[(int)value.length()-1] == '\"' ) {
+ buddies << Buddy( objName, value.mid(1, value.length() - 2 ) );
+ continue;
+ }
+ if ( isLine && prop == "orientation" ) {
+ prop = "frameShape";
+ if ( value.right(10) == "Horizontal" )
+ value = "Qt::Frame::HLine";
+ else
+ value = "Qt::Frame::VLine";
+ if ( !hadFrameShadow ) {
+ prop = "frameStyle";
+ value += " | Qt::Frame::Sunken";
+ }
+ }
+ if ( prop == "buttonGroupId" ) {
+ if ( parentClass == "Qt::ButtonGroup" )
+ out << indent << parent << ".insert( " << fullObjName << "," << value << ")" << endl;
+ continue;
+ }
+ if ( prop == "frameworkCode" )
+ continue;
+ if ( objClass == "Qt::MultiLineEdit" &&
+ QRegExp("echoMode|hMargin|maxLength|maxLines|undoEnabled").exactMatch(prop) )
+ continue;
+
+ QString call = fullObjName + ".";
+ if (! call.startsWith("@")) {
+ call.prepend("@");
+ }
+
+ if ( stdset ) {
+ call += mkStdSet( prop ) + "( ";
+ call += value + " )";
+ } else {
+ call += "setProperty( \"" + prop + "\", Qt::Variant.new(" ;
+ call += value + " ) )";
+ }
+
+ if ( n.firstChild().toElement().tagName() == "string" ||
+ prop == "currentItem" ) {
+ trout << indent << call << endl;
+ } else {
+ out << indent << call << endl;
+ }
+ } else if ( n.tagName() == "item" ) {
+ QString call;
+ QString value;
+
+ if ( objClass.mid( 4 ) == "ListBox" ) {
+ call = createListBoxItemImpl( n, fullObjName, &value );
+ if ( !call.isEmpty() ) {
+ if ( numItems == 0 )
+ trout << indent << fullObjName << ".clear()" << endl;
+ trout << indent << call << endl;
+ }
+ } else if ( objClass.mid( 4 ) == "ComboBox" ) {
+ call = createListBoxItemImpl( n, fullObjName, &value );
+ if ( !call.isEmpty() ) {
+ if ( numItems == 0 )
+ trout << indent << fullObjName << ".clear()" << endl;
+ trout << indent << call << endl;
+ }
+ } else if ( objClass.mid( 4 ) == "IconView" ) {
+ call = createIconViewItemImpl( n, fullObjName );
+ if ( !call.isEmpty() ) {
+ if ( numItems == 0 )
+ trout << indent << fullObjName << ".clear()" << endl;
+ trout << indent << call << endl;
+ }
+ } else if ( objClass.mid( 4 ) == "ListView" ) {
+ call = createListViewItemImpl( n, fullObjName, QString::null );
+ if ( !call.isEmpty() ) {
+ if ( numItems == 0 )
+ trout << indent << fullObjName << ".clear()" << endl;
+ trout << call << endl;
+ }
+ }
+ if ( !call.isEmpty() )
+ numItems++;
+ } else if ( n.tagName() == "column" || n.tagName() == "row" ) {
+ QString call;
+ QString value;
+
+ if ( objClass.mid( 4 ) == "ListView" ) {
+ call = createListViewColumnImpl( n, fullObjName, &value );
+ if ( !call.isEmpty() ) {
+ out << call;
+ trout << indent << fullObjName << ".header().setLabel( "
+ << numColumns++ << ", " << value << " )\n";
+ }
+ } else if ( objClass == "Qt::Table" || objClass == "Qt::DataTable" ) {
+ bool isCols = ( n.tagName() == "column" );
+ call = createTableRowColumnImpl( n, fullObjName, &value );
+ if ( !call.isEmpty() ) {
+ out << call;
+ trout << indent << fullObjName << "."
+ << ( isCols ? "horizontalHeader" : "verticalHeader" )
+ << "().setLabel( "
+ << ( isCols ? numColumns++ : numRows++ )
+ << ", " << value << " )\n";
+ }
+ }
+ }
+ }
+
+ // create all children, some widgets have special requirements
+
+ if ( objClass == "Qt::TabWidget" ) {
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( tags.contains( n.tagName() ) ) {
+ QString page = createObjectImpl( n, objClass, fullObjName );
+ QString comment;
+ QString label = DomTool::readAttribute( n, "title", "", comment ).toString();
+ out << indent << fullObjName << ".insertTab(" << page << ", " << trcall( label ) << ")" << endl;
+ trout << indent << fullObjName << ".changeTab( " << page << ", "
+ << trcall( label, comment ) << " )" << endl;
+ }
+ }
+ } else if ( objClass == "Qt::WidgetStack" ) {
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( tags.contains( n.tagName() ) ) {
+ QString page = createObjectImpl( n, objClass, objName );
+ int id = DomTool::readAttribute( n, "id", "" ).toInt();
+ out << indent << fullObjName << ".addWidget( " << page << ", " << id << " )" << endl;
+ }
+ }
+ } else if ( objClass == "Qt::ToolBox" ) {
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( tags.contains( n.tagName() ) ) {
+ QString page = createObjectImpl( n, objClass, objName );
+ QString comment;
+ QString label = DomTool::readAttribute( n, "label", comment ).toString();
+ out << indent << fullObjName << ".addItem( " << page << ", \"\" )" << endl;
+ trout << indent << fullObjName << ".setItemLabel( " << fullObjName
+ << ".indexOf(" << page << "), " << trcall( label, comment )
+ << " )" << endl;
+ }
+ }
+ } else if ( objClass != "Qt::ToolBar" && objClass != "Qt::MenuBar" ) { // standard widgets
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( tags.contains( n.tagName() ) )
+ createObjectImpl( n, objClass, fullObjName );
+ }
+ }
+
+ return fullObjName;
+}
+
+
+
+/*!
+ Creates a set-call for property \a exclusiveProp of the object
+ given in \a e.
+
+ If the object does not have this property, the function does nothing.
+
+ Exclusive properties are used to generate the implementation of
+ application font or palette change handlers in createFormImpl().
+
+ */
+void Uic::createExclusiveProperty( const QDomElement & e, const QString& exclusiveProp )
+{
+ QDomElement n;
+ QString objClass = getClassName( e );
+ if ( objClass.isEmpty() )
+ return;
+ QString objName = getObjectName( e );
+ if ( objClass.isEmpty() )
+ return;
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "property" ) {
+ bool stdset = stdsetdef;
+ if ( n.hasAttribute( "stdset" ) )
+ stdset = toBool( n.attribute( "stdset" ) );
+ QString prop = n.attribute("name");
+ if ( prop != exclusiveProp )
+ continue;
+ QString value = setObjectProperty( objClass, objName, prop, n.firstChild().toElement(), stdset );
+ if ( value.isEmpty() )
+ continue;
+ out << indent << indent << objName << ".setProperty(\"" << prop << "\", Qt::Variant.new(" << value << "))" << endl;
+ }
+ }
+}
+
+
+/*! Attention: this function has to be in sync with
+ Resource::saveProperty() and DomTool::elementToVariant. If you
+ change one, change all.
+ */
+QString Uic::setObjectProperty( const QString& objClass, const QString& obj, const QString &prop, const QDomElement &e, bool stdset )
+{
+ QString v;
+ if ( e.tagName() == "rect" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ int x = 0, y = 0, w = 0, h = 0;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "x" )
+ x = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "y" )
+ y = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "width" )
+ w = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "height" )
+ h = n3.firstChild().toText().data().toInt();
+ n3 = n3.nextSibling().toElement();
+ }
+ v = "Qt::Rect.new(%1, %2, %3, %4)";
+ v = v.arg(x).arg(y).arg(w).arg(h);
+
+ } else if ( e.tagName() == "point" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ int x = 0, y = 0;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "x" )
+ x = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "y" )
+ y = n3.firstChild().toText().data().toInt();
+ n3 = n3.nextSibling().toElement();
+ }
+ v = "Qt::Point.new(%1, %2)";
+ v = v.arg(x).arg(y);
+ } else if ( e.tagName() == "size" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ int w = 0, h = 0;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "width" )
+ w = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "height" )
+ h = n3.firstChild().toText().data().toInt();
+ n3 = n3.nextSibling().toElement();
+ }
+ v = "Qt::Size.new(%1, %2)";
+ v = v.arg(w).arg(h);
+ } else if ( e.tagName() == "color" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ int r= 0, g = 0, b = 0;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "red" )
+ r = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "green" )
+ g = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "blue" )
+ b = n3.firstChild().toText().data().toInt();
+ n3 = n3.nextSibling().toElement();
+ }
+ v = "Qt::Color.new(%1, %2, %3)";
+ v = v.arg(r).arg(g).arg(b);
+ } else if ( e.tagName() == "font" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ QString fontname;
+ if ( !obj.isEmpty() ) {
+ fontname = obj + "_font";
+ out << indent << fontname << " = Qt::Font.new(" << obj << ".font())" << endl;
+ } else {
+ fontname = registerObject( "f" );
+ out << indent << fontname << " = Qt::Font.new(font())" << endl;
+ }
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "family" )
+ out << indent << fontname << ".setFamily(\"" << n3.firstChild().toText().data() << "\")" << endl;
+ else if ( n3.tagName() == "pointsize" )
+ out << indent << fontname << ".setPointSize(" << n3.firstChild().toText().data() << ")" << endl;
+ else if ( n3.tagName() == "bold" )
+ out << indent << fontname << ".setBold(" << mkBool( n3.firstChild().toText().data() ) << ")" << endl;
+ else if ( n3.tagName() == "italic" )
+ out << indent << fontname << ".setItalic(" << mkBool( n3.firstChild().toText().data() ) << ")" << endl;
+ else if ( n3.tagName() == "underline" )
+ out << indent << fontname << ".setUnderline(" << mkBool( n3.firstChild().toText().data() ) << ")" << endl;
+ else if ( n3.tagName() == "strikeout" )
+ out << indent << fontname << ".setStrikeOut(" << mkBool( n3.firstChild().toText().data() ) << ")" << endl;
+ n3 = n3.nextSibling().toElement();
+ }
+
+ if ( prop == "font" ) {
+ if ( !obj.isEmpty() )
+ out << indent << obj << ".setFont(" << fontname << ")" << endl;
+ else
+ out << indent << "setFont(" << fontname << ")" << endl;
+ } else {
+ v = fontname;
+ }
+ } else if ( e.tagName() == "string" ) {
+ QString txt = e.firstChild().toText().data();
+ QString com = getComment( e.parentNode() );
+
+ if ( prop == "toolTip" && objClass != "Qt::Action" && objClass != "Qt::ActionGroup" ) {
+ if ( !obj.isEmpty() )
+ trout << indent << "Qt::ToolTip.add( " << obj << ", "
+ << trcall( txt, com ) << " )" << endl;
+ else
+ trout << indent << "Qt::ToolTip.add( self, "
+ << trcall( txt, com ) << " )" << endl;
+ } else if ( prop == "whatsThis" && objClass != "Qt::Action" && objClass != "Qt::ActionGroup" ) {
+ if ( !obj.isEmpty() )
+ trout << indent << "Qt::WhatsThis.add(" << obj << ", " << trcall( txt, com ) << ")" << endl;
+ else
+ trout << indent << "Qt::WhatsThis.add(self," << trcall( txt, com ) << ")" << endl;
+ } else if (e.parentNode().toElement().attribute("name") == "accel") {
+ v = "Qt::KeySequence.new(" + trcall( txt, com ) + ")";
+ } else {
+ v = trcall( txt, com );
+ }
+ } else if ( e.tagName() == "cstring" ) {
+ v = "\"%1\"";
+ v = v.arg( e.firstChild().toText().data() );
+ } else if ( e.tagName() == "number" ) {
+ // FIXME: hack. QtRuby needs a QKeySequence to build an accel
+ if( e.parentNode().toElement().attribute("name") == "accel" )
+ v = "Qt::KeySequence.new(%1)";
+ else
+ v = "%1";
+ v = v.arg( e.firstChild().toText().data() );
+ } else if ( e.tagName() == "bool" ) {
+ if ( stdset )
+ v = "%1";
+ else
+ v = "Qt::Variant.new(%1, 0)";
+ v = v.arg( mkBool( e.firstChild().toText().data() ) );
+ } else if ( e.tagName() == "pixmap" ) {
+ v = e.firstChild().toText().data();
+ if( !externPixmaps )
+ v.prepend( '@' );
+ if ( !pixmapLoaderFunction.isEmpty() ) {
+ v.prepend( pixmapLoaderFunction + "(" + QString( externPixmaps ? "\"" : "" ) );
+ v.append( QString( externPixmaps ? "\"" : "" ) + ")" );
+ }
+ } else if ( e.tagName() == "iconset" ) {
+ v = "Qt::IconSet.new(%1)";
+ QString s = e.firstChild().toText().data();
+ if ( !pixmapLoaderFunction.isEmpty() ) {
+ s.prepend( pixmapLoaderFunction + "(" + QString( externPixmaps ? "\"" : "" ) );
+ s.append( QString( externPixmaps ? "\"" : "" ) + ")" );
+ } else {
+ s.prepend("@");
+ }
+ v = v.arg( s );
+ } else if ( e.tagName() == "image" ) {
+ v = e.firstChild().toText().data() + ".convertToImage()";
+ } else if ( e.tagName() == "enum" ) {
+ v = "%1::%2";
+ QString oc = objClass;
+ QString ev = e.firstChild().toText().data();
+ if ( oc == "Qt::ListView" && ev == "Manual" ) // #### workaround, rename QListView::Manual of WithMode enum in 3.0
+ oc = "Qt::ScrollView";
+ v = v.arg( oc ).arg( ev );
+ } else if ( e.tagName() == "set" ) {
+ QString keys( e.firstChild().toText().data() );
+ QStringList lst = QStringList::split( '|', keys );
+ v = "";
+#if defined(Q_CC_EDG)
+ // workaround for EDG bug reproduced with MIPSpro C++ 7.3.?
+ // and KAI C++ 4.0e that will be fixed in KAI C++ 4.0f
+ QStringList::Iterator it = lst.begin();
+ for ( ; it != lst.end(); ++it ) {
+#else
+ for ( QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) {
+#endif
+ v += objClass + "::" + *it;
+ if ( it != lst.fromLast() )
+ v += " | ";
+ }
+ v += "";
+ } else if ( e.tagName() == "sizepolicy" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ QSizePolicy sp;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "hsizetype" )
+ sp.setHorData( (QSizePolicy::SizeType)n3.firstChild().toText().data().toInt() );
+ else if ( n3.tagName() == "vsizetype" )
+ sp.setVerData( (QSizePolicy::SizeType)n3.firstChild().toText().data().toInt() );
+ else if ( n3.tagName() == "horstretch" )
+ sp.setHorStretch( n3.firstChild().toText().data().toInt() );
+ else if ( n3.tagName() == "verstretch" )
+ sp.setVerStretch( n3.firstChild().toText().data().toInt() );
+ n3 = n3.nextSibling().toElement();
+ }
+ QString tmp = (obj.isEmpty() ? QString::fromLatin1("self") : obj) + ".";
+ v = "Qt::SizePolicy.new(%1, %2, %3, %4, " + tmp + "sizePolicy().hasHeightForWidth())";
+ v = v.arg( (int)sp.horData() ).arg( (int)sp.verData() ).arg( sp.horStretch() ).arg( sp.verStretch() );
+ } else if ( e.tagName() == "palette" ) {
+ QPalette pal;
+ bool no_pixmaps = e.elementsByTagName( "pixmap" ).count() == 0;
+ QDomElement n;
+ if ( no_pixmaps ) {
+ n = e.firstChild().toElement();
+ while ( !n.isNull() ) {
+ QColorGroup cg;
+ if ( n.tagName() == "active" ) {
+ cg = loadColorGroup( n );
+ pal.setActive( cg );
+ } else if ( n.tagName() == "inactive" ) {
+ cg = loadColorGroup( n );
+ pal.setInactive( cg );
+ } else if ( n.tagName() == "disabled" ) {
+ cg = loadColorGroup( n );
+ pal.setDisabled( cg );
+ }
+ n = n.nextSibling().toElement();
+ }
+ }
+ if ( no_pixmaps && pal == QPalette( pal.active().button(), pal.active().background() ) ) {
+ v = "Qt::Palette.new(Qt::Color.new(%1,%2,%3), Qt::Color.new(%1,%2,%3))";
+ v = v.arg( pal.active().button().red() ).arg( pal.active().button().green() ).arg( pal.active().button().blue() );
+ v = v.arg( pal.active().background().red() ).arg( pal.active().background().green() ).arg( pal.active().background().blue() );
+ } else {
+ QString palette = "pal";
+ if ( !pal_used ) {
+ out << indent << palette << " = Qt::Palette.new()" << endl;
+ pal_used = true;
+ }
+ QString cg = "cg";
+ if ( !cg_used ) {
+ out << indent << cg << " = Qt::ColorGroup.new()" << endl;
+ cg_used = true;
+ }
+ n = e.firstChild().toElement();
+ while ( !n.isNull() && n.tagName() != "active" )
+ n = n.nextSibling().toElement();
+ createColorGroupImpl( cg, n );
+ out << indent << palette << ".setActive(" << cg << ")" << endl;
+
+ n = e.firstChild().toElement();
+ while ( !n.isNull() && n.tagName() != "inactive" )
+ n = n.nextSibling().toElement();
+ createColorGroupImpl( cg, n );
+ out << indent << palette << ".setInactive(" << cg << ")" << endl;
+
+ n = e.firstChild().toElement();
+ while ( !n.isNull() && n.tagName() != "disabled" )
+ n = n.nextSibling().toElement();
+ createColorGroupImpl( cg, n );
+ out << indent << palette << ".setDisabled(" << cg << ")" << endl;
+ v = palette;
+ }
+ } else if ( e.tagName() == "cursor" ) {
+ v = "Qt::Cursor.new(%1)";
+ v = v.arg( e.firstChild().toText().data() );
+ } else if ( e.tagName() == "date" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ int y, m, d;
+ y = m = d = 0;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "year" )
+ y = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "month" )
+ m = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "day" )
+ d = n3.firstChild().toText().data().toInt();
+ n3 = n3.nextSibling().toElement();
+ }
+ v = "Qt::Date.new(%1,%2,%3)";
+ v = v.arg(y).arg(m).arg(d);
+ } else if ( e.tagName() == "time" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ int h, m, s;
+ h = m = s = 0;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "hour" )
+ h = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "minute" )
+ m = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "second" )
+ s = n3.firstChild().toText().data().toInt();
+ n3 = n3.nextSibling().toElement();
+ }
+ v = "Qt::Time.new(%1, %2, %3)";
+ v = v.arg(h).arg(m).arg(s);
+ } else if ( e.tagName() == "datetime" ) {
+ QDomElement n3 = e.firstChild().toElement();
+ int h, mi, s, y, mo, d;
+ h = mi = s = y = mo = d = 0;
+ while ( !n3.isNull() ) {
+ if ( n3.tagName() == "hour" )
+ h = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "minute" )
+ mi = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "second" )
+ s = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "year" )
+ y = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "month" )
+ mo = n3.firstChild().toText().data().toInt();
+ else if ( n3.tagName() == "day" )
+ d = n3.firstChild().toText().data().toInt();
+ n3 = n3.nextSibling().toElement();
+ }
+ v = "Qt::DateTime.new(Qt::Date.new(%1, %2, %3), Qt::Time.new(%4, %5, %6))";
+ v = v.arg(y).arg(mo).arg(d).arg(h).arg(mi).arg(s);
+ } else if ( e.tagName() == "stringlist" ) {
+ QStringList l;
+ QDomElement n3 = e.firstChild().toElement();
+ QString listname;
+ if ( !obj.isEmpty() ) {
+ listname = obj + "_strlist";
+ out << indent << listname << " = [";
+ } else {
+ listname = "strlist";
+ out << indent << listname << " = [";
+ }
+ int i = 0;
+ while ( true ) {
+ if ( n3.tagName() == "string" )
+ {
+ out << "'" << n3.firstChild().toText().data().simplifyWhiteSpace() << "'";
+ n3 = n3.nextSibling().toElement();
+ i++;
+ if( n3.isNull() )
+ break;
+ else if( (i%3) == 0 )
+ {
+ ++indent;
+ out << "," << endl << indent;
+ --indent;
+ }
+ else if( n3.isNull() )
+ break;
+ else
+ out << ", ";
+ }
+ }
+ out << "]" << endl;
+ v = listname;
+ }
+ return v;
+}
+
+
+
+
+/*! Extracts a named object property from \a e.
+ */
+QDomElement Uic::getObjectProperty( const QDomElement& e, const QString& name )
+{
+ QDomElement n;
+ for ( n = e.firstChild().toElement();
+ !n.isNull();
+ n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "property" && n.toElement().attribute("name") == name )
+ return n;
+ }
+ return n;
+}
+
diff --git a/qtruby/rubylib/designer/rbuic/parser.cpp b/qtruby/rubylib/designer/rbuic/parser.cpp
new file mode 100644
index 00000000..b7869f75
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/parser.cpp
@@ -0,0 +1,71 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+** 08/2003 : Initial release of rbuic, the QtRuby User Interface Compiler,
+** a work derived from the PerlQt puic.
+**
+** Richard Dale
+**
+**********************************************************************/
+
+#include "parser.h"
+#include <qobject.h>
+#include <qstringlist.h>
+
+class NormalizeObject : public QObject
+{
+public:
+ NormalizeObject() : QObject() {}
+ static QCString normalizeSignalSlot( const char *signalSlot ) { return QObject::normalizeSignalSlot( signalSlot ); }
+};
+
+QString Parser::cleanArgs( const QString &func )
+{
+ QString slot( func );
+ int begin = slot.find( "(" ) + 1;
+ QString args = slot.mid( begin );
+ args = args.left( args.find( ")" ) );
+ QStringList lst = QStringList::split( ',', args );
+ QString res = slot.left( begin );
+ for ( QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) {
+ if ( it != lst.begin() )
+ res += ",";
+ QString arg = *it;
+ int pos = 0;
+ if ( ( pos = arg.find( "&" ) ) != -1 ) {
+ arg = arg.left( pos + 1 );
+ } else if ( ( pos = arg.find( "*" ) ) != -1 ) {
+ arg = arg.left( pos + 1 );
+ } else {
+ arg = arg.simplifyWhiteSpace();
+ if ( ( pos = arg.find( ':' ) ) != -1 )
+ arg = arg.left( pos ).simplifyWhiteSpace() + ":" + arg.mid( pos + 1 ).simplifyWhiteSpace();
+ QStringList l = QStringList::split( ' ', arg );
+ if ( l.count() == 2 ) {
+ if ( l[ 0 ] != "const" && l[ 0 ] != "unsigned" && l[ 0 ] != "var" )
+ arg = l[ 0 ];
+ } else if ( l.count() == 3 ) {
+ arg = l[ 0 ] + " " + l[ 1 ];
+ }
+ }
+ res += arg;
+ }
+ res += ")";
+
+ return QString::fromLatin1( NormalizeObject::normalizeSignalSlot( res.latin1() ) );
+}
diff --git a/qtruby/rubylib/designer/rbuic/parser.h b/qtruby/rubylib/designer/rbuic/parser.h
new file mode 100644
index 00000000..5a5671ad
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/parser.h
@@ -0,0 +1,33 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef PARSER_H
+#define PARSER_H
+
+#include <qstring.h>
+
+class Parser
+{
+public:
+ static QString cleanArgs( const QString &func );
+
+};
+
+#endif
diff --git a/qtruby/rubylib/designer/rbuic/rbuic.pro b/qtruby/rubylib/designer/rbuic/rbuic.pro
new file mode 100644
index 00000000..a9869ab0
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/rbuic.pro
@@ -0,0 +1,24 @@
+TEMPLATE = app
+CONFIG += qt console warn_on release professional
+HEADERS = uic.h \
+ widgetdatabase.h \
+ domtool.h \
+ parser.h \
+ widgetinterface.h
+
+SOURCES = main.cpp uic.cpp form.cpp object.cpp \
+ subclassing.cpp embed.cpp\
+ widgetdatabase.cpp \
+ domtool.cpp \
+ parser.cpp
+
+DEFINES += QT_INTERNAL_XML
+#include( ../../../src/qt_professional.pri )
+
+TARGET = rbuic
+DEFINES += UIC
+DESTDIR = /usr/bin
+
+#target.path=$$bins.path
+#INSTALLS += target
+
diff --git a/qtruby/rubylib/designer/rbuic/subclassing.cpp b/qtruby/rubylib/designer/rbuic/subclassing.cpp
new file mode 100644
index 00000000..a3ad25c3
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/subclassing.cpp
@@ -0,0 +1,197 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "uic.h"
+#include "parser.h"
+#include "widgetdatabase.h"
+#include "domtool.h"
+#include <qfile.h>
+#include <qstringlist.h>
+#include <qdatetime.h>
+#define NO_STATIC_COLORS
+#include <globaldefs.h>
+#include <qregexp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <zlib.h>
+
+
+/*!
+ Creates an implementation for a subclass \a subClass of the form
+ given in \a e
+
+ \sa createSubDecl()
+ */
+void Uic::createSubImpl( const QDomElement &e, const QString& subClass )
+{
+ QDomElement n;
+ QDomNodeList nl;
+ int i;
+ QStringList::Iterator it, it2, it3;
+
+ QString objClass = getClassName( e );
+ if ( objClass.isEmpty() )
+ return;
+ if (hasKDEwidget) {
+ out << indent << "require 'Korundum'" << endl;
+ } else {
+ out << indent << "require 'Qt'" << endl;
+ }
+ out << endl;
+ out << indent << "class " << subClass << " < " << nameOfClass << endl;
+
+ out << endl;
+ ++indent;
+
+ // constructor
+ if ( objClass == "Qt::Dialog" || objClass == "Qt::Wizard" ) {
+ out << indent << "# Constructs a " << subClass << " which is a child of 'parent', with the " << endl;
+ out << indent << "# name 'name' and widget flags set to 'fl' " << endl;
+ out << indent << "# " << endl;
+ out << indent << "# The " << objClass.mid(4).lower() << " will by default be modeless, unless you set 'modal' to" << endl;
+ out << indent << "# true to construct a modal " << objClass.mid(4).lower() << "." << endl;
+ out << indent << "def initialize(parent = nil, name = nil, modal = false, fl = 0)" << endl;
+ ++indent;
+ out << indent << "super" << endl;
+ } else {
+ out << indent << "# Constructs a " << subClass << " which is a child of 'parent', with the " << endl;
+ out << indent << "# name 'name' and widget flags set to 'fl' " << endl;
+ out << indent << "def initialize(parent = nil, name = nil, fl = 0)" << endl;
+ ++indent;
+ out << indent << "super" << endl;
+ }
+ --indent;
+ out << indent << "end" << endl;
+ out << endl;
+
+ // find additional slots
+ QStringList publicSlots, protectedSlots, privateSlots;
+ QStringList publicSlotTypes, protectedSlotTypes, privateSlotTypes;
+ QStringList publicSlotSpecifier, protectedSlotSpecifier, privateSlotSpecifier;
+ QMap<QString, QString> functionImpls;
+ nl = e.parentNode().toElement().elementsByTagName( "slot" );
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ n = nl.item(i).toElement();
+ if ( n.parentNode().toElement().tagName() != "slots"
+ && n.parentNode().toElement().tagName() != "connections" )
+ continue;
+ if ( n.attribute( "language", "C++" ) != "C++" )
+ continue;
+ QString returnType = n.attribute( "returnType", "void" );
+ QString slotName = n.firstChild().toText().data().stripWhiteSpace();
+ if ( slotName.endsWith( ";" ) )
+ slotName = slotName.left( slotName.length() - 1 );
+ QString specifier = n.attribute( "specifier" );
+ QString access = n.attribute( "access" );
+ if ( access == "protected" ) {
+ protectedSlots += slotName;
+ protectedSlotTypes += returnType;
+ protectedSlotSpecifier += specifier;
+ } else if ( access == "private" ) {
+ privateSlots += slotName;
+ privateSlotTypes += returnType;
+ privateSlotSpecifier += specifier;
+ } else {
+ publicSlots += slotName;
+ publicSlotTypes += returnType;
+ publicSlotSpecifier += specifier;
+ }
+ }
+
+
+ // compatibility with early 3.0 betas
+ nl = e.parentNode().toElement().elementsByTagName( "function" );
+ for ( i = 0; i < (int) nl.length(); i++ ) {
+ QString fname = n.attribute( "name" );
+ fname = Parser::cleanArgs( fname );
+ functionImpls.insert( fname, n.firstChild().toText().data() );
+ }
+ // create stubs for public additional slots
+ if ( !publicSlots.isEmpty() ) {
+ for ( it = publicSlots.begin(), it2 = publicSlotTypes.begin(), it3 = publicSlotSpecifier.begin();
+ it != publicSlots.end(); ++it, ++it2, ++it3 ) {
+ QString pure;
+ QString type = *it2;
+ if ( type.isEmpty() )
+ type = "void";
+ if ( *it3 == "non virtual" )
+ continue;
+ if ( isEmptyFunction( *it ) ) {
+ out << endl;
+ int astart = (*it).find('(');
+ out << indent << "def " << (*it).left(astart)<< "(*k)" << endl;
+ ++indent;
+ out << indent << "print(\"" << subClass << "." << (*it) << ": Not implemented yet.\\n\")" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ }
+ }
+ }
+
+ // create stubs for protected additional slots
+ if ( !protectedSlots.isEmpty() ) {
+ for ( it = protectedSlots.begin(), it2 = protectedSlotTypes.begin(), it3 = protectedSlotSpecifier.begin();
+ it != protectedSlots.end(); ++it, ++it2, ++it3 ) {
+ QString pure;
+ QString type = *it2;
+ if ( type.isEmpty() )
+ type = "void";
+ if ( *it3 == "non virtual" )
+ continue;
+ if ( isEmptyFunction( *it ) ) {
+ out << endl;
+ int astart = (*it).find('(');
+ out << indent << "def " << (*it).left(astart)<< "(*k)" << endl;
+ ++indent;
+ out << indent << "print(\"" << subClass << "." << (*it) << ": (Protected) Not implemented yet.\\n\")" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ out << indent << "protected :" << (*it).left(astart)<< endl;
+ }
+ }
+ }
+
+
+ // create stubs for private additional slots
+ if ( !privateSlots.isEmpty() ) {
+ for ( it = privateSlots.begin(), it2 = privateSlotTypes.begin(), it3 = privateSlotSpecifier.begin();
+ it != privateSlots.end(); ++it, ++it2, ++it3 ) {
+ QString pure;
+ QString type = *it2;
+ if ( type.isEmpty() )
+ type = "void";
+ if ( *it3 == "non virtual" )
+ continue;
+ if ( isEmptyFunction( *it ) ) {
+ out << endl;
+ int astart = (*it).find('(');
+ out << indent << "def " << (*it).left(astart)<< "(*k)" << endl;
+ ++indent;
+ out << indent << "print(\"" << subClass << "." << (*it) << ": (Private) Not implemented yet.\\n\")" << endl;
+ --indent;
+ out << indent << "end" << endl;
+ out << indent << "private :" << (*it).left(astart)<< endl;
+ }
+ }
+ }
+
+ --indent;
+ out << indent << "end" << endl;
+}
diff --git a/qtruby/rubylib/designer/rbuic/uic.cpp b/qtruby/rubylib/designer/rbuic/uic.cpp
new file mode 100644
index 00000000..e4f8eed7
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/uic.cpp
@@ -0,0 +1,1104 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+** Copyright (c) 2001 Phil Thompson <phil@river-bank.demon.co.uk>
+** Copyright (c) 2002 Germain Garand <germain@ebooksfrance.com>
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+/*
+** 06/2002 : Initial release of puic, the PerlQt User Interface Compiler,
+** a work derivated from uic (the Qt User Interface Compiler)
+** and pyuic (the PyQt User Interface Compiler).
+**
+** G.Garand
+**
+** 08/2003 : Initial release of rbuic, the QtRuby User Interface Compiler,
+** a work derived from the PerlQt puic.
+**
+** Richard Dale
+**
+**********************************************************************/
+
+#include "uic.h"
+#include "parser.h"
+#include "widgetdatabase.h"
+#include "domtool.h"
+#include <qfile.h>
+#include <qstringlist.h>
+#include <qdatetime.h>
+#define NO_STATIC_COLORS
+#include <globaldefs.h>
+#include <qregexp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <zlib.h>
+
+bool Uic::hasKDEwidget = false;
+bool Uic::isMainWindow = false;
+RubyIndent Uic::indent;
+
+
+// Re-calculate the indent string based on the current number and nature of the
+// indent.
+void RubyIndent::calc()
+{
+ indstr.truncate(0);
+
+ for (uint i = current; i > 0; --i)
+ if (tabStop == 0)
+ indstr += '\t';
+ else
+ for (uint t = 0; t < tabStop; ++t)
+ indstr += ' ';
+}
+
+
+QString Uic::getComment( const QDomNode& n )
+{
+ QDomNode child = n.firstChild();
+ while ( !child.isNull() ) {
+ if ( child.toElement().tagName() == "comment" )
+ return child.toElement().firstChild().toText().data();
+ child = child.nextSibling();
+ }
+ return QString::null;
+}
+
+QString Uic::mkBool( bool b )
+{
+ return b? "true" : "false";
+}
+
+QString Uic::mkBool( const QString& s )
+{
+ return mkBool( s == "true" || s == "1" );
+}
+
+bool Uic::toBool( const QString& s )
+{
+ return s == "true" || s.toInt() != 0;
+}
+
+QString Uic::fixString( const QString &str )
+{
+ QString s( str );
+ s.replace( QRegExp( "\\\\" ), "\\\\" );
+ s.replace( QRegExp( "\"" ), "\\\"" );
+ s.replace( QRegExp( "\r?\n" ), "\\n\" +\n" + indent + "\"" );
+ return "\"" + s + "\"";
+}
+
+QString Uic::trcall( const QString& sourceText, const QString& comment )
+{
+ if ( sourceText.isEmpty() && comment.isEmpty() )
+ return "nil";
+
+ if ( comment.isEmpty() )
+ return trmacro + "(" + fixString( sourceText ) + ")";
+ return trmacro + "(" + fixString( sourceText ) + "," + fixString( comment ) + ")";
+}
+
+QString Uic::mkStdSet( const QString& prop )
+{
+ return QString( "set" ) + prop[0].upper() + prop.mid(1);
+}
+
+
+
+bool Uic::isEmptyFunction( const QString& fname )
+{
+ QMap<QString, QString>::Iterator fit = functionImpls.find( Parser::cleanArgs( fname ) );
+ if ( fit != functionImpls.end() ) {
+ int begin = (*fit).find( "{" );
+ QString body = (*fit).mid( begin + 1, (*fit).findRev( "}" ) - begin - 1 );
+ return body.simplifyWhiteSpace().isEmpty();
+ }
+ // For now ruby functions are always empty, until a rubyeditor Qt Designer plugin exists..
+ return true;
+}
+
+
+
+/*!
+ \class Uic uic.h
+ \brief User Interface Compiler
+
+ The class Uic encapsulates the user interface compiler (uic).
+ */
+Uic::Uic( const QString &fn, QTextStream &outStream, QDomDocument doc,
+ bool subcl, const QString &trm, const QString& subClass,
+ bool omitForwardDecls, QString &uicClass, bool useKDE )
+ : out( outStream ), trout( &languageChangeBody ),
+ trmacro( trm ), nofwd( omitForwardDecls )
+{
+ Uic::hasKDEwidget = useKDE;
+ fileName = fn;
+ writeSlotImpl = true;
+ defMargin = BOXLAYOUT_DEFAULT_MARGIN;
+ defSpacing = BOXLAYOUT_DEFAULT_SPACING;
+ externPixmaps = false;
+
+ item_used = cg_used = pal_used = 0;
+
+ layouts << "hbox" << "vbox" << "grid";
+ tags = layouts;
+ tags << "widget";
+
+ pixmapLoaderFunction = getPixmapLoaderFunction( doc.firstChild().toElement() );
+ nameOfClass = getFormClassName( doc.firstChild().toElement() );
+
+ uiFileVersion = doc.firstChild().toElement().attribute("version");
+ stdsetdef = toBool( doc.firstChild().toElement().attribute("stdsetdef") );
+
+ QDomElement e = doc.firstChild().firstChild().toElement();
+ QDomElement widget;
+ while ( !e.isNull() ) {
+ if ( e.tagName() == "widget" ) {
+ widget = e;
+ } else if ( e.tagName() == "pixmapinproject" ) {
+ externPixmaps = true;
+ } else if ( e.tagName() == "layoutdefaults" ) {
+ defSpacing = e.attribute( "spacing", QString::number( defSpacing ) ).toInt();
+ defMargin = e.attribute( "margin", QString::number( defMargin ) ).toInt();
+ }
+ e = e.nextSibling().toElement();
+ }
+ e = widget;
+
+ if ( nameOfClass.isEmpty() )
+ nameOfClass = getObjectName( e );
+
+ uicClass = nameOfClass;
+
+ if ( subcl ) {
+ createSubImpl( e, subClass );
+ } else {
+ createFormImpl( e );
+ }
+}
+
+/*! Extracts a pixmap loader function from \a e
+ */
+QString Uic::getPixmapLoaderFunction( const QDomElement& e )
+{
+ QDomElement n;
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "pixmapfunction" )
+ return n.firstChild().toText().data();
+ }
+ return QString::null;
+}
+
+
+/*! Extracts the forms class name from \a e
+ */
+QString Uic::getFormClassName( const QDomElement& e )
+{
+ QDomElement n;
+ QString cn;
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "class" ) {
+ QString s = n.firstChild().toText().data();
+ int i;
+ while ( ( i = s.find(' ' )) != -1 )
+ s[i] = '_';
+ cn = s;
+ }
+ }
+ return cn;
+}
+
+/*! Extracts a Ruby class name from \a e.
+ */
+QString Uic::getClassName( const QDomElement& e )
+{
+ QString s = e.attribute( "class" );
+ if ( s.isEmpty() && e.tagName() == "toolbar" )
+ s = "Qt::ToolBar";
+ else if ( s.isEmpty() && e.tagName() == "menubar" )
+ s = "Qt::MenuBar";
+ else
+ {
+ QRegExp r("^([QK])(\\S+)");
+ if( r.search( s ) != -1 ) {
+ if (r.cap(1) == "K") {
+ hasKDEwidget = true;
+ s = "KDE::" + r.cap(2);
+ } else {
+ if (s.startsWith("Qext")) {
+ s = "Qext::" + r.cap(2).mid(4);
+ } else {
+ s = "Qt::" + r.cap(2);
+ }
+ }
+ }
+ }
+ return s;
+}
+
+
+
+/*! Returns TRUE if database framework code is generated, else FALSE.
+*/
+
+bool Uic::isFrameworkCodeGenerated( const QDomElement& e )
+{
+ QDomElement n = getObjectProperty( e, "frameworkCode" );
+ if ( n.attribute("name") == "frameworkCode" &&
+ !DomTool::elementToVariant( n.firstChild().toElement(), QVariant( true, 0 ) ).toBool() )
+ return false;
+ return true;
+}
+
+/*! Extracts an object name from \a e. It's stored in the 'name'
+ property.
+ */
+QString Uic::getObjectName( const QDomElement& e )
+{
+ QDomElement n = getObjectProperty( e, "name" );
+ if ( n.firstChild().toElement().tagName() == "cstring" )
+ return n.firstChild().toElement().firstChild().toText().data();
+ return QString::null;
+}
+
+/*! Extracts an layout name from \a e. It's stored in the 'name'
+ property of the preceeding sibling (the first child of a QLayoutWidget).
+ */
+QString Uic::getLayoutName( const QDomElement& e )
+{
+ QDomElement p = e.parentNode().toElement();
+ QString tail = QString::null;
+
+ if ( getClassName(p) != "Qt::LayoutWidget" )
+ tail = "Layout";
+
+ QDomElement n = getObjectProperty( p, "name" );
+ if ( n.firstChild().toElement().tagName() == "cstring" )
+ return n.firstChild().toElement().firstChild().toText().data() + tail;
+ return e.tagName();
+}
+
+
+QString Uic::getDatabaseInfo( const QDomElement& e, const QString& tag )
+{
+ QDomElement n;
+ QDomElement n1;
+ int child = 0;
+ // database info is a stringlist stored in this order
+ if ( tag == "connection" )
+ child = 0;
+ else if ( tag == "table" )
+ child = 1;
+ else if ( tag == "field" )
+ child = 2;
+ else
+ return QString::null;
+ n = getObjectProperty( e, "database" );
+ if ( n.firstChild().toElement().tagName() == "stringlist" ) {
+ // find correct stringlist entry
+ QDomElement n1 = n.firstChild().firstChild().toElement();
+ for ( int i = 0; i < child && !n1.isNull(); ++i )
+ n1 = n1.nextSibling().toElement();
+ if ( n1.isNull() )
+ return QString::null;
+ return n1.firstChild().toText().data();
+ }
+ return QString::null;
+}
+
+
+void Uic::registerLayouts( const QDomElement &e )
+{
+ if ( layouts.contains(e.tagName()) )
+ createObjectDecl(e);
+
+ QDomNodeList nl = e.childNodes();
+ for ( int i = 0; i < (int) nl.length(); ++i )
+ registerLayouts( nl.item(i).toElement() );
+}
+
+
+/*!
+ Returns include file for class \a className or a null string.
+ */
+QString Uic::getInclude( const QString& className )
+{
+ int wid = WidgetDatabase::idFromClassName( className );
+ if ( wid != -1 )
+ return WidgetDatabase::includeFile( wid );
+ return QString::null;
+}
+
+void Uic::createActionDecl( const QDomElement& e )
+{
+ QString objName = getObjectName( e );
+ if ( objName.isEmpty() )
+ return;
+ out << indent << objName << endl;
+ if ( e.tagName() == "actiongroup" ) {
+ for ( QDomElement n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "action" || n.tagName() == "actiongroup" )
+ createActionDecl( n );
+ }
+ }
+}
+
+void Uic::createActionImpl( const QDomElement &n, const QString &parent )
+{
+ for ( QDomElement ae = n; !ae.isNull(); ae = ae.nextSibling().toElement() ) {
+ QString objName = registerObject( getObjectName( ae ) );
+ if ( ae.tagName() == "action" )
+ out << indent << objName << "= Qt::Action.new(" << parent << ", \"" << objName.mid(1) << "\")" << endl;
+ else if ( ae.tagName() == "actiongroup" )
+ out << indent << objName << "= Qt::ActionGroup.new(" << parent << ", \"" << objName.mid(1) << "\")" << endl;
+ else
+ continue;
+ bool subActionsDone = false;
+ bool hasMenuText = false;
+ QString actionText;
+ for ( QDomElement n2 = ae.firstChild().toElement(); !n2.isNull(); n2 = n2.nextSibling().toElement() ) {
+ if ( n2.tagName() == "property" ) {
+ bool stdset = stdsetdef;
+ if ( n2.hasAttribute( "stdset" ) )
+ stdset = toBool( n2.attribute( "stdset" ) );
+ QString prop = n2.attribute("name");
+ if ( prop == "name" )
+ continue;
+ QString value = setObjectProperty( "Qt::Action", objName, prop, n2.firstChild().toElement(), stdset );
+ if ( value.isEmpty() )
+ continue;
+
+ QString call = objName + ".";
+ if ( stdset ) {
+ call += mkStdSet( prop ) + "(" + value + ")";
+ } else {
+ call += "setProperty( \"" + prop + "\", ";
+ call += "Qt::Variant.new(" + value + "))";
+ }
+
+ if (prop == "menuText")
+ hasMenuText = true;
+ else if (prop == "text")
+ actionText = value;
+
+ if ( n2.firstChild().toElement().tagName() == "string" ) {
+ trout << indent << call << endl;
+ } else {
+ out << indent << call << endl;
+ }
+ } else if ( !subActionsDone && ( n2.tagName() == "actiongroup" || n2.tagName() == "action" ) ) {
+ createActionImpl( n2, objName );
+ subActionsDone = true;
+ }
+ }
+ // workaround for loading pre-3.3 files expecting bogus QAction behavior
+ if (!hasMenuText && !actionText.isEmpty() && uiFileVersion < "3.3")
+ trout << indent << objName << ".setMenuText(" << actionText << ")" << endl;
+ }
+}
+
+QString get_dock( const QString &d )
+{
+ if ( d == "0" )
+ return "DockUnmanaged";
+ if ( d == "1" )
+ return "DockTornOff";
+ if ( d == "2" )
+ return "DockTop";
+ if ( d == "3" )
+ return "DockBottom";
+ if ( d == "4" )
+ return "DockRight";
+ if ( d == "5" )
+ return "DockLeft";
+ if ( d == "6" )
+ return "DockMinimized";
+ return "";
+}
+
+void Uic::createToolbarImpl( const QDomElement &n, const QString &parentClass, const QString &parent )
+{
+ QDomNodeList nl = n.elementsByTagName( "toolbar" );
+ for ( int i = 0; i < (int) nl.length(); i++ ) {
+ QDomElement ae = nl.item( i ).toElement();
+ QString dock = get_dock( ae.attribute( "dock" ) );
+ QString objName = "@" + getObjectName( ae );
+ out << indent << objName << " = Qt::ToolBar.new(\"\", self, " << dock << ")" << endl;
+ createObjectImpl( ae, parentClass, parent );
+ for ( QDomElement n2 = ae.firstChild().toElement(); !n2.isNull(); n2 = n2.nextSibling().toElement() ) {
+ if ( n2.tagName() == "action" ) {
+ out << indent << "@" << n2.attribute( "name" ) << ".addTo( " << objName << " )" << endl;
+ } else if ( n2.tagName() == "separator" ) {
+ out << indent << objName << ".addSeparator;" << endl;
+ } else if ( n2.tagName() == "widget" ) {
+ if ( n2.attribute( "class" ) != "Spacer" ) {
+ createObjectImpl( n2, "Qt::ToolBar", objName );
+ } else {
+ QString child = createSpacerImpl( n2, parentClass, parent, objName );
+ out << indent << "Qt::Application.sendPostedEvents( " << objName
+ << ", Qt::Event::ChildInserted)" << endl;
+ out << indent << objName << ".boxLayout().addItem(" << child << ")" << endl;
+ }
+ }
+ }
+ }
+}
+
+void Uic::createMenuBarImpl( const QDomElement &n, const QString &parentClass, const QString &parent )
+{
+ QString objName = "@" + getObjectName( n );
+ out << indent << objName << " = Qt::MenuBar.new( self, \"" << objName.mid(1) << "\" )" << endl;
+ createObjectImpl( n, parentClass, parent );
+ int i = 0;
+ QDomElement c = n.firstChild().toElement();
+ while ( !c.isNull() ) {
+ if ( c.tagName() == "item" ) {
+ QString itemName = "@" + c.attribute( "name" );
+ out << endl;
+ out << indent << itemName << " = Qt::PopupMenu.new( self )" << endl;
+ createPopupMenuImpl( c, parentClass, itemName );
+ out << indent << objName << ".insertItem( \"\", " << itemName << ", " << i << " )" << endl;
+ QString findItem(objName + ".findItem(%1)");
+ findItem = findItem.arg(i);
+ trout << indent << "if !" << findItem << ".nil?" << endl;
+ trout << indent << indent << findItem << ".setText( " << trcall( c.attribute( "text" ) ) << " )" << endl;
+ trout << indent << "end" << endl;
+ } else if ( c.tagName() == "separator" ) {
+ out << endl;
+ out << indent << objName << ".insertSeparator( " << i << " )" << endl;
+ }
+ c = c.nextSibling().toElement();
+ i++;
+ }
+}
+
+void Uic::createPopupMenuImpl( const QDomElement &e, const QString &parentClass, const QString &parent )
+{
+ int i = 0;
+ for ( QDomElement n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "action" || n.tagName() == "actiongroup" ) {
+ QDomElement n2 = n.nextSibling().toElement();
+ if ( n2.tagName() == "item" ) { // the action has a sub menu
+ QString itemName = "@" + n2.attribute( "name" );
+ QString itemText = n2.attribute( "text" );
+ out << indent << itemName << " = Qt::PopupMenu.new( self )" << endl;
+ out << indent << indent << parent << ".insertItem( @" << n.attribute( "name" ) << ".iconSet(),";
+ out << trcall( itemText ) << ", " << itemName << " )" << endl;
+ trout << indent << parent << ".changeItem( " << parent << ".idAt( " << i << " ), ";
+ trout << trcall( itemText ) << " )" << endl;
+ createPopupMenuImpl( n2, parentClass, itemName );
+ n = n2;
+ } else {
+ out << indent << "@" << n.attribute( "name" ) << ".addTo( " << parent << " )" << endl;
+ }
+ } else if ( n.tagName() == "separator" ) {
+ out << indent << parent << ".insertSeparator()" << endl;
+ }
+ ++i;
+ }
+}
+
+/*!
+ Creates implementation of an listbox item tag.
+*/
+
+QString Uic::createListBoxItemImpl( const QDomElement &e, const QString &parent,
+ QString *value )
+{
+ QDomElement n = e.firstChild().toElement();
+ QString txt;
+ QString com;
+ QString pix;
+ while ( !n.isNull() ) {
+ if ( n.tagName() == "property" ) {
+ QString attrib = n.attribute("name");
+ QVariant v = DomTool::elementToVariant( n.firstChild().toElement(), QVariant() );
+ if ( attrib == "text" ) {
+ txt = v.toString();
+ com = getComment( n );
+ } else if ( attrib == "pixmap" ) {
+ pix = v.toString();
+ if (!pix.isEmpty()) {
+ pix.prepend("@");
+ }
+ if ( !pix.isEmpty() && !pixmapLoaderFunction.isEmpty() ) {
+ pix.prepend( pixmapLoaderFunction + "(" + QString( externPixmaps ? "\"" : "" ) );
+ pix.append( QString( externPixmaps ? "\"" : "" ) + ")" );
+ }
+ }
+ }
+ n = n.nextSibling().toElement();
+ }
+
+ if ( value )
+ *value = trcall( txt, com );
+
+ if ( pix.isEmpty() )
+ return parent + ".insertItem(" + trcall( txt, com ) + ")";
+
+ return parent + ".insertItem(" + pix + ", " + trcall( txt, com ) + ")";
+}
+
+/*!
+ Creates implementation of an iconview item tag.
+*/
+
+QString Uic::createIconViewItemImpl( const QDomElement &e, const QString &parent )
+{
+ QDomElement n = e.firstChild().toElement();
+ QString txt;
+ QString com;
+ QString pix;
+ while ( !n.isNull() ) {
+ if ( n.tagName() == "property" ) {
+ QString attrib = n.attribute("name");
+ QVariant v = DomTool::elementToVariant( n.firstChild().toElement(), QVariant() );
+ if ( attrib == "text" ) {
+ txt = v.toString();
+ com = getComment( n );
+ } else if ( attrib == "pixmap" ) {
+ pix = v.toString();
+ if (!pix.isEmpty()) {
+ pix.prepend("@");
+ }
+ if ( !pix.isEmpty() && !pixmapLoaderFunction.isEmpty() ) {
+ pix.prepend( pixmapLoaderFunction + "(" + QString( externPixmaps ? "\"" : "" ) );
+ pix.append( QString( externPixmaps ? "\"" : "" ) + ")" );
+ }
+ }
+ }
+ n = n.nextSibling().toElement();
+ }
+
+ if ( pix.isEmpty() )
+ return "Qt::IconViewItem.new(" + parent + ", " + trcall( txt, com ) + ")";
+ else
+ return "Qt::IconViewItem.new(" + parent + ", " + trcall( txt, com ) + ", " + pix + ")";
+}
+
+/*!
+ Creates implementation of an listview item tag.
+*/
+
+QString Uic::createListViewItemImpl( const QDomElement &e, const QString &parent,
+ const QString &parentItem )
+{
+ QString s;
+
+ QDomElement n = e.firstChild().toElement();
+
+ bool hasChildren = e.elementsByTagName( "item" ).count() > 0;
+ QString item;
+
+ if ( hasChildren ) {
+ item = registerObject( "item" );
+ s = indent + item + " = ";
+ } else {
+ if (! item_used) {
+ // This is here to make the ruby generated names for 'item',
+ // the same as the original C++
+ item = registerObject( "item" );
+ item_used = true;
+ }
+ item = "item";
+ s = indent + item + " = ";
+ }
+
+ if ( !parentItem.isEmpty() )
+ s += "Qt::ListViewItem.new(" + parentItem + ", " + lastItem + ")\n";
+ else
+ s += "Qt::ListViewItem.new(" + parent + ", " + lastItem + ")\n";
+
+ QStringList textes;
+ QStringList pixmaps;
+ while ( !n.isNull() ) {
+ if ( n.tagName() == "property" ) {
+ QString attrib = n.attribute("name");
+ QVariant v = DomTool::elementToVariant( n.firstChild().toElement(), QVariant() );
+ if ( attrib == "text" )
+ textes << v.toString();
+ else if ( attrib == "pixmap" ) {
+ QString pix = v.toString();
+ if (!pix.isEmpty()) {
+ pix.prepend("@");
+ }
+ if ( !pix.isEmpty() && !pixmapLoaderFunction.isEmpty() ) {
+ pix.prepend( pixmapLoaderFunction + "(" + QString( externPixmaps ? "\"" : "" ) );
+ pix.append( QString( externPixmaps ? "\"" : "" ) + ")" );
+ }
+ pixmaps << pix;
+ }
+ } else if ( n.tagName() == "item" ) {
+ s += indent + item + ".setOpen(true)\n";
+ s += createListViewItemImpl( n, parent, item );
+ }
+ n = n.nextSibling().toElement();
+ }
+
+ for ( int i = 0; i < (int)textes.count(); ++i ) {
+ if ( !textes[ i ].isEmpty() )
+ s += indent + item + ".setText(" + QString::number( i ) + ", " + trcall( textes[ i ] ) + ")\n";
+ if ( !pixmaps[ i ].isEmpty() )
+ s += indent + item + ".setPixmap(" + QString::number( i ) + ", " + pixmaps[ i ] + ")\n";
+ }
+
+ lastItem = item;
+ return s;
+}
+
+/*!
+ Creates implementation of an listview column tag.
+*/
+
+QString Uic::createListViewColumnImpl( const QDomElement &e, const QString &parent,
+ QString *value )
+{
+ QDomElement n = e.firstChild().toElement();
+ QString txt;
+ QString com;
+ QString pix;
+ bool clickable = false, resizeable = false;
+ while ( !n.isNull() ) {
+ if ( n.tagName() == "property" ) {
+ QString attrib = n.attribute("name");
+ QVariant v = DomTool::elementToVariant( n.firstChild().toElement(), QVariant() );
+ if ( attrib == "text" ) {
+ txt = v.toString();
+ com = getComment( n );
+ } else if ( attrib == "pixmap" ) {
+ pix = v.toString();
+ if (!pix.isEmpty()) {
+ pix.prepend("@");
+ }
+ if ( !pix.isEmpty() && !pixmapLoaderFunction.isEmpty() ) {
+ pix.prepend( pixmapLoaderFunction + "(" + QString( externPixmaps ? "\"" : "" ) );
+ pix.append( QString( externPixmaps ? "\"" : "" ) + ")" );
+ }
+ } else if ( attrib == "clickable" )
+ clickable = v.toBool();
+ else if ( attrib == "resizable" || attrib == "resizeable" )
+ resizeable = v.toBool();
+ }
+ n = n.nextSibling().toElement();
+ }
+
+ if ( value )
+ *value = trcall( txt, com );
+
+ QString s;
+ s = indent + parent + ".addColumn(" + trcall( txt, com ) + ")\n";
+ if ( !pix.isEmpty() )
+ s += indent + parent + ".header().setLabel(" + parent + ".header().count() - 1," + pix + ", " + trcall( txt, com ) + ")\n";
+ if ( !clickable )
+ s += indent + parent + ".header().setClickEnabled( false, " + parent + ".header().count() - 1 )\n";
+ if ( !resizeable )
+ s += indent + parent + ".header().setResizeEnabled( false, " + parent + ".header().count() - 1 )\n";
+
+ return s;
+}
+
+QString Uic::createTableRowColumnImpl( const QDomElement &e, const QString &parent,
+ QString *value )
+{
+ QString objClass = getClassName( e.parentNode().toElement() );
+ QDomElement n = e.firstChild().toElement();
+ QString txt;
+ QString com;
+ QString pix;
+ QString field;
+ bool isRow = e.tagName() == "row";
+ while ( !n.isNull() ) {
+ if ( n.tagName() == "property" ) {
+ QString attrib = n.attribute("name");
+ QVariant v = DomTool::elementToVariant( n.firstChild().toElement(), QVariant() );
+ if ( attrib == "text" ) {
+ txt = v.toString();
+ com = getComment( n );
+ } else if ( attrib == "pixmap" ) {
+ pix = v.toString();
+ if ( !pix.isEmpty() && !pixmapLoaderFunction.isEmpty() ) {
+ pix.prepend( pixmapLoaderFunction + "(" + QString( externPixmaps ? "\"" : "" ) );
+ pix.append( QString( externPixmaps ? "\"" : "" ) + ")" );
+ }
+ } else if ( attrib == "field" )
+ field = v.toString();
+ }
+ n = n.nextSibling().toElement();
+ }
+
+ if ( value )
+ *value = trcall( txt, com );
+
+ // ### This generated code sucks! We have to set the number of
+ // rows/cols before and then only do setLabel/()
+ // ### careful, though, since QDataTable has an API which makes this code pretty good
+
+ QString s;
+ if ( isRow ) {
+ s = indent + parent + ".setNumRows(" + parent + ".numRows() + 1 )\n";
+ if ( pix.isEmpty() )
+ s += indent + parent + ".verticalHeader().setLabel(" + parent + ".numRows() - 1, "
+ + trcall( txt, com ) + ")\n";
+ else
+ s += indent + parent + ".verticalHeader().setLabel(" + parent + ".numRows() - 1, Qt::IconSet.new(@"
+ + pix + " ), " + trcall( txt, com ) + ")\n";
+ } else {
+ if ( objClass == "Qt::Table" ) {
+ s = indent + parent + ".setNumCols(" + parent + ".numCols() + 1)\n";
+ if ( pix.isEmpty() )
+ s += indent + parent + ".horizontalHeader().setLabel(" + parent + ".numCols() - 1, "
+ + trcall( txt, com ) + ")\n";
+ else
+ s += indent + parent + ".horizontalHeader().setLabel(" + parent + ".numCols() - 1, Qt::IconSet.new(@"
+ + pix + " ), " + trcall( txt, com ) + ")\n";
+ } else if ( objClass == "Qt::DataTable" ) {
+ if ( !txt.isEmpty() && !field.isEmpty() ) {
+ if ( pix.isEmpty() )
+ out << indent << parent << ".addColumn(" << fixString( field ) << ", " << trcall( txt, com ) << ")" << endl;
+ else
+ out << indent << parent << ".addColumn(" << fixString( field ) << ", " << trcall( txt, com ) << ", Qt::IconSet.new(@" << pix << "))" << endl;
+ }
+ }
+ }
+ return s;
+}
+
+/*!
+ Creates the implementation of a layout tag. Called from createObjectImpl().
+ */
+QString Uic::createLayoutImpl( const QDomElement &e, const QString& parentClass, const QString& parent, const QString& layout )
+{
+ QDomElement n;
+ QString objClass, objName;
+ objClass = e.tagName();
+
+ QString qlayout = "Qt::VBoxLayout.new";
+ if ( objClass == "hbox" )
+ qlayout = "Qt::HBoxLayout.new";
+ else if ( objClass == "grid" )
+ qlayout = "Qt::GridLayout.new";
+
+ bool isGrid = e.tagName() == "grid" ;
+ objName = registerObject( getLayoutName( e ) );
+ layoutObjects += objName;
+
+ QString margin = DomTool::readProperty( e, "margin", defMargin ).toString();
+ QString spacing = DomTool::readProperty( e, "spacing", defSpacing ).toString();
+ QString resizeMode = DomTool::readProperty( e, "resizeMode", QString::null ).toString();
+
+ QString optcells;
+ if ( isGrid )
+ optcells = "1, 1, ";
+ if ( (parentClass == "Qt::GroupBox" || parentClass == "Qt::ButtonGroup") && layout.isEmpty() ) {
+ // special case for group box
+ out << indent << parent << ".setColumnLayout( 0, Qt::Vertical )" << endl;
+ out << indent << parent << ".layout().setSpacing(" << spacing << ")" << endl;
+ out << indent << parent << ".layout().setMargin(" << margin << ")" << endl;
+ out << indent << objName << " = " << qlayout << "(" << parent << ".layout() )" << endl;
+ out << indent << objName << ".setAlignment( AlignTop )" << endl;
+ } else {
+ out << indent << objName << " = " << qlayout << "(";
+ if ( layout.isEmpty() )
+ out << parent;
+ else {
+ out << "nil";
+ if ( !DomTool::hasProperty( e, "margin" ) )
+ margin = "0";
+ }
+ out << ", " << optcells << margin << ", " << spacing << ", '" << objName.mid(1) << "')" << endl;
+ }
+ if ( !resizeMode.isEmpty() )
+ out << indent << objName << ".setResizeMode( Qt::Layout::" << resizeMode << " )" << endl;
+
+ if ( !isGrid ) {
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "spacer" ) {
+ QString child = createSpacerImpl( n, parentClass, parent, objName );
+ out << indent << objName << ".addItem(" << child << ")" << endl;
+ } else if ( tags.contains( n.tagName() ) ) {
+ QString child = createObjectImpl( n, parentClass, parent, objName );
+ if ( isLayout( child ) )
+ out << indent << objName << ".addLayout(" << child << ")" << endl;
+ else
+ out << indent << objName << ".addWidget(" << child << ")" << endl;
+ }
+ }
+ } else {
+ for ( n = e.firstChild().toElement(); !n.isNull(); n = n.nextSibling().toElement() ) {
+ QDomElement ae = n;
+ int row = ae.attribute( "row" ).toInt();
+ int col = ae.attribute( "column" ).toInt();
+ int rowspan = ae.attribute( "rowspan" ).toInt();
+ int colspan = ae.attribute( "colspan" ).toInt();
+ if ( rowspan < 1 )
+ rowspan = 1;
+ if ( colspan < 1 )
+ colspan = 1;
+ if ( n.tagName() == "spacer" ) {
+ QString child = createSpacerImpl( n, parentClass, parent, objName );
+ if ( rowspan * colspan != 1 )
+ out << indent << objName << ".addMultiCell(" << child << ", "
+ << row << ", " << row + rowspan - 1 << ", " << col << ", " << col + colspan - 1 << ")" << endl;
+ else
+ out << indent << objName << ".addItem(" << child << ", "
+ << row << ", " << col << ")" << endl;
+ } else if ( tags.contains( n.tagName() ) ) {
+ QString child = createObjectImpl( n, parentClass, parent, objName );
+ out << endl;
+ QString o = "Widget";
+ if ( isLayout( child ) )
+ o = "Layout";
+ if ( rowspan * colspan != 1 )
+ out << indent << objName << ".addMultiCell" << o << "(" << child << ", "
+ << row << ", " << row + rowspan - 1 << ", " << col << ", " << col + colspan - 1 << ")" << endl;
+ else
+ out << indent << objName << ".add" << o << "(" << child << ", "
+ << row << ", " << col << ")" << endl;
+ }
+ }
+ }
+
+ return objName;
+}
+
+
+
+QString Uic::createSpacerImpl( const QDomElement &e, const QString& /*parentClass*/, const QString& /*parent*/, const QString& /*layout*/)
+{
+ QDomElement n;
+ QString objClass, objName;
+ objClass = e.tagName();
+ objName = registerObject( getObjectName( e ) );
+
+ QSize size = DomTool::readProperty( e, "sizeHint", QSize( 0, 0 ) ).toSize();
+ QString sizeType = DomTool::readProperty( e, "sizeType", "Expanding" ).toString();
+ bool isVspacer = DomTool::readProperty( e, "orientation", "Horizontal" ) == "Vertical";
+
+ if ( sizeType != "Expanding" && sizeType != "MinimumExpanding" &&
+ DomTool::hasProperty( e, "geometry" ) ) { // compatibility Qt 2.2
+ QRect geom = DomTool::readProperty( e, "geometry", QRect(0,0,0,0) ).toRect();
+ size = geom.size();
+ }
+
+ if ( isVspacer )
+ out << indent << objName << " = Qt::SpacerItem.new("
+ << size.width() << ", " << size.height()
+ << ", Qt::SizePolicy::Minimum, Qt::SizePolicy::" << sizeType << ")" << endl;
+ else
+ out << indent << objName << " = Qt::SpacerItem.new("
+ << size.width() << ", " << size.height()
+ << ", Qt::SizePolicy::" << sizeType << ", Qt::SizePolicy::Minimum)" << endl;
+
+ return objName;
+}
+
+static const char* const ColorRole[] = {
+ "Foreground", "Button", "Light", "Midlight", "Dark", "Mid",
+ "Text", "BrightText", "ButtonText", "Base", "Background", "Shadow",
+ "Highlight", "HighlightedText", "Link", "LinkVisited", 0
+};
+
+
+/*!
+ Creates a colorgroup with name \a name from the color group \a cg
+ */
+void Uic::createColorGroupImpl( const QString& name, const QDomElement& e )
+{
+ QColorGroup cg;
+ int r = -1;
+ QDomElement n = e.firstChild().toElement();
+ QString color;
+ while ( !n.isNull() ) {
+ if ( n.tagName() == "color" ) {
+ r++;
+ QColor col = DomTool::readColor( n );
+ color = "Qt::Color.new(%1,%2,%3)";
+ color = color.arg( col.red() ).arg( col.green() ).arg( col.blue() );
+ if ( col == white )
+ color = "white";
+ else if ( col == black )
+ color = "black";
+ if ( n.nextSibling().toElement().tagName() != "pixmap" ) {
+ out << indent << name << ".setColor(Qt::ColorGroup::" << ColorRole[r] << ", " << color << ")" << endl;
+ }
+ } else if ( n.tagName() == "pixmap" ) {
+ QString pixmap = n.firstChild().toText().data();
+ pixmap.prepend("@");
+ if ( !pixmapLoaderFunction.isEmpty() ) {
+ pixmap.prepend( pixmapLoaderFunction + "(" + QString( externPixmaps ? "\"" : "" ) );
+ pixmap.append( QString( externPixmaps ? "\"" : "" ) + ")" );
+ }
+ out << indent << name << ".setBrush(Qt::ColorGroup::"
+ << ColorRole[r] << ", Qt::Brush.new(" << color << ", " << pixmap << "))" << endl;
+ }
+ n = n.nextSibling().toElement();
+ }
+}
+
+/*!
+ Auxiliary function to load a color group. The colorgroup must not
+ contain pixmaps.
+ */
+QColorGroup Uic::loadColorGroup( const QDomElement &e )
+{
+ QColorGroup cg;
+ int r = -1;
+ QDomElement n = e.firstChild().toElement();
+ QColor col;
+ while ( !n.isNull() ) {
+ if ( n.tagName() == "color" ) {
+ r++;
+ cg.setColor( (QColorGroup::ColorRole)r, (col = DomTool::readColor( n ) ) );
+ }
+ n = n.nextSibling().toElement();
+ }
+ return cg;
+}
+
+/*! Returns TRUE if the widget properties specify that it belongs to
+ the database \a connection and \a table.
+*/
+
+bool Uic::isWidgetInTable( const QDomElement& e, const QString& connection, const QString& table )
+{
+ QString conn = getDatabaseInfo( e, "connection" );
+ QString tab = getDatabaseInfo( e, "table" );
+ if ( conn == connection && tab == table )
+ return true;
+ return false;
+}
+
+/*!
+ Registers all database connections, cursors and forms.
+*/
+
+void Uic::registerDatabases( const QDomElement& e )
+{
+ QDomElement n;
+ QDomNodeList nl;
+ int i;
+ nl = e.parentNode().toElement().elementsByTagName( "widget" );
+ for ( i = 0; i < (int) nl.length(); ++i ) {
+ n = nl.item(i).toElement();
+ QString conn = getDatabaseInfo( n, "connection" );
+ QString tab = getDatabaseInfo( n, "table" );
+ QString fld = getDatabaseInfo( n, "field" );
+ if ( !conn.isNull() ) {
+ dbConnections += conn;
+ if ( !tab.isNull() ) {
+ dbCursors[conn] += tab;
+ if ( !fld.isNull() )
+ dbForms[conn] += tab;
+ }
+ }
+ }
+}
+
+/*!
+ Registers an object with name \a name.
+
+ The returned name is a valid variable identifier, as similar to \a
+ name as possible and guaranteed to be unique within the form.
+
+ \sa registeredName(), isObjectRegistered()
+ */
+QString Uic::registerObject( const QString& name )
+{
+ if ( objectNames.isEmpty() ) {
+ // some temporary variables we need
+ objectNames += "img";
+ objectNames += "item";
+ objectNames += "cg";
+ objectNames += "pal";
+ }
+ QString result("@");
+ result += name;
+ int i;
+ while ( ( i = result.find(' ' )) != -1 ) {
+ result[i] = '_';
+ }
+
+ if ( objectNames.contains( result ) ) {
+ int i = 2;
+ while ( objectNames.contains( result + "_" + QString::number(i) ) )
+ i++;
+ result += "_";
+ result += QString::number(i);
+ }
+ objectNames += result;
+ objectMapper.insert( name, result );
+ return result;
+}
+
+/*!
+ Returns the registered name for the original name \a name
+ or \a name if \a name wasn't registered.
+
+ \sa registerObject(), isObjectRegistered()
+ */
+QString Uic::registeredName( const QString& name )
+{
+ if ( !objectMapper.contains( name ) )
+ return name;
+ return objectMapper[name];
+}
+
+/*!
+ Returns whether the object \a name was registered yet or not.
+ */
+bool Uic::isObjectRegistered( const QString& name )
+{
+ return objectMapper.contains( name );
+}
+
+
+/*!
+ Unifies the entries in stringlist \a list. Should really be a QStringList feature.
+ */
+QStringList Uic::unique( const QStringList& list )
+{
+ QStringList result;
+ if ( list.isEmpty() )
+ return result;
+ QStringList l = list;
+ l.sort();
+ result += l.first();
+ for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
+ if ( *it != result.last() )
+ result += *it;
+ }
+ return result;
+}
+
+
+
+/*!
+ Creates an instance of class \a objClass, with parent \a parent and name \a objName
+ */
+QString Uic::createObjectInstance( const QString& objClass, const QString& parent, const QString& objName )
+{
+
+ if ( objClass.mid( 4 ) == "ComboBox" ) {
+ return objClass + ".new(false, " + parent + ", \"" + objName.mid(1) + "\")";
+ }
+ return objClass + ".new(" + parent + ", \"" + objName.mid(1) + "\")";
+}
+
+bool Uic::isLayout( const QString& name ) const
+{
+ return layoutObjects.contains( name );
+}
diff --git a/qtruby/rubylib/designer/rbuic/uic.h b/qtruby/rubylib/designer/rbuic/uic.h
new file mode 100644
index 00000000..707df590
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/uic.h
@@ -0,0 +1,181 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+** Copyright (c) 2001 Phil Thompson <phil@river-bank.demon.co.uk>
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef UIC_H
+#define UIC_H
+#include <qdom.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qmap.h>
+#include <qtextstream.h>
+#include <qpalette.h>
+
+
+class RubyIndent
+{
+public:
+ RubyIndent() : tabStop(4), current(0) {calc();}
+
+ void setTabStop(uint n) {tabStop = n; calc();}
+ void operator++() {++current; calc();}
+ void operator--() {--current; calc();}
+ operator QString() {return indstr;}
+
+private:
+ uint tabStop;
+ uint current;
+ QString indstr;
+
+ void calc();
+};
+
+
+class Uic : public Qt
+{
+public:
+ Uic( const QString &fn, QTextStream& out, QDomDocument doc, bool subcl,
+ const QString &trm, const QString& subclname, bool omitForwardDecls,
+ QString &uicClass, bool useKDE );
+
+ static void setIndent(const RubyIndent &rubyind) {indent = rubyind;}
+
+ void createFormImpl( const QDomElement &e );
+
+ void createSubImpl( const QDomElement &e, const QString& subclname );
+
+ void createObjectDecl( const QDomElement& e );
+ void createAttrDecl( const QDomElement& e );
+ void createActionDecl( const QDomElement& e );
+ void createActionImpl( const QDomElement& e, const QString &parent );
+ void createToolbarImpl( const QDomElement &e, const QString &parentClass, const QString &parent );
+ void createMenuBarImpl( const QDomElement &e, const QString &parentClass, const QString &parent );
+ void createPopupMenuImpl( const QDomElement &e, const QString &parentClass, const QString &parent );
+ QString createObjectImpl( const QDomElement &e, const QString& parentClass, const QString& parent, const QString& layout = QString::null );
+ QString createLayoutImpl( const QDomElement &e, const QString& parentClass, const QString& parent, const QString& layout = QString::null );
+ QString createObjectInstance( const QString& objClass, const QString& parent, const QString& objName );
+ QString createSpacerImpl( const QDomElement &e, const QString& parentClass, const QString& parent, const QString& layout = QString::null );
+ void createExclusiveProperty( const QDomElement & e, const QString& exclusiveProp );
+ QString createListBoxItemImpl( const QDomElement &e, const QString &parent, QString *value = 0 );
+ QString createIconViewItemImpl( const QDomElement &e, const QString &parent );
+ QString createListViewColumnImpl( const QDomElement &e, const QString &parent, QString *value = 0 );
+ QString createTableRowColumnImpl( const QDomElement &e, const QString &parent, QString *value = 0 );
+ QString createListViewItemImpl( const QDomElement &e, const QString &parent,
+ const QString &parentItem );
+ void createColorGroupImpl( const QString& cg, const QDomElement& e );
+ QColorGroup loadColorGroup( const QDomElement &e );
+
+ QDomElement getObjectProperty( const QDomElement& e, const QString& name );
+ QString getPixmapLoaderFunction( const QDomElement& e );
+ QString getFormClassName( const QDomElement& e );
+ QString getClassName( const QDomElement& e );
+ QString getObjectName( const QDomElement& e );
+ QString getLayoutName( const QDomElement& e );
+ QString getInclude( const QString& className );
+
+ QString setObjectProperty( const QString& objClass, const QString& obj, const QString &prop, const QDomElement &e, bool stdset );
+
+ QString registerObject( const QString& name );
+ QString registeredName( const QString& name );
+ bool isObjectRegistered( const QString& name );
+ QStringList unique( const QStringList& );
+
+ QString trcall( const QString& sourceText, const QString& comment = "" );
+
+ static void embed( QTextStream& out, const char* project, const QStringList& images );
+
+ friend void getDBConnections(Uic& uic, QString& s);
+ static bool hasKDEwidget;
+
+private:
+ void registerLayouts ( const QDomElement& e );
+
+ QTextStream& out;
+ QTextOStream trout;
+ QString languageChangeBody;
+ QStringList objectNames;
+ QMap<QString,QString> objectMapper;
+ QStringList tags;
+ QStringList layouts;
+ QString formName;
+ QString lastItem;
+ QString trmacro;
+
+ bool nofwd;
+ static RubyIndent indent;
+
+ struct Buddy
+ {
+ Buddy( const QString& k, const QString& b )
+ : key( k ), buddy( b ) {}
+ Buddy(){} // for valuelist
+ QString key;
+ QString buddy;
+ bool operator==( const Buddy& other ) const
+ { return (key == other.key); }
+ };
+ struct CustomInclude
+ {
+ QString header;
+ QString location;
+ };
+ QValueList<Buddy> buddies;
+
+ QStringList layoutObjects;
+ bool isLayout( const QString& name ) const;
+
+ uint item_used : 1;
+ uint cg_used : 1;
+ uint pal_used : 1;
+ uint stdsetdef : 1;
+ uint externPixmaps : 1;
+
+ QString uiFileVersion;
+ QString nameOfClass;
+ QString pixmapLoaderFunction;
+
+ void registerDatabases( const QDomElement& e );
+ bool isWidgetInTable( const QDomElement& e, const QString& connection, const QString& table );
+ bool isFrameworkCodeGenerated( const QDomElement& e );
+ QString getDatabaseInfo( const QDomElement& e, const QString& tag );
+ void createFormImpl( const QDomElement& e, const QString& form, const QString& connection, const QString& table );
+ QStringList dbConnections;
+ QMap< QString, QStringList > dbCursors;
+ QMap< QString, QStringList > dbForms;
+
+ static bool isMainWindow;
+ static QString mkBool( bool b );
+ static QString mkBool( const QString& s );
+ bool toBool( const QString& s );
+ static QString fixString( const QString &str );
+ static bool onlyAscii;
+ static QString mkStdSet( const QString& prop );
+ static QString getComment( const QDomNode& n );
+ int defSpacing, defMargin;
+ QString fileName;
+ bool writeSlotImpl;
+
+ bool isEmptyFunction( const QString& fname );
+ QMap<QString, QString> functionImpls;
+
+ void rubySlot(QStringList::Iterator &it);
+};
+
+#endif
diff --git a/qtruby/rubylib/designer/rbuic/widgetdatabase.cpp b/qtruby/rubylib/designer/rbuic/widgetdatabase.cpp
new file mode 100644
index 00000000..c79815b1
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/widgetdatabase.cpp
@@ -0,0 +1,833 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#if !defined(UIC)
+#include "../designer/pixmapchooser.h"
+#endif
+#include "widgetinterface.h"
+#include "widgetdatabase.h"
+
+#include <qapplication.h>
+#define NO_STATIC_COLORS
+#include <globaldefs.h>
+#include <qstrlist.h>
+#include <qdict.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qcleanuphandler.h>
+
+#include <qfeatures.h>
+
+#include <stdlib.h>
+
+const int dbsize = 300;
+const int dbcustom = 200;
+const int dbdictsize = 211;
+static WidgetDatabaseRecord* db[ dbsize ];
+static QDict<int> *className2Id = 0;
+static int dbcount = 0;
+static int dbcustomcount = 200;
+static QStrList *wGroups;
+static QStrList *invisibleGroups;
+static bool whatsThisLoaded = false;
+static QPluginManager<WidgetInterface> *widgetPluginManager = 0;
+static bool plugins_set_up = false;
+static bool was_in_setup = false;
+
+QCleanupHandler<QPluginManager<WidgetInterface> > cleanup_manager;
+
+WidgetDatabaseRecord::WidgetDatabaseRecord()
+{
+ isForm = false;
+ isContainer = false;
+ icon = 0;
+ nameCounter = 0;
+}
+
+WidgetDatabaseRecord::~WidgetDatabaseRecord()
+{
+ delete icon;
+}
+
+
+/*!
+ \class WidgetDatabase widgetdatabase.h
+ \brief The WidgetDatabase class holds information about widgets
+
+ The WidgetDatabase holds information about widgets like toolTip(),
+ iconSet(), ... It works Id-based, so all access functions take the
+ widget id as parameter. To get the id for a widget (classname), use
+ idFromClassName().
+
+ All access functions are static. Having multiple widgetdatabases in
+ one application doesn't make sense anyway and so you don't need more
+ than an instance of the widgetdatabase.
+
+ For creating widgets, layouts, etc. see WidgetFactory.
+*/
+
+/*!
+ Creates widget database. Does nothing.
+*/
+
+WidgetDatabase::WidgetDatabase()
+{
+}
+
+/*! Sets up the widget database. If the static widgetdatabase already
+ exists, the functions returns immediately.
+*/
+
+void WidgetDatabase::setupDataBase( int id )
+{
+ was_in_setup = true;
+#ifndef UIC
+ Q_UNUSED( id )
+ if ( dbcount )
+ return;
+#else
+ if ( dbcount && id != -2 )
+ return;
+ if ( dbcount && !plugins_set_up ) {
+ setupPlugins();
+ return;
+ }
+ if ( dbcount && plugins_set_up)
+ return;
+#endif
+
+ wGroups = new QStrList;
+ invisibleGroups = new QStrList;
+ invisibleGroups->append( "Forms" );
+ invisibleGroups->append( "Temp" );
+ className2Id = new QDict<int>( dbdictsize );
+ className2Id->setAutoDelete( true );
+
+ WidgetDatabaseRecord *r = 0;
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "pushbutton.xpm";
+ r->name = "QPushButton";
+ r->group = widgetGroup( "Buttons" );
+ r->toolTip = "Push Button";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "toolbutton.xpm";
+ r->name = "QToolButton";
+ r->group = widgetGroup( "Buttons" );
+ r->toolTip = "Tool Button";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "radiobutton.xpm";
+ r->name = "QRadioButton";
+ r->group = widgetGroup( "Buttons" );
+ r->toolTip = "Radio Button";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "checkbox.xpm";
+ r->name = "QCheckBox";
+ r->group = widgetGroup( "Buttons" );
+ r->toolTip = "Check Box";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "groupbox.xpm";
+ r->name = "QGroupBox";
+ r->group = widgetGroup( "Containers" );
+ r->toolTip = "Group Box";
+ r->isContainer = true;
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "buttongroup.xpm";
+ r->name = "QButtonGroup";
+ r->group = widgetGroup( "Containers" );
+ r->toolTip = "Button Group";
+ r->isContainer = true;
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "frame.xpm";
+ r->name = "QFrame";
+ r->group = widgetGroup( "Containers" );
+ r->toolTip = "Frame";
+ r->isContainer = true;
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "tabwidget.xpm";
+ r->name = "QTabWidget";
+ r->group = widgetGroup( "Containers" );
+ r->toolTip = "Tabwidget";
+ r->isContainer = true;
+
+ append( r );
+
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "listbox.xpm";
+ r->name = "QListBox";
+ r->group = widgetGroup( "Views" );
+ r->toolTip = "List Box";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "listview.xpm";
+ r->name = "QListView";
+ r->group = widgetGroup( "Views" );
+ r->toolTip = "List View";
+
+ append( r );
+
+#if !defined(QT_NO_ICONVIEW) || defined(UIC)
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "iconview.xpm";
+ r->name = "QIconView";
+ r->group = widgetGroup( "Views" );
+ r->toolTip = "Icon View";
+
+ append( r );
+#endif
+
+#if !defined(QT_NO_TABLE)
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "table.xpm";
+ r->name = "QTable";
+ r->group = widgetGroup( "Views" );
+ r->toolTip = "Table";
+
+ append( r );
+#endif
+
+#if !defined(QT_NO_SQL)
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "datatable.xpm";
+ r->includeFile = "qdatatable.h";
+ r->name = "QDataTable";
+ r->group = widgetGroup( "Database" );
+ r->toolTip = "Data Table";
+
+ append( r );
+#endif
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "lineedit.xpm";
+ r->name = "QLineEdit";
+ r->group = widgetGroup( "Input" );
+ r->toolTip = "Line Edit";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "spinbox.xpm";
+ r->name = "QSpinBox";
+ r->group = widgetGroup( "Input" );
+ r->toolTip = "Spin Box";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "dateedit.xpm";
+ r->name = "QDateEdit";
+ r->group = widgetGroup( "Input" );
+ r->toolTip = "Date Edit";
+ r->includeFile = "qdatetimeedit.h";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "timeedit.xpm";
+ r->name = "QTimeEdit";
+ r->group = widgetGroup( "Input" );
+ r->toolTip = "Time Edit";
+ r->includeFile = "qdatetimeedit.h";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "datetimeedit.xpm";
+ r->name = "QDateTimeEdit";
+ r->group = widgetGroup( "Input" );
+ r->toolTip = "Date-Time Edit";
+ r->includeFile = "qdatetimeedit.h";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "multilineedit.xpm";
+ r->name = "QMultiLineEdit";
+ r->group = widgetGroup( "Temp" );
+ r->toolTip = "Multi Line Edit";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "richtextedit.xpm";
+ r->name = "QTextEdit";
+ r->group = widgetGroup( "Input" );
+ r->toolTip = "Richtext Editor";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "combobox.xpm";
+ r->name = "QComboBox";
+ r->group = widgetGroup( "Input" );
+ r->toolTip = "Combo Box";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "slider.xpm";
+ r->name = "QSlider";
+ r->group = widgetGroup( "Input" );
+ r->toolTip = "Slider";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "scrollbar.xpm";
+ r->name = "QScrollBar";
+ r->group = widgetGroup( "Input" );
+ r->toolTip = "Scrollbar";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "dial.xpm";
+ r->name = "QDial";
+ r->group = widgetGroup( "Input" );
+ r->toolTip = "Dial";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "label.xpm";
+ r->name = "QLabel";
+ r->group = widgetGroup( "Temp" );
+ r->toolTip = "Label";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "label.xpm";
+ r->name = "TextLabel";
+ r->group = widgetGroup( "Display" );
+ r->toolTip = "Text Label";
+ r->whatsThis = "The Text Label provides a widget to display static text.";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "pixlabel.xpm";
+ r->name = "PixmapLabel";
+ r->group = widgetGroup( "Display" );
+ r->toolTip = "Pixmap Label";
+ r->whatsThis = "The Pixmap Label provides a widget to display pixmaps.";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "lcdnumber.xpm";
+ r->name = "QLCDNumber";
+ r->group = widgetGroup( "Display" );
+ r->toolTip = "LCD Number";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "line.xpm";
+ r->name = "Line";
+ r->group = widgetGroup( "Display" );
+ r->toolTip = "Line";
+ r->includeFile = "qframe.h";
+ r->whatsThis = "The Line widget provides horizontal and vertical lines.";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "progress.xpm";
+ r->name = "QProgressBar";
+ r->group = widgetGroup( "Display" );
+ r->toolTip = "Progress Bar";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "textview.xpm";
+ r->name = "QTextView";
+ r->group = widgetGroup( "Temp" );
+ r->toolTip = "Text View";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "textbrowser.xpm";
+ r->name = "QTextBrowser";
+ r->group = widgetGroup( "Display" );
+ r->toolTip = "Text Browser";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "spacer.xpm";
+ r->name = "Spacer";
+ r->group = widgetGroup( "Temp" );
+ r->toolTip = "Spacer";
+ r->whatsThis = "The Spacer provides horizontal and vertical spacing to be able to manipulate the behaviour of layouts.";
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->name = "QWidget";
+ r->isForm = true;
+ r->group = widgetGroup( "Forms" );
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->name = "QDialog";
+ r->group = widgetGroup( "Forms" );
+ r->isForm = true;
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->name = "QWizard";
+ r->group = widgetGroup( "Forms" );
+ r->isContainer = true;
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->name = "QDesignerWizard";
+ r->group = widgetGroup( "Forms" );
+ r->isContainer = true;
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->name = "QLayoutWidget";
+ r->group = widgetGroup( "Temp" );
+ r->includeFile = "";
+ r->isContainer = true;
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->name = "QSplitter";
+ r->group = widgetGroup( "Temp" );
+ r->includeFile = "qsplitter.h";
+ r->isContainer = true;
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "tabwidget.xpm";
+ r->name = "QDesignerTabWidget";
+ r->group = widgetGroup( "Temp" );
+ r->isContainer = true;
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "tabwidget.xpm";
+ r->name = "QDesignerWidget";
+ r->group = widgetGroup( "Temp" );
+ r->isContainer = true;
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "tabwidget.xpm";
+ r->name = "QDesignerDialog";
+ r->group = widgetGroup( "Temp" );
+ r->isContainer = true;
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "";
+ r->name = "QMainWindow";
+ r->includeFile = "qmainwindow.h";
+ r->group = widgetGroup( "Temp" );
+ r->isContainer = true;
+
+ append( r );
+
+#ifndef QT_NO_SQL
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "";
+ r->name = "QDataBrowser";
+ r->includeFile = "qdatabrowser.h";
+ r->group = widgetGroup( "Database" );
+ r->toolTip = "Data Browser";
+ r->iconSet = "databrowser.xpm";
+ r->isContainer = true;
+
+ append( r );
+
+ r = new WidgetDatabaseRecord;
+ r->iconSet = "";
+ r->name = "QDataView";
+ r->includeFile = "qdataview.h";
+ r->group = widgetGroup( "Database" );
+ r->toolTip = "Data View";
+ r->iconSet = "dataview.xpm";
+ r->isContainer = true;
+
+ append( r );
+#endif
+
+#ifndef UIC
+ setupPlugins();
+#endif
+}
+
+void WidgetDatabase::setupPlugins()
+{
+ if ( plugins_set_up )
+ return;
+ plugins_set_up = true;
+ QStringList widgets = widgetManager()->featureList();
+ for ( QStringList::Iterator it = widgets.begin(); it != widgets.end(); ++it ) {
+ if ( hasWidget( *it ) )
+ continue;
+ WidgetDatabaseRecord *r = new WidgetDatabaseRecord;
+ WidgetInterface *iface = 0;
+ widgetManager()->queryInterface( *it, &iface );
+ if ( !iface )
+ continue;
+
+#ifndef UIC
+ QIconSet icon = iface->iconSet( *it );
+ if ( !icon.pixmap().isNull() )
+ r->icon = new QIconSet( icon );
+#endif
+ QString grp = iface->group( *it );
+ if ( grp.isEmpty() )
+ grp = "3rd party widgets";
+ r->group = widgetGroup( grp );
+ r->toolTip = iface->toolTip( *it );
+ r->whatsThis = iface->whatsThis( *it );
+ r->includeFile = iface->includeFile( *it );
+ r->isContainer = iface->isContainer( *it );
+ r->name = *it;
+ append( r );
+ iface->release();
+ }
+}
+
+/*!
+ Returns the number of elements in the widget database.
+*/
+
+int WidgetDatabase::count()
+{
+ setupDataBase( -1 );
+ return dbcount;
+}
+
+/*!
+ Returns the id at which the ids of custom widgets start.
+*/
+
+int WidgetDatabase::startCustom()
+{
+ setupDataBase( -1 );
+ return dbcustom;
+}
+
+/*!
+ Returns the iconset which represents the class registered as \a id.
+*/
+
+QIconSet WidgetDatabase::iconSet( int id )
+{
+ setupDataBase( id );
+ WidgetDatabaseRecord *r = at( id );
+ if ( !r )
+ return QIconSet();
+#if !defined(UIC) && !defined(RESOURCE)
+ if ( !r->icon )
+ r->icon = new QIconSet( PixmapChooser::loadPixmap( r->iconSet, PixmapChooser::Small ),
+ PixmapChooser::loadPixmap( r->iconSet, PixmapChooser::Large ) );
+ return *r->icon;
+#else
+ return QIconSet();
+#endif
+}
+
+/*!
+ Returns the classname of the widget which is registered as \a id.
+*/
+
+QString WidgetDatabase::className( int id )
+{
+ setupDataBase( id );
+ WidgetDatabaseRecord *r = at( id );
+ if ( !r )
+ return QString::null;
+ return r->name;
+}
+
+/*!
+ Returns the group to which the widget registered as \a id belongs.
+*/
+
+QString WidgetDatabase::group( int id )
+{
+ setupDataBase( id );
+ WidgetDatabaseRecord *r = at( id );
+ if ( !r )
+ return QString::null;
+ return r->group;
+}
+
+/*! Returns the tooltip text of the widget which is registered as \a
+ id.
+*/
+
+QString WidgetDatabase::toolTip( int id )
+{
+ setupDataBase( id );
+ WidgetDatabaseRecord *r = at( id );
+ if ( !r )
+ return QString::null;
+ return r->toolTip;
+}
+
+/*! Returns the what's this? test of the widget which is registered
+ as \a id.
+*/
+
+QString WidgetDatabase::whatsThis( int id )
+{
+ setupDataBase( id );
+ WidgetDatabaseRecord *r = at( id );
+ if ( !r )
+ return QString::null;
+ return r->whatsThis;
+}
+
+/*!
+ Returns the include file if the widget which is registered as \a id.
+*/
+
+QString WidgetDatabase::includeFile( int id )
+{
+ setupDataBase( id );
+ WidgetDatabaseRecord *r = at( id );
+ if ( !r )
+ return QString::null;
+ if ( r->includeFile.isNull() )
+ return r->name.lower() + ".h";
+ return r->includeFile;
+}
+
+/*! Returns wheather the widget registered as \a id is a form
+*/
+bool WidgetDatabase::isForm( int id )
+{
+ setupDataBase( id );
+ WidgetDatabaseRecord *r = at( id );
+ if ( !r )
+ return false;
+ return r->isForm;
+}
+
+/*! Returns wheather the widget registered as \a id is a container
+ (can have children) or not.
+*/
+
+bool WidgetDatabase::isContainer( int id )
+{
+ setupDataBase( id );
+ WidgetDatabaseRecord *r = at( id );
+ if ( !r )
+ return false;
+ return r->isContainer || r->isForm;
+}
+
+QString WidgetDatabase::createWidgetName( int id )
+{
+ setupDataBase( id );
+ QString n = className( id );
+ if ( n == "QLayoutWidget" )
+ n = "Layout";
+ if ( n[ 0 ] == 'Q' )
+ n = n.mid( 1 );
+ WidgetDatabaseRecord *r = at( id );
+ if ( !r )
+ return n;
+ n += QString::number( ++r->nameCounter );
+ return n;
+}
+
+/*! Returns the id for \a name or -1 if \a name is unknown.
+ */
+int WidgetDatabase::idFromClassName( const QString &name )
+{
+ setupDataBase( -1 );
+ if ( name.isEmpty() )
+ return 0;
+ int *i = className2Id->find( name );
+ if ( i )
+ return *i;
+ if ( name == "FormWindow" )
+ return idFromClassName( "QLayoutWidget" );
+#ifdef UIC
+#ifndef NO_UI_PLUGINS
+ setupDataBase( -2 );
+ i = className2Id->find( name );
+ if ( i )
+ return *i;
+#endif
+#endif
+ return -1;
+}
+
+bool WidgetDatabase::hasWidget( const QString &name )
+{
+ return className2Id->find( name ) != 0;
+}
+
+WidgetDatabaseRecord *WidgetDatabase::at( int index )
+{
+ if ( index < 0 )
+ return 0;
+ if ( index >= dbcustom && index < dbcustomcount )
+ return db[ index ];
+ if ( index < dbcount )
+ return db[ index ];
+ return 0;
+}
+
+void WidgetDatabase::insert( int index, WidgetDatabaseRecord *r )
+{
+ if ( index < 0 || index >= dbsize )
+ return;
+ db[ index ] = r;
+ className2Id->insert( r->name, new int( index ) );
+ if ( index < dbcustom )
+ dbcount = QMAX( dbcount, index );
+}
+
+void WidgetDatabase::append( WidgetDatabaseRecord *r )
+{
+ if ( !was_in_setup )
+ setupDataBase( -1 );
+ insert( dbcount++, r );
+}
+
+QString WidgetDatabase::widgetGroup( const QString &g )
+{
+ if ( wGroups->find( g ) == -1 )
+ wGroups->append( g );
+ return g;
+}
+
+bool WidgetDatabase::isGroupEmpty( const QString &grp )
+{
+ WidgetDatabaseRecord *r = 0;
+ for ( int i = 0; i < dbcount; ++i ) {
+ if ( !( r = db[ i ] ) )
+ continue;
+ if ( r->group == grp )
+ return false;
+ }
+ return true;
+}
+
+QString WidgetDatabase::widgetGroup( int i )
+{
+ setupDataBase( -1 );
+ if ( i >= 0 && i < (int)wGroups->count() )
+ return wGroups->at( i );
+ return QString::null;
+}
+
+int WidgetDatabase::numWidgetGroups()
+{
+ setupDataBase( -1 );
+ return wGroups->count();
+}
+
+bool WidgetDatabase::isGroupVisible( const QString &g )
+{
+ setupDataBase( -1 );
+ return invisibleGroups->find( g ) == -1;
+}
+
+int WidgetDatabase::addCustomWidget( WidgetDatabaseRecord *r )
+{
+ insert( dbcustomcount++, r );
+ return dbcustomcount - 1;
+}
+
+bool WidgetDatabase::isCustomWidget( int id )
+{
+ if ( id >= dbcustom && id < dbcustomcount )
+ return true;
+ return false;
+}
+
+bool WidgetDatabase::isWhatsThisLoaded()
+{
+ return whatsThisLoaded;
+}
+
+void WidgetDatabase::loadWhatsThis( const QString &docPath )
+{
+ QString whatsthisFile = docPath + "/whatsthis";
+ QFile f( whatsthisFile );
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+ QTextStream ts( &f );
+ while ( !ts.atEnd() ) {
+ QString s = ts.readLine();
+ QStringList l = QStringList::split( " | ", s );
+ int id = idFromClassName( l[ 1 ] );
+ WidgetDatabaseRecord *r = at( id );
+ if ( r )
+ r->whatsThis = l[ 0 ];
+ }
+ whatsThisLoaded = true;
+}
+
+QPluginManager<WidgetInterface> *widgetManager()
+{
+ if ( !widgetPluginManager ) {
+ widgetPluginManager = new QPluginManager<WidgetInterface>( IID_Widget, QApplication::libraryPaths(), "/designer" );
+ cleanup_manager.add( &widgetPluginManager );
+ }
+ return widgetPluginManager;
+}
diff --git a/qtruby/rubylib/designer/rbuic/widgetdatabase.h b/qtruby/rubylib/designer/rbuic/widgetdatabase.h
new file mode 100644
index 00000000..efe585ab
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/widgetdatabase.h
@@ -0,0 +1,85 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef WIDGETDATABASE_H
+#define WIDGETDATABASE_H
+
+#include <qiconset.h>
+#include <qstring.h>
+#include "widgetinterface.h" // up here for GCC 2.7.* compatibility
+#include <private/qpluginmanager_p.h>
+
+
+extern QPluginManager<WidgetInterface> *widgetManager();
+
+struct WidgetDatabaseRecord
+{
+ WidgetDatabaseRecord();
+ ~WidgetDatabaseRecord();
+ QString iconSet, name, group, toolTip, whatsThis, includeFile;
+ uint isContainer : 1;
+ uint isForm : 1;
+ QIconSet *icon;
+ int nameCounter;
+};
+
+class WidgetDatabase : public Qt
+{
+public:
+ WidgetDatabase();
+ static void setupDataBase( int id );
+ static void setupPlugins();
+
+ static int count();
+ static int startCustom();
+
+ static QIconSet iconSet( int id );
+ static QString className( int id );
+ static QString group( int id );
+ static QString toolTip( int id );
+ static QString whatsThis( int id );
+ static QString includeFile( int id );
+ static bool isForm( int id );
+ static bool isContainer( int id );
+
+ static int idFromClassName( const QString &name );
+ static QString createWidgetName( int id );
+
+ static WidgetDatabaseRecord *at( int index );
+ static void insert( int index, WidgetDatabaseRecord *r );
+ static void append( WidgetDatabaseRecord *r );
+
+ static QString widgetGroup( const QString &g );
+ static QString widgetGroup( int i );
+ static int numWidgetGroups();
+ static bool isGroupVisible( const QString &g );
+ static bool isGroupEmpty( const QString &grp );
+
+ static int addCustomWidget( WidgetDatabaseRecord *r );
+ static bool isCustomWidget( int id );
+
+ static bool isWhatsThisLoaded();
+ static void loadWhatsThis( const QString &docPath );
+
+ static bool hasWidget( const QString &name );
+
+};
+
+#endif
diff --git a/qtruby/rubylib/designer/rbuic/widgetinterface.h b/qtruby/rubylib/designer/rbuic/widgetinterface.h
new file mode 100644
index 00000000..bf6bcd55
--- /dev/null
+++ b/qtruby/rubylib/designer/rbuic/widgetinterface.h
@@ -0,0 +1,29 @@
+ /**********************************************************************
+** Copyright (C) 2000-2001 Trolltech AS. All rights reserved.
+**
+** This file is part of Qt Designer.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef WIDGETINTERFACE_H
+#define WIDGETINTERFACE_H
+
+#include <private/qwidgetinterface_p.h>
+
+#define WidgetInterface QWidgetFactoryInterface
+#define IID_Widget IID_QWidgetFactory
+
+#endif
diff --git a/qtruby/rubylib/designer/uilib/Makefile.am b/qtruby/rubylib/designer/uilib/Makefile.am
new file mode 100644
index 00000000..e7f21bea
--- /dev/null
+++ b/qtruby/rubylib/designer/uilib/Makefile.am
@@ -0,0 +1,7 @@
+INCLUDES = -I$(top_srcdir)/smoke -I$(top_srcdir)/qtruby/rubylib/qtruby $(all_includes) -I$(RUBY_ARCHDIR)
+
+rubylibdir = $(RUBY_SITEARCHDIR)
+rubylib_LTLIBRARIES = qui.la
+qui_la_SOURCES = qui.cpp
+qui_la_LDFLAGS = -module -export-dynamic $(all_libraries) -version-info 0:0:0
+qui_la_LIBADD = -lqui \ No newline at end of file
diff --git a/qtruby/rubylib/designer/uilib/extconf.rb b/qtruby/rubylib/designer/uilib/extconf.rb
new file mode 100644
index 00000000..fa742b9a
--- /dev/null
+++ b/qtruby/rubylib/designer/uilib/extconf.rb
@@ -0,0 +1,6 @@
+require 'mkmf'
+dir_config('smoke')
+dir_config('qt')
+$CPPFLAGS += " -I../../../../smoke -I../../qtruby "
+$LOCAL_LIBS += '-bundle_loader ../../qtruby/qtruby.bundle -lsmokeqt -lqui -lqt-mt -lstdc++'
+create_makefile("qui")
diff --git a/qtruby/rubylib/designer/uilib/qui.cpp b/qtruby/rubylib/designer/uilib/qui.cpp
new file mode 100644
index 00000000..9aa7513f
--- /dev/null
+++ b/qtruby/rubylib/designer/uilib/qui.cpp
@@ -0,0 +1,175 @@
+/***************************************************************************
+ qui.cpp - A ruby wrapper for the QWidgetFactory class
+ -------------------
+ begin : Wed Mar 14 2004
+ copyright : (C) 2004 by Richard Dale
+ email : Richard_Dale@tipitina.demon.co.uk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qwidgetfactory.h>
+#include <qwidget.h>
+
+#include "smoke.h"
+
+#undef DEBUG
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#ifndef __USE_XOPEN
+#define __USE_XOPEN
+#endif
+#include <ruby.h>
+
+#include "qtruby.h"
+#include "smokeruby.h"
+
+extern Smoke *qt_Smoke;
+extern bool isDerivedFrom(Smoke *smoke, Smoke::Index classId, Smoke::Index baseId);
+
+extern "C" {
+extern VALUE set_obj_info(const char * className, smokeruby_object * o);
+
+static VALUE qui_module;
+static VALUE qwidget_factory_class;
+
+static VALUE
+create(int argc, VALUE * argv, VALUE /*klass*/)
+{
+ QWidget * topLevelWidget = 0;
+ VALUE result = Qnil;
+
+ if (argc == 0 || argc > 4) {
+ rb_raise(rb_eArgError, "wrong number of arguments (%d)\n", argc);
+ }
+
+ QObject * connector = 0;
+ if (argc >= 2) {
+ if (TYPE(argv[1]) == T_DATA) {
+ smokeruby_object *o = value_obj_info(argv[1]);
+ if (o != 0) {
+ connector = (QObject *) o->ptr;
+ }
+ } else {
+ rb_raise(rb_eArgError, "invalid argument type\n");
+ }
+ }
+
+ QWidget * parent = 0;
+ if (argc >= 3) {
+ if (TYPE(argv[2]) == T_DATA) {
+ smokeruby_object *o = value_obj_info(argv[2]);
+ if (o != 0) {
+ parent = (QWidget *) o->ptr;
+ }
+ } else {
+ rb_raise(rb_eArgError, "invalid argument type\n");
+ }
+ }
+
+ const char * name = 0;
+ if (argc >= 4) {
+ if (TYPE(argv[3]) == T_STRING) {
+ name = StringValuePtr(argv[3]);
+ } else {
+ rb_raise(rb_eArgError, "invalid argument type\n");
+ }
+ }
+
+ if (TYPE(argv[0]) == T_STRING) {
+ topLevelWidget = QWidgetFactory::create(QString(StringValuePtr(argv[0])), connector, parent, name);
+ } else if (TYPE(argv[0]) == T_DATA) {
+ QIODevice * dev = 0;
+ smokeruby_object *o = value_obj_info(argv[0]);
+
+ if (o != 0 && o->ptr != 0 && o->classId == qt_Smoke->idClass("QIODevice")) {
+ dev = (QIODevice *) o->ptr;
+ } else {
+ rb_raise(rb_eArgError, "invalid argument type\n");
+ }
+
+ topLevelWidget = QWidgetFactory::create(dev, connector, parent, name);
+ } else {
+ rb_raise(rb_eArgError, "invalid argument type\n");
+ }
+
+ if (topLevelWidget != 0) {
+ smokeruby_object * o = (smokeruby_object *) malloc(sizeof(smokeruby_object));
+ o->smoke = qt_Smoke;
+ o->classId = qt_Smoke->idClass(topLevelWidget->className());
+ o->ptr = topLevelWidget;
+ o->allocated = false;
+
+ const char * className = qt_Smoke->binding->className(o->classId);
+ result = set_obj_info(className, o);
+ }
+
+ return result;
+}
+
+static VALUE
+load_images(VALUE klass, VALUE dir)
+{
+ QWidgetFactory::loadImages(QString(StringValuePtr(dir)));
+ return klass;
+}
+
+static VALUE
+widgets(VALUE /*self*/)
+{
+ VALUE result = rb_ary_new();
+ QStringList widgetList = QWidgetFactory::widgets();
+
+ for (QStringList::Iterator it = widgetList.begin(); it != widgetList.end(); ++it) {
+ QString widgetName = *it;
+ if (widgetName.startsWith("Q")) {
+ widgetName.replace(0, 1, QString("Qt::"));
+ } else if (widgetName.startsWith("K")) {
+ widgetName.replace(0, 1, QString("KDE::"));
+ }
+ rb_ary_push(result, rb_str_new2(widgetName.latin1()));
+ }
+
+ return result;
+}
+
+static VALUE
+supports_widget(VALUE /*self*/, VALUE widget)
+{
+ QString widgetName(StringValuePtr(widget));
+
+ if (widgetName.startsWith("Qt::")) {
+ widgetName.replace(0, 4, QString("Q"));
+ } else if (widgetName.startsWith("KDE::")) {
+ widgetName.replace(0, 5, QString("K"));
+ }
+
+ return QWidgetFactory::supportsWidget(widgetName) ? Qtrue : Qfalse;
+}
+
+void
+Init_qui()
+{
+ qui_module = rb_define_module("QUI");
+ qwidget_factory_class = rb_define_class_under(qui_module, "WidgetFactory", rb_cObject);
+
+ rb_define_singleton_method(qwidget_factory_class, "create", (VALUE (*) (...)) create, -1);
+ rb_define_singleton_method(qwidget_factory_class, "loadImages", (VALUE (*) (...)) load_images, 1);
+ rb_define_singleton_method(qwidget_factory_class, "load_images", (VALUE (*) (...)) load_images, 1);
+ rb_define_singleton_method(qwidget_factory_class, "widgets", (VALUE (*) (...)) widgets, 0);
+ rb_define_singleton_method(qwidget_factory_class, "supportsWidget", (VALUE (*) (...)) supports_widget, 1);
+ rb_define_singleton_method(qwidget_factory_class, "supports_widget", (VALUE (*) (...)) supports_widget, 1);
+}
+
+};
diff --git a/qtruby/rubylib/designer/uilib/test/test.rb b/qtruby/rubylib/designer/uilib/test/test.rb
new file mode 100644
index 00000000..628f1270
--- /dev/null
+++ b/qtruby/rubylib/designer/uilib/test/test.rb
@@ -0,0 +1,20 @@
+require 'Qt'
+require 'qui'
+
+a = Qt::Application.new(ARGV)
+if ARGV.length == 0
+ puts "Usage: test.rb <image dir> <ui file>"
+ exit
+end
+
+if ARGV.length == 2
+ QUI::WidgetFactory.loadImages( ARGV[ 0 ] )
+ w = QUI::WidgetFactory.create( ARGV[ 1 ] )
+ if w.nil?
+ puts "Failed to create top level widget"
+ exit
+ end
+ w.show()
+ a.connect( a, SIGNAL('lastWindowClosed()'), a, SLOT('quit()') )
+ a.exec()
+end
diff --git a/qtruby/rubylib/examples/base/kicons.rb b/qtruby/rubylib/examples/base/kicons.rb
new file mode 100644
index 00000000..0d0a2c01
--- /dev/null
+++ b/qtruby/rubylib/examples/base/kicons.rb
@@ -0,0 +1,54 @@
+class KIconCollection
+ IconInfo = Struct.new(:collection, :id, :filetype)
+ def initialize(icon_collections)
+ @icon_info = {}
+ icon_collections.each_pair {
+ |collection_name, collection|
+ collection.each_pair {
+ |key, value|
+ info = IconInfo.new(collection_name, value, "png")
+ @icon_info[key] = info
+ }
+ }
+ end
+ def dims
+ "32x32"
+ end
+ def kdedir
+ ENV["KDEDIR"]
+ end
+ def get_icon_path(icon_type)
+ info = @icon_info[icon_type]
+ "#{kdedir}/share/icons/default.kde/#{dims}/#{info.collection}/#{info.id}.#{info.filetype}"
+ end
+ def get_icon_set(icon_type)
+ path = get_icon_path(icon_type)
+ pixmap = Qt::Pixmap.new(path)
+ icon_set = Qt::IconSet.new
+ icon_set.setPixmap(pixmap, Qt::IconSet.Small)
+ icon_set
+ end
+ def make_qt_action(parent, text_with_accel, icon_type)
+ act = Qt::Action.new(parent)
+ act.setIconSet(get_icon_set(icon_type))
+ act.setMenuText(text_with_accel)
+ act
+ end
+end
+
+module Icons
+ FILE_NEW, FILE_OPEN, FILE_CLOSE, FILE_SAVE, FILE_SAVE_AS, EXIT = 1,2,3,4,5,6
+end
+
+icon_collections = {
+ "actions" => {
+ Icons::FILE_NEW => "filenew",
+ Icons::FILE_OPEN => "fileopen",
+ Icons::FILE_CLOSE => "fileclose",
+ Icons::FILE_SAVE => "filesave",
+ Icons::FILE_SAVE_AS => "filesaveas",
+ Icons::EXIT => "exit"
+ }
+}
+$kIcons = KIconCollection.new(icon_collections)
+print "Using KDEDIR == ", $kIcons.kdedir, "\n"
diff --git a/qtruby/rubylib/examples/base/rui.rb b/qtruby/rubylib/examples/base/rui.rb
new file mode 100644
index 00000000..ad14bc11
--- /dev/null
+++ b/qtruby/rubylib/examples/base/rui.rb
@@ -0,0 +1,21 @@
+require '../base/kicons.rb'
+
+RAction = Struct.new(:text_with_accel, :icon_type, :rec, :slot, :included_in, :action)
+RSeperator = Struct.new(:included_in, :id)
+
+def build_actions(actions)
+ actions.each { |a|
+ if a.is_a? RSeperator
+ a.included_in.each {
+ |to| a.id = to.insertSeparator()
+ }
+ else
+ qt_action = $kIcons.make_qt_action(self, a.text_with_accel, a.icon_type)
+ connect(qt_action, SIGNAL('activated()'), a.rec, a.slot)
+ a.included_in.each {
+ |to| qt_action.addTo(to)
+ }
+ a.action = qt_action
+ end
+ }
+end
diff --git a/qtruby/rubylib/examples/canvastest/canvastest.rb b/qtruby/rubylib/examples/canvastest/canvastest.rb
new file mode 100644
index 00000000..4187d91d
--- /dev/null
+++ b/qtruby/rubylib/examples/canvastest/canvastest.rb
@@ -0,0 +1,75 @@
+#!/usr/bin/env ruby -w
+
+require 'Qt'
+require 'rexml/document'
+
+require '../base/kicons.rb'
+require '../base/rui.rb'
+
+class MyCanvasView < Qt::CanvasView
+ def initialize(canvas, parent)
+ @canvas = canvas
+ super(canvas, parent)
+ end
+ def contentsMousePressEvent(e)
+ super
+ list = canvas.collisions(e.pos)
+ return if list.empty?
+ c = list.first
+ return if c.rtti != Qt::CanvasItem::Rtti_Rectangle
+ c.hide
+ @canvas.update
+ end
+end
+
+class MyWidget < Qt::MainWindow
+ slots 'new()', 'open()', 'save_as()'
+ def make_rect
+ rect = Qt::CanvasRectangle.new(rand(@canvas.width()), rand(@canvas.height()),
+ @canvas.width / 5, @canvas.width / 5, @canvas)
+ z = rand(256)
+ color = Qt::Color.new(z,z,z)
+ rect.setBrush(Qt::Brush.new(color))
+ color = Qt::Color.new(rand(32)*8, rand(32)*8, rand(32)*8)
+ rect.setPen(Qt::Pen.new(color, 6))
+ rect.setZ(z)
+ rect.show
+ @rects << rect
+ end
+ def initialize()
+ super
+
+ fileTools = Qt::ToolBar.new(self, "file operations")
+ fileMenu = Qt::PopupMenu.new(self)
+
+ actions = [
+ RAction.new("&New", Icons::FILE_NEW, self, SLOT('new()'), [fileTools, fileMenu]),
+ RAction.new("&Open...", Icons::FILE_OPEN, self, SLOT('open()'), [fileTools, fileMenu]),
+ @save = RAction.new("Save &As...", Icons::FILE_SAVE_AS, self, SLOT('save_as()'), [fileTools, fileMenu]),
+ RSeperator.new([fileMenu]),
+ RAction.new("E&xit", Icons::EXIT, $qApp, SLOT('quit()'), [fileMenu])
+ ]
+ build_actions(actions)
+
+ menubar = Qt::MenuBar.new(self)
+ menubar.insertItem("&File", fileMenu)
+
+ @canvas = Qt::Canvas.new(640, 480)
+
+ @rects = []
+ 5.times { make_rect }
+
+ @canvas_view = MyCanvasView.new(@canvas, self)
+ self.setCentralWidget(@canvas_view)
+ @canvas.update
+ end
+end
+
+a = Qt::Application.new(ARGV)
+
+w = MyWidget.new
+w.show
+
+a.setMainWidget(w)
+a.exec()
+exit
diff --git a/qtruby/rubylib/examples/killerfilter/killerfilter.rb b/qtruby/rubylib/examples/killerfilter/killerfilter.rb
new file mode 100644
index 00000000..647dc079
--- /dev/null
+++ b/qtruby/rubylib/examples/killerfilter/killerfilter.rb
@@ -0,0 +1,56 @@
+#!/usr/bin/env ruby -w
+
+# This is the EventFilter example from Chapter 16 of 'Programming with Qt'
+
+require 'Qt'
+
+class KillerFilter < Qt::Object
+
+ def eventFilter( object, event )
+ if event.type() == Qt::Event::MouseButtonPress
+ if event.button() == RightButton
+ object.close(false)
+ return true
+ else
+ return false
+ end
+ else
+ return false
+ end
+ end
+
+end
+
+a = Qt::Application.new(ARGV)
+
+toplevel = Qt::Widget.new
+toplevel.resize(230, 130)
+
+killerfilter = KillerFilter.new
+
+pb = Qt::PushButton.new(toplevel)
+pb.setGeometry( 10, 10, 100, 50 )
+pb.text = "pushbutton"
+pb.installEventFilter(killerfilter)
+
+le = Qt::LineEdit.new(toplevel)
+le.setGeometry( 10, 70, 100, 50 )
+le.text = "Line edit"
+le.installEventFilter(killerfilter)
+
+cb = Qt::CheckBox.new(toplevel)
+cb.setGeometry( 120, 10, 100, 50 )
+cb.text = "Check-box"
+cb.installEventFilter(killerfilter)
+
+rb = Qt::RadioButton.new(toplevel)
+rb.setGeometry( 120, 70, 100, 50 )
+rb.text = "Radio button"
+rb.installEventFilter(killerfilter)
+
+a.mainWidget = toplevel
+toplevel.show
+a.exec
+
+
+ \ No newline at end of file
diff --git a/qtruby/rubylib/examples/network/clientserver/client/client.rb b/qtruby/rubylib/examples/network/clientserver/client/client.rb
new file mode 100644
index 00000000..1f16b0ca
--- /dev/null
+++ b/qtruby/rubylib/examples/network/clientserver/client/client.rb
@@ -0,0 +1,88 @@
+require 'Qt'
+
+class Client < Qt::VBox
+
+ def initialize( host, port )
+ super()
+ # GUI layout
+ @infoText = Qt::TextView.new( self )
+ hb = Qt::HBox.new( self )
+ @inputText = Qt::LineEdit.new( hb )
+ send = Qt::PushButton.new( tr("Send") , hb )
+ close = Qt::PushButton.new( tr("Close connection") , self )
+ quit = Qt::PushButton.new( tr("Quit") , self )
+
+ connect( send, SIGNAL('clicked()'), SLOT('sendToServer()') )
+ connect( close, SIGNAL('clicked()'), SLOT('closeConnection()') )
+ connect( quit, SIGNAL('clicked()'), $qApp, SLOT('quit()') )
+
+ # create the socket and connect various of its signals
+ @socket = Qt::Socket.new( self )
+ connect( @socket, SIGNAL('connected()'),
+ SLOT('socketConnected()') )
+ connect( @socket, SIGNAL('connectionClosed()'),
+ SLOT('socketConnectionClosed()') )
+ connect( @socket, SIGNAL('readyRead()'),
+ SLOT('socketReadyRead()') )
+ connect( @socket, SIGNAL('error(int)'),
+ SLOT('socketError(int)') )
+
+ # connect to the server
+ @infoText.append( tr("Trying to connect to the server\n") )
+ @socket.connectToHost( host, port )
+ end
+
+ slots 'closeConnection()', 'sendToServer()',
+ 'socketReadyRead()', 'socketConnected()',
+ 'socketConnectionClosed()', 'socketClosed()',
+ 'socketError(int)'
+
+ def closeConnection()
+ @socket.close()
+ if @socket.state() == Qt::Socket::Closing
+ # We have a delayed close.
+ connect( @socket, SIGNAL('delayedCloseFinished()'),
+ SLOT('socketClosed()') )
+ else
+ # The socket is closed.
+ socketClosed()
+ end
+ end
+
+ def sendToServer()
+ # write to the server
+ os = Qt::TextStream.new(@socket)
+ os << @inputText.text() << "\n"
+ @inputText.setText( "" )
+ os.dispose()
+ end
+
+ def socketReadyRead()
+ # read from the server
+ while @socket.canReadLine() do
+ @infoText.append( @socket.readLine() )
+ end
+ end
+
+ def socketConnected()
+ @infoText.append( tr("Connected to server\n") )
+ end
+
+ def socketConnectionClosed()
+ @infoText.append( tr("Connection closed by the server\n") )
+ end
+
+ def socketClosed()
+ @infoText.append( tr("Connection closed\n") )
+ end
+
+ def socketError( e )
+ @infoText.append( tr("Error number %d occurred\n" % e) )
+ end
+end
+
+app = Qt::Application.new( ARGV )
+client = Client.new( ARGV.length < 1 ? "localhost" : ARGV[0], 4242 )
+app.mainWidget = client
+client.show
+app.exec
diff --git a/qtruby/rubylib/examples/network/clientserver/server/server.rb b/qtruby/rubylib/examples/network/clientserver/server/server.rb
new file mode 100644
index 00000000..d8a937f4
--- /dev/null
+++ b/qtruby/rubylib/examples/network/clientserver/server/server.rb
@@ -0,0 +1,115 @@
+require 'Qt'
+
+=begin
+ The ClientSocket class provides a socket that is connected with a client.
+ For every client that connects to the server, the server creates a new
+ instance of this class.
+=end
+class ClientSocket < Qt::Socket
+ def initialize(sock, parent=nil, name=nil)
+ super( parent, name )
+ @line = 0
+ connect( self, SIGNAL('readyRead()'),
+ SLOT('readClient()') )
+ connect( self, SIGNAL('connectionClosed()'),
+ SLOT('deleteLater()') )
+ setSocket( sock )
+ end
+
+ signals 'logText(const QString&)'
+
+ slots 'readClient()'
+
+ def readClient()
+ ts = Qt::TextStream.new( self )
+ while canReadLine() do
+ str = ts.readLine()
+ emit logText( tr("Read: '%s'\n" % str) )
+
+ ts << @line << ": " << str
+ # 'endl' needs to be called like this in ruby
+ endl(ts)
+ emit logText( tr("Wrote: '%d: %s'\n" % [@line, str]) )
+
+ @line += 1
+ end
+ ts.dispose()
+ end
+end
+
+
+=begin
+ The SimpleServer class handles new connections to the server. For every
+ client that connects, it creates a new ClientSocket -- that instance is now
+ responsible for the communication with that client.
+=end
+class SimpleServer < Qt::ServerSocket
+ def initialize( parent=nil )
+ super( 4242, 1, parent )
+ if !ok()
+ qWarning("Failed to bind to port 4242")
+ exit(1)
+ end
+ end
+
+ def newConnection( socket )
+ s = ClientSocket.new( socket, self )
+ emit newConnect( s )
+ end
+
+ # The type of the argument is 'QSocket*', not
+ # 'ClientSocket*' as only types in the Smoke
+ # library can be used for types in Signals
+ signals 'newConnect(QSocket*)'
+end
+
+
+=begin
+ The ServerInfo class provides a small GUI for the server. It also creates the
+ SimpleServer and as a result the server.
+=end
+class ServerInfo < Qt::VBox
+ def initialize()
+ super
+ @server = SimpleServer.new( self )
+
+ itext = tr(
+ "This is a small server example.\n" +
+ "Connect with the client now."
+ )
+ lb = Qt::Label.new( itext, self )
+ lb.setAlignment( AlignHCenter )
+ @infoText = Qt::TextView.new( self )
+ quit = Qt::PushButton.new( tr("Quit") , self )
+
+ # See the comment above about why the 'ClientSocket*'
+ # type cannot be used
+ connect( @server, SIGNAL('newConnect(QSocket*)'),
+ SLOT('newConnect(QSocket*)') )
+ connect( quit, SIGNAL('clicked()'), $qApp,
+ SLOT('quit()') )
+ end
+
+ slots 'newConnect(QSocket*)', 'connectionClosed()'
+
+ def newConnect( s )
+ @infoText.append( tr("New connection\n") )
+ connect( s, SIGNAL('logText(const QString&)'),
+ @infoText, SLOT('append(const QString&)') )
+ connect( s, SIGNAL('connectionClosed()'),
+ SLOT('connectionClosed()') )
+ end
+
+ def connectionClosed()
+ @infoText.append( tr("Client closed connection\n") )
+ end
+end
+
+
+app = Qt::Application.new( ARGV )
+info = ServerInfo.new
+app.mainWidget = info
+info.show
+app.exec
+
+
diff --git a/qtruby/rubylib/examples/passivepopup/passivepopup.rb b/qtruby/rubylib/examples/passivepopup/passivepopup.rb
new file mode 100644
index 00000000..37f60c1f
--- /dev/null
+++ b/qtruby/rubylib/examples/passivepopup/passivepopup.rb
@@ -0,0 +1,39 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+
+class PassiveWindow < Qt::Frame
+ MARGIN = 20
+
+ def initialize(message)
+ super(nil, "passivedlg",
+ Qt::WStyle_Customize | Qt::WX11BypassWM | Qt::WStyle_StaysOnTop |
+ Qt::WStyle_Tool | Qt::WStyle_NoBorder)
+
+ setFrameStyle(Qt::Frame::Box| Qt::Frame::Plain)
+ setLineWidth(2)
+
+ setMinimumWidth(100)
+ layout=Qt::VBoxLayout.new(self, 6, 11)
+ layout.setAutoAdd(true)
+ Qt::Label.new(message, self)
+
+ quit=Qt::PushButton.new(tr("Close"), self)
+ connect(quit, SIGNAL("clicked()"), SLOT("close()"))
+ end
+
+ def show
+ super
+ move(Qt::Application.desktop().width() - width() - MARGIN,
+ Qt::Application.desktop().height() - height() - MARGIN)
+ end
+end
+
+if (Process.fork != nil)
+ exit
+end
+app = Qt::Application.new(ARGV)
+win = PassiveWindow.new(ARGV[0])
+app.mainWidget = win
+win.show
+app.exec
diff --git a/qtruby/rubylib/examples/qt-examples/aclock/aclock.rb b/qtruby/rubylib/examples/qt-examples/aclock/aclock.rb
new file mode 100644
index 00000000..a2cdc378
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/aclock/aclock.rb
@@ -0,0 +1,113 @@
+#!/usr/bin/env ruby -w
+
+require 'Qt'
+
+# an analog clock widget using an internal QTimer
+class AnalogClock < Qt::Widget
+ slots 'setTime(const QTime&)', 'drawClock(QPainter*)', 'timeout()'
+
+ def initialize(*k)
+ super(*k)
+
+ @time = Qt::Time::currentTime
+ @internalTimer = Qt::Timer.new(self)
+ connect(@internalTimer, SIGNAL('timeout()'), self, SLOT('timeout()'))
+ @internalTimer.start(5000)
+ end
+
+ def mousePressEvent(e)
+ if isTopLevel
+ topLeft = geometry.topLeft - frameGeometry.topLeft
+ @clickPos = e.pos + topLeft
+ end
+ end
+
+ def mouseMoveEvent(e)
+ if isTopLevel
+ move(e.globalPos - @clickPos) unless @clickPos.nil?
+ end
+ end
+
+ def setTime(t)
+ # erm. huh?
+ timeout()
+ end
+
+ # The QTimer::timeout() signal is received by this slot.
+ def timeout
+ new_time = Qt::Time::currentTime
+ @time = @time.addSecs 5
+ unless new_time.minute == @time.minute
+ if autoMask
+ updateMask
+ else
+ update
+ end
+ end
+ end
+
+ def paintEvent(blah)
+ unless autoMask
+ paint = Qt::Painter.new(self)
+ paint.setBrush(colorGroup.foreground)
+ drawClock(paint)
+ paint.end
+ end
+ end
+
+ # If clock is transparent, we use updateMask() instead of paintEvent()
+ def updateMask
+ bm = Qt::Bitmap.new(size)
+ bm.fill(color0) # transparent
+
+ paint = Qt::Painter.new
+ paint.begin(bm, self)
+ paint.setBrush(color1) # use non-transparent color
+ paint.setPen(color1)
+
+ drawClock(paint)
+
+ paint.end
+ setMask(bm)
+ end
+
+ # The clock is painted using a 1000x1000 square coordinate system, in
+ # the centered square, as big as possible. The painter's pen and
+ # brush colors are used.
+ def drawClock(paint)
+ paint.save
+
+ paint.setWindow(-500,-500, 1000,1000)
+
+ v = paint.viewport
+ d = [v.width, v.height].min
+ vpx = (v.left + (v.width-d)) / 2
+ vpy = (v.top - (v.height-d)) / 2
+ paint.setViewport(vpx, vpy, d, d)
+
+ paint.save
+ paint.rotate(30*(@time.hour%12-3) + @time.minute/2)
+ pts = Qt::PointArray.new(4, [-20,0, 0,-20, 300,0, 0,20])
+ paint.drawConvexPolygon(pts)
+ paint.restore
+
+ paint.save
+ paint.rotate((@time.minute-15)*6)
+ pts = Qt::PointArray.new(4, [-10,0, 0,-10, 400,0, 0,10])
+ paint.drawConvexPolygon(pts)
+ paint.restore;
+
+ 12.times {
+ paint.drawLine(440,0, 460,0)
+ paint.rotate(30)
+ }
+
+ paint.restore
+ end
+
+ def setAutoMask(background)
+ setBackgroundMode(background ? PaletteForeground : PaletteBackground)
+ Qt::Widget::setAutoMask(background)
+ end
+
+end
diff --git a/qtruby/rubylib/examples/qt-examples/aclock/main.rb b/qtruby/rubylib/examples/qt-examples/aclock/main.rb
new file mode 100755
index 00000000..dadbee15
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/aclock/main.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+require 'aclock'
+
+a = Qt::Application.new(ARGV)
+clock = AnalogClock.new
+ARGV.each {|arg|
+ clock.setAutoMask(true) if arg == '-transparent'
+}
+clock.resize(100, 100)
+a.setMainWidget(clock)
+clock.setCaption('QtRuby example - Analog Clock')
+clock.show
+a.exec
diff --git a/qtruby/rubylib/examples/qt-examples/chart/README b/qtruby/rubylib/examples/qt-examples/chart/README
new file mode 100644
index 00000000..921437c5
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/README
@@ -0,0 +1,8 @@
+
+A Complete Canvas Application
+
+This is a complete example program with a main window, menus and
+toolbars. The main widget is a Qt::Canvas, and this example
+demonstrates basic canvas usage.
+
+This example is the subject of Qt Tutorial #2
diff --git a/qtruby/rubylib/examples/qt-examples/chart/canvastext.rb b/qtruby/rubylib/examples/qt-examples/chart/canvastext.rb
new file mode 100644
index 00000000..8a298faa
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/canvastext.rb
@@ -0,0 +1,16 @@
+
+class CanvasText < Qt::CanvasText
+
+ CANVAS_TEXT = 1100
+ attr :index
+
+ def initialize(index, *k)
+ super(*k)
+ @index = index
+ end
+
+ def rtti() return CANVAS_TEXT end
+
+end
+
+
diff --git a/qtruby/rubylib/examples/qt-examples/chart/canvasview.rb b/qtruby/rubylib/examples/qt-examples/chart/canvasview.rb
new file mode 100644
index 00000000..416b0de7
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/canvasview.rb
@@ -0,0 +1,53 @@
+class CanvasView < Qt::CanvasView
+
+ def initialize(canvas, elements, parent = nil, name = "canvas view", f = 0)
+ super(canvas, parent, name, f)
+ @elements = elements
+ @movingItem = nil
+ end
+
+ def contentsContextMenuEvent( e )
+ parent().optionsMenu.exec( Qt::Cursor.pos() )
+ end
+
+
+ def viewportResizeEvent( e )
+ canvas().resize( e.size().width(), e.size().height() )
+ parent().drawElements()
+ end
+
+
+ def contentsMousePressEvent( e )
+ list = canvas().collisions( e.pos() )
+ list.each do |it|
+ if it.rtti() == CanvasText::CANVAS_TEXT
+ @movingItem = it
+ @pos = e.pos()
+ return
+ end
+ end
+ @movingItem = nil
+ end
+
+
+ def contentsMouseMoveEvent( e )
+ if @movingItem
+ offset = e.pos() - @pos
+ @movingItem.moveBy( offset.x(), offset.y() )
+ @pos = e.pos()
+ form = parent()
+ form.changed = true
+ chartType = form.chartType()
+ item = @movingItem
+ i = item.index()
+
+ @elements[i].setProX( chartType, item.x() / canvas().width() )
+ @elements[i].setProY( chartType, item.y() / canvas().height() )
+
+ canvas().update()
+ end
+ end
+
+end
+
+
diff --git a/qtruby/rubylib/examples/qt-examples/chart/chartform.rb b/qtruby/rubylib/examples/qt-examples/chart/chartform.rb
new file mode 100644
index 00000000..a649ce12
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/chartform.rb
@@ -0,0 +1,488 @@
+class ChartForm < Qt::MainWindow
+
+ slots 'fileNew()',
+ 'fileOpen()',
+ 'fileOpenRecent( int )',
+ 'fileSave()',
+ 'fileSaveAs()',
+ 'fileSaveAsPixmap()',
+ 'filePrint()',
+ 'fileQuit()',
+ 'optionsSetData()',
+ 'updateChartType( QAction * )',
+ 'optionsSetFont()',
+ 'optionsSetOptions()',
+ 'helpHelp()',
+ 'helpAbout()',
+ 'helpAboutQt()',
+ 'saveOptions()'
+
+ attr_accessor :changed
+ attr_reader :chartType, :optionsMenu
+
+ MAX_ELEMENTS = 100
+ MAX_RECENTFILES = 9 # Must not exceed 9
+
+ PIE = 0
+ VERTICAL_BAR = 1
+ HORIZONTAL_BAR = 2
+
+ NO = 0
+ YES = 1
+ AS_PERCENTAGE = 2
+
+ WINDOWS_REGISTRY = "/Trolltech/QtExamples"
+ APP_KEY = "/Chart/"
+
+ def initialize( filename )
+ super( nil, nil, WDestructiveClose )
+ @filename = filename
+ setIcon( Qt::Pixmap.new( "images/options_piechart.xpm" ) )
+
+ fileNewAction = Qt::Action.new(
+ "New Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/file_new.xpm" )),
+ "&New", Qt::KeySequence.new(CTRL+Key_N), self, "new" )
+ connect( fileNewAction, SIGNAL( 'activated()' ), self, SLOT( 'fileNew()' ) )
+
+ fileOpenAction = Qt::Action.new(
+ "Open Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/file_open.xpm" )),
+ "&Open...", Qt::KeySequence.new(CTRL+Key_O), self, "open" )
+ connect( fileOpenAction, SIGNAL( 'activated()' ), self, SLOT( 'fileOpen()' ) )
+
+ fileSaveAction = Qt::Action.new(
+ "Save Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/file_save.xpm" )),
+ "&Save", Qt::KeySequence.new(CTRL+Key_S), self, "save" )
+ connect( fileSaveAction, SIGNAL( 'activated()' ), self, SLOT( 'fileSave()' ) )
+
+ fileSaveAsAction = Qt::Action.new(
+ "Save Chart As", Qt::IconSet.new(Qt::Pixmap.new( "images/file_save.xpm" )),
+ "Save &As...", Qt::KeySequence.new(0), self, "save as" )
+ connect( fileSaveAsAction, SIGNAL( 'activated()' ),
+ self, SLOT( 'fileSaveAs()' ) )
+
+ fileSaveAsPixmapAction = Qt::Action.new(
+ "Save Chart As Bitmap", Qt::IconSet.new(Qt::Pixmap.new( "images/file_save.xpm" )),
+ "Save As &Bitmap...", Qt::KeySequence.new(CTRL+Key_B), self, "save as bitmap" )
+ connect( fileSaveAsPixmapAction, SIGNAL( 'activated()' ),
+ self, SLOT( 'fileSaveAsPixmap()' ) )
+
+ filePrintAction = Qt::Action.new(
+ "Print Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/file_print.xpm" )),
+ "&Print Chart...", Qt::KeySequence.new(CTRL+Key_P), self, "print chart" )
+ connect( filePrintAction, SIGNAL( 'activated()' ),
+ self, SLOT( 'filePrint()' ) )
+
+ optionsSetDataAction = Qt::Action.new(
+ "Set Data", Qt::IconSet.new(Qt::Pixmap.new( "images/options_setdata.xpm" )),
+ "Set &Data...", Qt::KeySequence.new(CTRL+Key_D), self, "set data" )
+ connect( optionsSetDataAction, SIGNAL( 'activated()' ),
+ self, SLOT( 'optionsSetData()' ) )
+
+
+ chartGroup = Qt::ActionGroup.new( self ) # Connected later
+ chartGroup.setExclusive( true )
+
+ @optionsPieChartAction = Qt::Action.new(
+ "Pie Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/options_piechart.xpm" )),
+ "&Pie Chart", Qt::KeySequence.new(CTRL+Key_I), chartGroup, "pie chart" )
+ @optionsPieChartAction.setToggleAction( true )
+
+ @optionsHorizontalBarChartAction = Qt::Action.new(
+ "Horizontal Bar Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/options_horizontalbarchart.xpm" )),
+ "&Horizontal Bar Chart", Qt::KeySequence.new(CTRL+Key_H), chartGroup,
+ "horizontal bar chart" )
+ @optionsHorizontalBarChartAction.setToggleAction( true )
+
+ @optionsVerticalBarChartAction = Qt::Action.new(
+ "Vertical Bar Chart", Qt::IconSet.new(Qt::Pixmap.new( "images/options_verticalbarchart.xpm" )),
+ "&Vertical Bar Chart", Qt::KeySequence.new(CTRL+Key_V), chartGroup, "Vertical bar chart" )
+ @optionsVerticalBarChartAction.setToggleAction( true )
+
+
+ optionsSetFontAction = Qt::Action.new(
+ "Set Font", Qt::IconSet.new(Qt::Pixmap.new( "images/options_setfont.xpm" )),
+ "Set &Font...", Qt::KeySequence.new(CTRL+Key_F), self, "set font" )
+ connect( optionsSetFontAction, SIGNAL( 'activated()' ),
+ self, SLOT( 'optionsSetFont()' ) )
+
+ optionsSetOptionsAction = Qt::Action.new(
+ "Set Options", Qt::IconSet.new(Qt::Pixmap.new( "images/options_setoptions.xpm" )),
+ "Set &Options...", Qt::KeySequence.new(0), self, "set options" )
+ connect( optionsSetOptionsAction, SIGNAL( 'activated()' ),
+ self, SLOT( 'optionsSetOptions()' ) )
+
+ fileQuitAction = Qt::Action.new( "Quit", "&Quit", Qt::KeySequence.new(CTRL+Key_Q), self, "quit" )
+ connect( fileQuitAction, SIGNAL( 'activated()' ), self, SLOT( 'fileQuit()' ) )
+
+
+ fileTools = Qt::ToolBar.new( self, "file operations" )
+ fileTools.setLabel( "File Operations" )
+ fileNewAction.addTo( fileTools )
+ fileOpenAction.addTo( fileTools )
+ fileSaveAction.addTo( fileTools )
+ fileTools.addSeparator()
+ filePrintAction.addTo( fileTools )
+
+ optionsTools = Qt::ToolBar.new( self, "options operations" )
+ optionsTools.setLabel( "Options Operations" )
+ optionsSetDataAction.addTo( optionsTools )
+ optionsTools.addSeparator()
+ @optionsPieChartAction.addTo( optionsTools )
+ @optionsHorizontalBarChartAction.addTo( optionsTools )
+ @optionsVerticalBarChartAction.addTo( optionsTools )
+ optionsTools.addSeparator()
+ optionsSetFontAction.addTo( optionsTools )
+ optionsTools.addSeparator()
+ optionsSetOptionsAction.addTo( optionsTools )
+
+ @fileMenu = Qt::PopupMenu.new( self )
+ menuBar().insertItem( "&File", @fileMenu )
+ fileNewAction.addTo( @fileMenu )
+ fileOpenAction.addTo( @fileMenu )
+ fileSaveAction.addTo( @fileMenu )
+ fileSaveAsAction.addTo( @fileMenu )
+ @fileMenu.insertSeparator()
+ fileSaveAsPixmapAction.addTo( @fileMenu )
+ @fileMenu.insertSeparator()
+ filePrintAction.addTo( @fileMenu )
+ @fileMenu.insertSeparator()
+ fileQuitAction.addTo( @fileMenu )
+
+ @optionsMenu = Qt::PopupMenu.new( self )
+ menuBar().insertItem( "&Options", @optionsMenu )
+ optionsSetDataAction.addTo( @optionsMenu )
+ @optionsMenu.insertSeparator()
+ @optionsPieChartAction.addTo( @optionsMenu )
+ @optionsHorizontalBarChartAction.addTo( @optionsMenu )
+ @optionsVerticalBarChartAction.addTo( @optionsMenu )
+ @optionsMenu.insertSeparator()
+ optionsSetFontAction.addTo( @optionsMenu )
+ @optionsMenu.insertSeparator()
+ optionsSetOptionsAction.addTo( @optionsMenu )
+
+ menuBar().insertSeparator()
+
+ helpMenu = Qt::PopupMenu.new( self )
+ menuBar().insertItem( "&Help", helpMenu )
+ helpMenu.insertItem( "&Help", self, SLOT('helpHelp()'), Qt::KeySequence.new(Key_F1) )
+ helpMenu.insertItem( "&About", self, SLOT('helpAbout()') )
+ helpMenu.insertItem( "About &Qt", self, SLOT('helpAboutQt()') )
+
+
+ @printer = nil
+ @elements = Array.new(MAX_ELEMENTS)
+
+ settings = Qt::Settings.new
+ settings.insertSearchPath( Qt::Settings::Windows, WINDOWS_REGISTRY )
+ windowWidth = settings.readNumEntry( APP_KEY + "WindowWidth", 460 )
+ windowHeight = settings.readNumEntry( APP_KEY + "WindowHeight", 530 )
+ windowX = settings.readNumEntry( APP_KEY + "WindowX", -1 )
+ windowY = settings.readNumEntry( APP_KEY + "WindowY", -1 )
+ setChartType( settings.readNumEntry( APP_KEY + "ChartType", PIE ) )
+ @addValues = settings.readNumEntry( APP_KEY + "AddValues", NO )
+ @decimalPlaces = settings.readNumEntry( APP_KEY + "Decimals", 2 )
+ @font = Qt::Font.new( "Helvetica", 18, Qt::Font::Bold )
+ @font.fromString(
+ settings.readEntry( APP_KEY + "Font", @font.toString() ) )
+ @recentFiles = []
+ for i in 0...MAX_RECENTFILES
+ filename = settings.readEntry( APP_KEY + "File" + ( i + 1 ).to_s )
+ if !filename.nil?
+ @recentFiles.push( filename )
+ end
+ end
+ if @recentFiles.length() > 0
+ updateRecentFilesMenu()
+ end
+
+
+ # Connect *after* we've set the chart type on so we don't call
+ # drawElements() prematurely.
+ connect( chartGroup, SIGNAL( 'selected(QAction*)' ),
+ self, SLOT( 'updateChartType(QAction*)' ) )
+
+ resize( windowWidth, windowHeight )
+ if windowX != -1 || windowY != -1
+ move( windowX, windowY )
+ end
+
+ @canvas = Qt::Canvas.new( self )
+ @canvas.resize( width(), height() )
+ @canvasView = CanvasView.new( @canvas, @elements, self )
+ setCentralWidget( @canvasView )
+ @canvasView.show()
+
+ if ! @filename.nil?
+ load( @filename )
+ else
+ init()
+ @elements[0].set( 20, red, 14, "Red" )
+ @elements[1].set( 70, cyan, 2, "Cyan", darkGreen )
+ @elements[2].set( 35, blue, 11, "Blue" )
+ @elements[3].set( 55, yellow, 1, "Yellow", darkBlue )
+ @elements[4].set( 80, magenta, 1, "Magenta" )
+ drawElements()
+ end
+
+ statusBar().message( "Ready", 2000 )
+ end
+
+
+
+ def init()
+ setCaption( "Chart" )
+ @filename = nil
+ @changed = false
+
+ @elements[0] = Element.new( Element::INVALID, red )
+ @elements[1] = Element.new( Element::INVALID, cyan )
+ @elements[2] = Element.new( Element::INVALID, blue )
+ @elements[3] = Element.new( Element::INVALID, yellow )
+ @elements[4] = Element.new( Element::INVALID, green )
+ @elements[5] = Element.new( Element::INVALID, magenta )
+ @elements[6] = Element.new( Element::INVALID, darkYellow )
+ @elements[7] = Element.new( Element::INVALID, darkRed )
+ @elements[8] = Element.new( Element::INVALID, darkCyan )
+ @elements[9] = Element.new( Element::INVALID, darkGreen )
+ @elements[10] = Element.new( Element::INVALID, darkMagenta )
+ @elements[11] = Element.new( Element::INVALID, darkBlue )
+ for i in 12...MAX_ELEMENTS
+ x = (i.to_f / MAX_ELEMENTS) * 360
+ y = ((x * 256) % 105) + 151
+ z = ((i * 17) % 105) + 151;
+ @elements[i] = Element.new( Element::INVALID, Qt::Color.new( x, y, z, Qt::Color::Hsv ) )
+ end
+ end
+
+ def closeEvent( e )
+ fileQuit()
+ end
+
+
+ def fileNew()
+ if okToClear()
+ init()
+ drawElements()
+ end
+ end
+
+
+ def fileOpen()
+ if !okToClear()
+ return
+ end
+
+ filename = Qt::FileDialog.getOpenFileName(
+ nil, "Charts (*.cht)", self,
+ "file open", "Chart -- File Open" )
+ if !filename.nil?
+ load( filename )
+ else
+ statusBar().message( "File Open abandoned", 2000 )
+ end
+ end
+
+
+ def fileSaveAs()
+ filename = Qt::FileDialog.getSaveFileName(
+ nil, "Charts (*.cht)", self,
+ "file save as", "Chart -- File Save As" )
+ if !filename.nil?
+ answer = 0
+ if Qt::File.exists( filename )
+ answer = Qt::MessageBox.warning(
+ self, "Chart -- Overwrite File",
+ "Overwrite\n\'#{filename}\'?",
+ "&Yes", "&No", nil, 1, 1 )
+ end
+ if answer == 0
+ @filename = filename
+ updateRecentFiles( filename )
+ fileSave()
+ return
+ end
+ end
+ statusBar().message( "Saving abandoned", 2000 )
+ end
+
+
+ def fileOpenRecent( index )
+ if !okToClear()
+ return
+ end
+
+ load( @recentFiles[index] )
+ end
+
+
+ def updateRecentFiles( filename )
+ if @recentFiles.include?( filename )
+ return
+ end
+
+ @recentFiles.push( filename )
+ if @recentFiles.length() > MAX_RECENTFILES
+ @recentFiles.shift()
+ end
+
+ updateRecentFilesMenu()
+ end
+
+
+ def updateRecentFilesMenu()
+ for i in 0...MAX_RECENTFILES
+ if @fileMenu.findItem( i )
+ @fileMenu.removeItem( i )
+ end
+ if i < @recentFiles.length()
+ @fileMenu.insertItem( "&%d %s" % [i + 1, @recentFiles[i]],
+ self, SLOT( 'fileOpenRecent(int)' ),
+ Qt::KeySequence.new(0), i )
+ end
+ end
+ end
+
+
+ def fileQuit()
+ if okToClear()
+ saveOptions()
+ $qApp.exit( 0 )
+ end
+ end
+
+
+ def okToClear()
+ if @changed
+ if @filename.nil?
+ msg = "Unnamed chart "
+ else
+ msg = "Chart '#{@filename}'\n"
+ end
+ msg += "has been changed."
+
+ x = Qt::MessageBox.information( self, "Chart -- Unsaved Changes",
+ msg, "&Save", "Cancel", "&Abandon",
+ 0, 1 )
+ case x
+ when 0 # Save
+ fileSave()
+ when 1 # Cancel
+ when 2 # Abandon
+ else
+ return false
+ end
+ end
+ return true
+ end
+
+
+ def saveOptions()
+ settings = Qt::Settings.new
+ settings.insertSearchPath( Qt::Settings::Windows, WINDOWS_REGISTRY )
+ settings.writeEntry( APP_KEY + "WindowWidth", width() )
+ settings.writeEntry( APP_KEY + "WindowHeight", height() )
+ settings.writeEntry( APP_KEY + "WindowX", x() )
+ settings.writeEntry( APP_KEY + "WindowY", y() )
+ settings.writeEntry( APP_KEY + "ChartType", @chartType )
+ settings.writeEntry( APP_KEY + "AddValues", @addValues )
+ settings.writeEntry( APP_KEY + "Decimals", @decimalPlaces )
+ settings.writeEntry( APP_KEY + "Font", @font.toString() )
+ for i in 0...@recentFiles.length
+ settings.writeEntry( APP_KEY + "File" + ( i + 1 ).to_s,
+ @recentFiles[i] )
+ end
+ end
+
+
+ def optionsSetData()
+ setDataForm = SetDataForm.new( @elements, @decimalPlaces, self )
+ if setDataForm.exec()
+ @changed = true
+ drawElements()
+ end
+ end
+
+
+ def setChartType( chartType )
+ @chartType = chartType;
+ case @chartType
+ when PIE
+ @optionsPieChartAction.setOn( true )
+ when VERTICAL_BAR:
+ @optionsVerticalBarChartAction.setOn( true )
+ when HORIZONTAL_BAR:
+ @optionsHorizontalBarChartAction.setOn( true )
+ end
+ end
+
+
+ def updateChartType( action )
+ if action == @optionsPieChartAction
+ @chartType = PIE
+ elsif action == @optionsHorizontalBarChartAction
+ @chartType = HORIZONTAL_BAR
+ elsif action == @optionsVerticalBarChartAction
+ @chartType = VERTICAL_BAR
+ end
+
+ drawElements()
+ end
+
+
+ def optionsSetFont()
+ ok = Qt::Boolean.new
+ font = Qt::FontDialog.getFont( ok, @font, self )
+ if !ok.nil?
+ @font = font
+ drawElements()
+ end
+ end
+
+
+ def optionsSetOptions()
+ optionsForm = OptionsForm.new( self )
+ optionsForm.chartTypeComboBox.setCurrentItem( @chartType )
+ optionsForm.font = @font
+ case @addValues
+ when NO
+ optionsForm.noRadioButton.setChecked( true )
+ when YES
+ optionsForm.yesRadioButton.setChecked( true )
+ when AS_PERCENTAGE
+ optionsForm.asPercentageRadioButton.setChecked( true )
+ end
+ optionsForm.decimalPlacesSpinBox.setValue( @decimalPlaces )
+ if optionsForm.exec()
+ setChartType( optionsForm.chartTypeComboBox.currentItem() )
+ @font = optionsForm.font
+ if optionsForm.noRadioButton.isChecked()
+ @addValues = NO
+ elsif optionsForm.yesRadioButton.isChecked()
+ @addValues = YES
+ elsif optionsForm.asPercentageRadioButton.isChecked()
+ @addValues = AS_PERCENTAGE
+ end
+ @decimalPlaces = optionsForm.decimalPlacesSpinBox.value()
+ drawElements()
+ end
+ end
+
+
+ def helpHelp()
+ statusBar().message( "Help is not implemented yet", 2000 )
+ end
+
+
+ def helpAbout()
+ Qt::MessageBox.about( self, "Chart -- About",
+ "<center><h1><font color=blue>Chart<font></h1></center>" +
+ "<p>Chart your data with <i>chart</i>.</p>" )
+ end
+
+
+ def helpAboutQt()
+ Qt::MessageBox.aboutQt( self, "Chart -- About Qt" )
+ end
+
+end
+
diff --git a/qtruby/rubylib/examples/qt-examples/chart/chartform_canvas.rb b/qtruby/rubylib/examples/qt-examples/chart/chartform_canvas.rb
new file mode 100644
index 00000000..86c66f76
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/chartform_canvas.rb
@@ -0,0 +1,212 @@
+class ChartForm
+
+ def drawElements()
+ list = @canvas.allItems()
+ list.each do |it|
+ it.dispose
+ end
+
+ # 360 * 16 for pies Qt works with 16ths of degrees
+ scaleFactor = @chartType == PIE ? 5760 :
+ @chartType == VERTICAL_BAR ? @canvas.height() :
+ @canvas.width()
+ biggest = 0.0
+ count = 0
+ total = 0.0
+ scales = Array.new(MAX_ELEMENTS)
+
+ for i in 0...MAX_ELEMENTS
+ if @elements[i].isValid()
+ value = @elements[i].value()
+ count += 1
+ total += value
+ if value > biggest
+ biggest = value
+ end
+ scales[i] = @elements[i].value() * scaleFactor
+ end
+ end
+
+ if count > 0
+ # 2nd loop because of total and biggest
+ for i in 0...MAX_ELEMENTS
+ if @elements[i].isValid()
+ if @chartType == PIE
+ scales[i] = (@elements[i].value() * scaleFactor) / total
+ else
+ scales[i] = (@elements[i].value() * scaleFactor) / biggest
+ end
+ end
+ end
+
+ case @chartType
+ when PIE
+ drawPieChart( scales, total, count )
+ when VERTICAL_BAR:
+ drawVerticalBarChart( scales, total, count )
+ when HORIZONTAL_BAR:
+ drawHorizontalBarChart( scales, total, count )
+ end
+ end
+
+ @canvas.update()
+ end
+
+
+ def drawPieChart( scales, total, i )
+ width = @canvas.width().to_f
+ height = @canvas.height().to_f
+ size = width > height ? height : width
+ x = width / 2
+ y = height / 2
+ angle = 0
+
+ for i in 0...MAX_ELEMENTS
+ if @elements[i].isValid()
+ extent = scales[i]
+ arc = Qt::CanvasEllipse.new( size, size, angle, extent, @canvas )
+ arc.setX( x )
+ arc.setY( y )
+ arc.setZ( 0 )
+ arc.setBrush( Qt::Brush.new( @elements[i].valueColor(),
+ @elements[i].valuePattern() ) )
+ arc.show()
+ angle += extent
+ label = @elements[i].label()
+ if !label.empty? || @addValues != NO
+ label = valueLabel( label, @elements[i].value(), total )
+ text = CanvasText.new( i, label, @font, @canvas )
+ proX = @elements[i].proX( PIE ).to_f
+ proY = @elements[i].proY( PIE ).to_f
+ if proX < 0 || proY < 0
+ # Find the centre of the pie segment
+ rect = arc.boundingRect()
+ proX = ( rect.width() / 2 ) + rect.x()
+ proY = ( rect.height() / 2 ) + rect.y()
+ # Centre text over the centre of the pie segment
+ rect = text.boundingRect()
+ proX -= ( rect.width() / 2 )
+ proY -= ( rect.height() / 2 )
+ # Make proportional
+ proX /= width
+ proY /= height
+ end
+ text.setColor( @elements[i].labelColor() )
+ text.setX( proX * width )
+ text.setY( proY * height )
+ text.setZ( 1 )
+ text.show()
+ @elements[i].setProX( PIE, proX )
+ @elements[i].setProY( PIE, proY )
+ end
+ end
+ end
+ end
+
+
+ def drawVerticalBarChart(scales, total, count )
+ width = @canvas.width().to_f
+ height = @canvas.height().to_f
+ prowidth = width / count
+ x = 0
+ pen = Qt::Pen.new
+ pen.style = NoPen
+
+ for i in 0...MAX_ELEMENTS
+ if @elements[i].isValid()
+ extent = scales[i]
+ y = height - extent
+ rect = Qt::CanvasRectangle.new(x, y, prowidth, extent, @canvas )
+ rect.setBrush( Qt::Brush.new( @elements[i].valueColor(),
+ @elements[i].valuePattern() ) )
+ rect.setPen( pen )
+ rect.setZ( 0 )
+ rect.show()
+ label = @elements[i].label()
+ if !label.empty? || @addValues != NO
+ proX = @elements[i].proX( VERTICAL_BAR ).to_f
+ proY = @elements[i].proY( VERTICAL_BAR ).to_f
+ if proX < 0 || proY < 0
+ proX = x / width
+ proY = y / height
+ end
+ label = valueLabel( label, @elements[i].value(), total )
+ text = CanvasText.new( i, label, @font, @canvas )
+ text.setColor( @elements[i].labelColor() )
+ text.setX( proX * width )
+ text.setY( proY * height )
+ text.setZ( 1 )
+ text.show()
+ @elements[i].setProX( VERTICAL_BAR, proX )
+ @elements[i].setProY( VERTICAL_BAR, proY )
+ end
+ x += prowidth
+ end
+ end
+ end
+
+
+ def drawHorizontalBarChart(scales, total, count )
+ width = @canvas.width().to_f
+ height = @canvas.height().to_f
+ proheight = height / count
+ y = 0
+ pen = Qt::Pen.new
+ pen.style = NoPen
+
+ for i in 0...MAX_ELEMENTS
+ if @elements[i].isValid()
+ extent = scales[i]
+ rect = Qt::CanvasRectangle.new(0, y, extent, proheight, @canvas )
+ rect.setBrush( Qt::Brush.new( @elements[i].valueColor(),
+ @elements[i].valuePattern() ) )
+ rect.setPen( pen )
+ rect.setZ( 0 )
+ rect.show()
+ label = @elements[i].label()
+ if !label.empty? || @addValues != NO
+ proX = @elements[i].proX( HORIZONTAL_BAR ).to_f
+ proY = @elements[i].proY( HORIZONTAL_BAR ).to_f
+ if proX < 0 || proY < 0
+ proX = 0
+ proY = y / height
+ end
+ label = valueLabel( label, @elements[i].value(), total )
+ text = CanvasText.new( i, label, @font, @canvas )
+ text.setColor( @elements[i].labelColor() )
+ text.setX( proX * width )
+ text.setY( proY * height )
+ text.setZ( 1 )
+ text.show()
+ @elements[i].setProX( HORIZONTAL_BAR, proX )
+ @elements[i].setProY( HORIZONTAL_BAR, proY )
+ end
+ y += proheight
+ end
+ end
+ end
+
+
+ def valueLabel(label, value, total )
+ if @addValues == NO
+ return label
+ end
+
+ newLabel = label
+ if !label.empty?
+ if @chartType == VERTICAL_BAR
+ newLabel += "\n"
+ else
+ newLabel += ' '
+ end
+ end
+ if @addValues == YES
+ newLabel += "%.#{@decimalPlaces}f" % value
+ elsif @addValues == AS_PERCENTAGE
+ newLabel += "%.#{@decimalPlaces}f%s" % [(value / total) * 100, '%']
+ end
+ return newLabel
+ end
+
+end
+
diff --git a/qtruby/rubylib/examples/qt-examples/chart/chartform_files.rb b/qtruby/rubylib/examples/qt-examples/chart/chartform_files.rb
new file mode 100644
index 00000000..648aba62
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/chartform_files.rb
@@ -0,0 +1,102 @@
+class ChartForm
+
+ def load( filename )
+ file = Qt::File.new( filename )
+ if !file.open( Qt::IO_ReadOnly )
+ statusBar().message( "Failed to load \'%s\'" % filename, 2000 )
+ return
+ end
+
+ init() # Make sure we have colours
+ @filename = filename
+ ts = Qt::TextStream.new( file )
+ errors = 0
+ i = 0
+ while !ts.eof()
+ element = Element.new
+ ts >> element
+ if element.isValid()
+ @elements[i] = element
+ i += 1
+ else
+ errors += 1
+ end
+ if i == MAX_ELEMENTS
+ statusBar().message("Read maximum number of elements (%d) discarding others" % i, 2000 )
+ break
+ end
+ end
+
+ file.close()
+
+ bad = ""
+ if errors > 0
+ bad = " skipped %d bad record" % errors
+ if errors > 1
+ bad += "s"
+ end
+ end
+ statusBar().message( "Read %d values from \'%s\'" % [i, filename], 3000 )
+
+ setCaption( "Chart -- %s" % filename )
+ updateRecentFiles( filename )
+
+ drawElements()
+ @changed = false
+ end
+
+
+ def fileSave()
+ if @filename.nil?
+ fileSaveAs()
+ return
+ end
+
+ file = Qt::File.new( @filename )
+ if !file.open( Qt::IO_WriteOnly )
+ statusBar().message( "Failed to save \'%s\'" % @filename, 2000 )
+ return
+ end
+ ts = Qt::TextStream.new( file )
+ for i in 0...MAX_ELEMENTS
+ if @elements[i].isValid()
+ ts << @elements[i]
+ end
+ end
+
+ file.close()
+
+ setCaption( "Chart -- %s" % @filename )
+ statusBar().message( "Saved \'%s\'" % @filename, 2000 )
+ @changed = false
+ end
+
+
+ def fileSaveAsPixmap()
+ filename = Qt::FileDialog.getSaveFileName(nil, "Images (*.png *.xpm *.jpg)",
+ self, "file save as bitmap",
+ "Chart -- File Save As Bitmap" )
+ if Qt::Pixmap.grabWidget( @canvasView ).save( filename,
+ filename.sub(/.*\.([^.]*)$/, '\1').upcase() )
+ statusBar().message( "Wrote \'%s\'" % filename, 2000 )
+ else
+ statusBar().message( "Failed to write \'%s\'" % filename, 2000 )
+ end
+ end
+
+ def filePrint()
+ if !@printer
+ @printer = Qt::Printer.new
+ end
+ if @printer.setup()
+ painter = Qt::Painter.new( @printer )
+ @canvas.drawArea( Qt::Rect.new( 0, 0, @canvas.width(), @canvas.height() ),
+ painter, false )
+ if !@printer.outputFileName().empty?
+ statusBar().message( "Printed \'%s\'" % @printer.outputFileName(), 2000 )
+ end
+ end
+ end
+
+end
+
diff --git a/qtruby/rubylib/examples/qt-examples/chart/element.rb b/qtruby/rubylib/examples/qt-examples/chart/element.rb
new file mode 100644
index 00000000..ba135632
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/element.rb
@@ -0,0 +1,161 @@
+class Element
+
+ FIELD_SEP = ':'
+ PROPOINT_SEP = ';'
+ XY_SEP = ','
+
+ EPSILON = 0.0000001
+
+ INVALID = -1
+ NO_PROPORTION = -1
+ MAX_PROPOINTS = 3 # One proportional point per chart type
+
+ attr_accessor :value, :valueColor, :valuePattern, :label, :labelColor
+
+ def initialize( value = INVALID, valueColor = Qt::gray,
+ valuePattern = Qt::SolidPattern,
+ label = nil,
+ labelColor = Qt::black )
+ init( value, valueColor, valuePattern, label, labelColor )
+ @propoints = []
+ for i in 0...MAX_PROPOINTS * 2
+ @propoints[i] = NO_PROPORTION
+ end
+ end
+
+ def isValid() return @value > EPSILON end
+
+
+ def init( value, valueColor, valuePattern,
+ label, labelColor )
+ @value = value
+ @valueColor = valueColor
+ if Qt::SolidPattern >= valuePattern || Qt::DiagCrossPattern <= valuePattern
+ valuePattern = Qt::SolidPattern
+ end
+ @valuePattern = valuePattern
+ @label = label
+ @labelColor = labelColor
+ end
+
+ def set( value = INVALID, valueColor = Qt::gray,
+ valuePattern = Qt::SolidPattern,
+ label = nil,
+ labelColor = Qt::black )
+ init( value, valueColor, valuePattern, label, labelColor )
+ end
+
+ def setValuePattern( valuePattern )
+ if valuePattern < Qt::SolidPattern.to_i || valuePattern > Qt::DiagCrossPattern.to_i
+ valuePattern = Qt::SolidPattern
+ end
+ @valuePattern = valuePattern
+ end
+
+
+ def proX( index )
+ return @propoints[2 * index]
+ end
+
+
+ def proY( index )
+ return @propoints[(2 * index) + 1]
+ end
+
+
+ def setProX( index, value )
+ @propoints[2 * index] = value
+ end
+
+
+ def setProY( index, value )
+ @propoints[(2 * index) + 1] = value
+ end
+
+end
+
+class Qt::TextStream
+
+ alias op_write <<
+
+ def <<( item )
+ if !item.kind_of? Element
+ return op_write(item)
+ end
+ element = item
+ self << element.value() << Element::FIELD_SEP <<
+ element.valueColor().name() << Element::FIELD_SEP <<
+ element.valuePattern().to_i << Element::FIELD_SEP <<
+ element.labelColor().name() << Element::FIELD_SEP
+
+ for i in 0...Element::MAX_PROPOINTS
+ self << element.proX( i ) << Element::XY_SEP << element.proY( i )
+ self << ( i == Element::MAX_PROPOINTS - 1 ? Element::FIELD_SEP : Element::PROPOINT_SEP )
+ end
+
+ self << element.label() << "\n"
+
+ return self
+ end
+
+ alias op_read >>
+
+ def >>( item )
+ if !item.kind_of? Element
+ return op_read(item)
+ end
+
+ element = item
+ data = readLine()
+ element.value = Element::INVALID
+
+ errors = 0
+
+ fields = data.split( Element::FIELD_SEP )
+ if fields.length() >= 4
+ value = fields[0].to_f
+ if value.nil?
+ errors += 1
+ end
+ valueColor = Qt::Color.new( fields[1] )
+ if !valueColor.isValid()
+ errors += 1
+ end
+ valuePattern = fields[2].to_i
+ if valuePattern.nil?
+ errors += 1
+ end
+ labelColor = Qt::Color.new( fields[3] )
+ if !labelColor.isValid()
+ errors += 1
+ end
+ propoints = fields[4].split( Element::PROPOINT_SEP )
+ label = data.split(Element::FIELD_SEP)[5]
+ if errors == 0
+ element.set( value, valueColor, valuePattern, label, labelColor )
+ i = 0
+ propoints.each do |point|
+ errors = 0
+ xy = point.split( Element::XY_SEP )
+ x = xy[0].to_f
+ if x.nil? || x <= 0.0 || x >= 1.0
+ errors += 1
+ end
+ y = xy[1].to_f
+ if y.nil? || y <= 0.0 || y >= 1.0
+ errors += 1
+ end
+ if errors > 0
+ x = y = Element::NO_PROPORTION
+ end
+ element.setProX( i, x )
+ element.setProY( i, y )
+ i += 1
+ end
+ end
+ end
+
+ return self
+ end
+
+end
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/chart-forms.sk b/qtruby/rubylib/examples/qt-examples/chart/images/chart-forms.sk
new file mode 100644
index 00000000..d9087b48
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/chart-forms.sk
@@ -0,0 +1,256 @@
+##Sketch 1 2
+document()
+layout('A4',0)
+layer('Layer 1',1,1,0,0,(0,0,0))
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(188.034,0,0,-149.201,526.688,-521.707)
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(128.762,0,0,-92.995,341.407,-572.49)
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(128.762,0,0,-92.995,768.68,-572.934)
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+e(31.6796,0,0,31.6796,635.564,-722.4)
+fp((0.8,0.8,0.8))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(188.034,0,0,-149.201,518.884,-513.603)
+fp((1,1,1))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(158.398,0,0,-106.28,533.702,-545.185)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('ChartForm',(575.182,-535.064))
+fp((0.8,0.8,0.8))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(128.762,0,0,-92.995,335.96,-566.743)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('OptionsForm',(354.009,-589.226))
+fp((0.8,0.8,0.8))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(128.762,0,0,-92.995,763.221,-566.743)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('SetDataForm',(781.675,-587.279))
+fp((1,0,1))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+e(31.6796,0,0,31.6796,631.296,-719.01)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-BoldOblique')
+Fs(18)
+txt('chart',(613.251,-723.609))
+G()
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('CanvasView',(569.827,-575.941))
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('depicting a',(573.94,-595.357))
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('QCanvas',(580.906,-614.774))
+G_()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(662.975,-716.966,0)
+bc(669.107,-712.686,671.463,-709.765,672.485,-707.625,2)
+bc(673.507,-705.485,677.438,-697.225,677.438,-696.155,2)
+bc(677.438,-695.085,679.326,-682.725,679.326,-682.725,2)
+bc(679.326,-682.725,679.326,-670.955,679.326,-670.955,2)
+bc(679.326,-670.955,679.326,-665.605,679.326,-664.535,2)
+lw(1.41732)
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(710.729,-618.861,0)
+bs(759.036,-618.861,0)
+lw(1.41732)
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(515.603,-617.742,0)
+bs(467.885,-617.742,0)
+G()
+fp((0,0.392,0))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+e(29.7517,0,0,-7.65884,468.929,-768.389)
+fp((0,0.392,0))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(58.9143,0,0,-44.1857,439.032,-724.349)
+fp((0,0.392,0))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+e(29.7517,0,0,-7.65884,468.929,-722.581)
+G_()
+lw(1.41732)
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(499.125,-739.077,0)
+bc(507.548,-735.049,508.671,-732.747,512.04,-728.144,2)
+bc(515.409,-723.54,519.901,-717.21,520.463,-716.059,2)
+bc(521.024,-714.909,531.132,-689.589,531.132,-689.589,2)
+bc(531.132,-689.589,533.378,-679.231,533.378,-679.231,2)
+bc(533.378,-679.231,535.062,-671.175,535.062,-671.175,2)
+bc(535.062,-671.175,535.062,-664.845,535.062,-664.845,2)
+fp((1,1,1))
+le()
+lw(1)
+Fn('Helvetica-Narrow-Bold')
+Fs(18)
+txt('disk',(453.761,-753.806))
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('run',(681.17,-700.783))
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('save',(524.007,-725.891))
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('load',(494.295,-706.489))
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(143.737,0,0,-67.586,525.422,-405.581)
+fp((0.596,0.984,0.596))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(143.737,0,0,-67.586,519.327,-401.081)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('getOpenFileName()',(526.396,-420.297))
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(143.737,0,0,-67.586,704.655,-405.581)
+fp((0.596,0.984,0.596))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(143.737,0,0,-67.586,698.561,-401.081)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('getSaveFileName()',(706.863,-420.39))
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(100.503,0,0,-67.586,375.286,-429.722)
+fp((0.529,0.808,0.98))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(100.503,0,0,-67.586,371.024,-425.223)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('getFont()',(391.333,-444.571))
+fp((0.9,0.9,0.9))
+le()
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(100.503,0,0,-67.586,935.176,-580.856)
+fp((1,0.753,0.796))
+lw(1.41732)
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+r(100.503,0,0,-67.586,930.915,-576.357)
+fp((0,0,0))
+le()
+lw(1)
+Fn('Helvetica-Narrow')
+Fs(18)
+txt('getColor()',(948.361,-598.303))
+lw(1.41732)
+ld((1, 1))
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(591.836,-511.466,0)
+bs(591.836,-471.702,0)
+lw(1.41732)
+ld((1, 1))
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(674.96,-513.083,0)
+bs(749.29,-470.169,0)
+lw(1.41732)
+ld((1, 1))
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(538.877,-513.083,0)
+bs(472.859,-474.968,0)
+lw(1.41732)
+ld((1, 1))
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(410.746,-562.437,0)
+bs(410.746,-494.504,0)
+lw(1.41732)
+ld((1, 1))
+la1(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+la2(([(-4.0, 3.0), (2.0, 0.0), (-4.0, -3.0), (-4.0, 3.0)], 1))
+b()
+bs(895.423,-617.315,0)
+bs(928.721,-617.315,0)
+guidelayer('Guide Lines',1,0,0,1,(0,0,1))
+grid((0,0,20,20),0,(0,0,1),'Grid')
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/file_new.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/file_new.xpm
new file mode 100644
index 00000000..8537176c
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/file_new.xpm
@@ -0,0 +1,36 @@
+/* XPM */
+static const char *file_new[] = {
+"20 20 12 1",
+" c white",
+"! c None",
+"# c #000",
+"$ c #2e2e2e2e2e2e",
+"% c #ffffffffffff",
+"& c #5c5c5c5c5c5c",
+"( c #878787878787",
+") c #c2c2c2c2c2c2",
+"* c black",
+"+ c #00C900",
+", c #ffff00",
+"- c red",
+"!!!!!!!!!!!!!!!!!!!!",
+"!!##########$!!!!!!!",
+"!!#%%%%%%%%#&$!!!!!!",
+"!!#%%%%%%%%#(&$!!!!!",
+"!!#%%%%%%%%#)(&$!!!!",
+"!!#%%%%%%%%#%)(&$!!!",
+"!!#%%%%*****#####!!!",
+"!!#%%%*+++++*%%%#!!!",
+"!!#%%*,++++++*%%#!!!",
+"!!#%*,,,++++++*%#!!!",
+"!!#%*,,,,+++++*%#!!!",
+"!!#%*,,,,-++++*%#!!!",
+"!!#%*,,,---+++*%#!!!",
+"!!#%*,,-----++*%#!!!",
+"!!#%%*-------*%%#!!!",
+"!!#%%%*-----*%%%#!!!",
+"!!#%%%%*****%%%%#!!!",
+"!!#%%%%%%%%%%%%%#!!!",
+"!!###############!!!",
+"!!!!!!!!!!!!!!!!!!!!"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/file_open.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/file_open.xpm
new file mode 100644
index 00000000..7a7b681d
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/file_open.xpm
@@ -0,0 +1,33 @@
+/* XPM */
+static const char *file_open[] = {
+"20 20 9 1",
+" c white",
+"! c None",
+"# c #002EFF",
+"$ c #000",
+"% c #ffffffff0",
+"& c #ffffffffffff",
+"( c #00C900",
+") c #ffff00",
+"* c #A500FF",
+"!!!!!!!!!!####!!!!#!",
+"!!!!!!!!!#!!!!##!##!",
+"!!!!!!!!!!!!!!!!###!",
+"!!!!!!!!!!!!!!!####!",
+"!!!!!!!!!!!!!!#####!",
+"!$$$$!!!!!!!!!!!!!!!",
+"$%&%&$$$$$$$$!!!!!!!",
+"$&%&%&%&%&%&$!!!!!!!",
+"$%&&&$$$$$&&$!!!!!!!",
+"$&&&$((((($&$!!!!!!!",
+"$%&$)(($$$$$$$$$$$$$",
+"$&$)))$***********$$",
+"$%$))$***********$$!",
+"$&$)$***********$$!!",
+"$%$$***********$$!!!",
+"$&$***********$$!!!!",
+"$$***********$$!!!!!",
+"$$***********$!!!!!!",
+"$$$$$$$$$$$$$!!!!!!!",
+"!!!!!!!!!!!!!!!!!!!!"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/file_print.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/file_print.xpm
new file mode 100644
index 00000000..915f65ba
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/file_print.xpm
@@ -0,0 +1,115 @@
+/* XPM */
+static const char *file_print[] = {
+/* columns rows colors chars-per-pixel */
+"20 20 89 1",
+" c Gray0",
+". c #101008081010",
+"X c #101010101010",
+"o c #101010101818",
+"O c #181810101818",
+"+ c #181818181818",
+"@ c #181818182121",
+"# c #212118182121",
+"$ c Gray13",
+"% c #212121212929",
+"& c #292921212929",
+"* c Gray16",
+"= c #292929293131",
+"- c #313129293131",
+"; c #313131313131",
+": c #313131313939",
+"> c #393931313939",
+", c #393939393939",
+"< c #393939394242",
+"1 c #424239394242",
+"2 c Gray26",
+"3 c #4a4a4a4a5252",
+"4 c #5a5a52525a5a",
+"5 c #5a5a5a5a6363",
+"6 c #6b6b63636b6b",
+"7 c Gray42",
+"8 c #6b6b6b6b7373",
+"9 c #73736b6b7373",
+"0 c #7b7b73737b7b",
+"q c #7b7b73738484",
+"w c #0808ffff0808",
+"e c #2929ffff2929",
+"r c #3131ffff3131",
+"t c #5a5acece5a5a",
+"y c #6b6bffff6363",
+"u c #7b7bffff7b7b",
+"i c #84847b7b8484",
+"p c #84847b7b8c8c",
+"a c #8c8c7b7b9494",
+"s c #848484848c8c",
+"d c #8c8c84848c8c",
+"f c Gray55",
+"g c #8c8c84849494",
+"h c #8c8c8c8c9494",
+"j c #94948c8c9494",
+"k c #94948c8c9c9c",
+"l c Gray58",
+"z c #949494949c9c",
+"x c #9c9c94949c9c",
+"c c Gray61",
+"v c #9c9c9494a5a5",
+"b c #9c9c9c9ca5a5",
+"n c #a5a59c9ca5a5",
+"m c #a5a59c9cadad",
+"M c #adad9c9cadad",
+"N c #a5a5a5a5a5a5",
+"B c #a5a5a5a5adad",
+"V c #adada5a5adad",
+"C c Gray68",
+"Z c #adadadadb5b5",
+"A c #b5b5adadb5b5",
+"S c Gray71",
+"D c Gray74",
+"F c #9494c6c69494",
+"G c #9c9ccecea5a5",
+"H c #bdbdd6d6bdbd",
+"J c #c0c0c0c0c0c0",
+"K c #c6c6c6c6c6c6",
+"L c #cecec6c6cece",
+"P c #cececececece",
+"I c #cecececed6d6",
+"U c #d6d6ceced6d6",
+"Y c #d6d6cecedede",
+"T c Gray84",
+"R c #d6d6d6d6dede",
+"E c #deded6d6dede",
+"W c Gray87",
+"Q c #deded6d6e7e7",
+"! c #dedededee7e7",
+"~ c #d6d6ffffd6d6",
+"^ c #e7e7dedee7e7",
+"/ c #e7e7e7e7e7e7",
+"( c #e7e7e7e7efef",
+") c #efefe7e7efef",
+"_ c #efefefefefef",
+"` c #e7e7ffffe7e7",
+"' c Gray97",
+"] c Gray100",
+"[ c None",
+/* pixels */
+"[[[[[[SDPPKKDDCD[[[[",
+"[[[[[[D_///___WD[[[[",
+"[[[[[[DKKPKKKKDK[[[[",
+"[[[[[[SDDSDDSSCD[[[[",
+"[[[[[KCKDKDDDKS[[[[[",
+"[[[[[KDDDDDDDDS[[[[[",
+"[[[[[CP/WWWWTWNNZ[[[",
+"[[[Dc9STPTPTWWj427S[",
+"[[Dziq00000pag8<%@2N",
+"[DcE(!ERRUYGtFn2##O<",
+"Db)]]]]]]]~ewePa;@X#",
+"V']]]]]]]]`yru]Q0@ #",
+"BRILITRRWE!RHUILhO @",
+"jAZVBmBnmmnmMvzh6o #",
+"jZZmBnnnbbbbvxxg6o +",
+"lmmnbnbbbvxxxvjs6O 3",
+"jBnnvcvxvxvxzjhd8o+C",
+"lsdgfgdhghjhjkhg6+l[",
+"S9%@$%&&&-::>>:-:l[[",
+"[[C511,:;**%++.2c[[["
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/file_save.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/file_save.xpm
new file mode 100644
index 00000000..61638992
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/file_save.xpm
@@ -0,0 +1,33 @@
+/* XPM */
+static const char *file_save[] = {
+"20 20 9 1",
+" c white",
+"! c #000",
+"# c #002EFF",
+"$ c #999999999999",
+"% c None",
+"& c #00C900",
+"( c #ffff00",
+") c red1",
+"* c black",
+"!!!!!!!!!!!!!!!!!!!!",
+"!##!$$$!!!!!!$$$!%%!",
+"!##!$$!&&&&&&!$$!%%!",
+"!##!$!(&&&&&&&!$!!!!",
+"!##!!(((&&&&&&&!!##!",
+"!##!!((((&&&&&&!!##!",
+"!##!!((((()&&&&!!##!",
+"!##!!((())))&&&!!##!",
+"!##!!(())))))&&!!##!",
+"!##!$!))))))))!$!##!",
+"!###!$!))))))!$*###!",
+"!####***!!!!!***###!",
+"!##################!",
+"!###!!!!!!!!!!!!!##!",
+"!###!!!!!!!!!$$$!##!",
+"!###!!!!!!!!!$$$!##!",
+"!###!!!!!!!!!$$$!##!",
+"!###!!!!!!!!!$$$!##!",
+"!###!!!!!!!!!$$$!##!",
+"%!!!!!!!!!!!!!!!!!!%"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/file_saveaspostscript.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/file_saveaspostscript.xpm
new file mode 100644
index 00000000..7dd75fcf
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/file_saveaspostscript.xpm
@@ -0,0 +1,34 @@
+/* XPM */
+static const char *file_saveaspostscript[] = {
+"20 20 10 1",
+" c white",
+"! c #000",
+"# c #002EFF",
+"$ c #999999999999",
+"% c None",
+"& c #00C900",
+"( c #ffff00",
+") c red1",
+"* c black",
+"+ c grey100",
+"!!!!!!!!!!!!!!!!!!!!",
+"!##!$$$!!!!!!$$$!%%!",
+"!##!$$!&&&&&&!$$!%%!",
+"!##!$!(&&&&&&&!$!!!!",
+"!##!!(((&&&&&&&!!##!",
+"!##!!((((&&&&&&!!##!",
+"!##!!((((()&&&&!!##!",
+"!##!!((())))&&&!!##!",
+"!##!!(())))))&&!!##!",
+"!##!$!))))))))!$!##!",
+"!###!$!))))))!$*###!",
+"!####***!!!!!***###!",
+"!##################!",
+"!###!!!!!!!!!!!!!##!",
+"!###!+++!+++!$$$!##!",
+"!###!+!+!+!!!$$$!##!",
+"!###!+++!+++!$$$!##!",
+"!###!+!!!!!+!$$$!##!",
+"!###!+!!!+++!$$$!##!",
+"%!!!!!!!!!!!!!!!!!!%"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/options_horizontalbarchart.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/options_horizontalbarchart.xpm
new file mode 100644
index 00000000..afb06ffa
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/options_horizontalbarchart.xpm
@@ -0,0 +1,31 @@
+/* XPM */
+static const char *options_horizontalbarchart[] = {
+"20 20 7 1",
+"( c #A500FF",
+" c white",
+"! c red1",
+"# c None",
+"$ c #E9FF00",
+"% c #00C900",
+"& c #002EFF",
+"!!!!!!!!!!!!!!######",
+"!!!!!!!!!!!!!!######",
+"!!!!!!!!!!!!!!######",
+"!!!!!!!!!!!!!!######",
+"$$$$$$$$$$$$$$$$$###",
+"$$$$$$$$$$$$$$$$$###",
+"$$$$$$$$$$$$$$$$$###",
+"$$$$$$$$$$$$$$$$$###",
+"%%%%%%%%%%%%%%%%%%%%",
+"%%%%%%%%%%%%%%%%%%%%",
+"%%%%%%%%%%%%%%%%%%%%",
+"%%%%%%%%%%%%%%%%%%%%",
+"&&&&&&&&&&&&&&######",
+"&&&&&&&&&&&&&&######",
+"&&&&&&&&&&&&&&######",
+"&&&&&&&&&&&&&&######",
+"(((((((((((#########",
+"(((((((((((#########",
+"(((((((((((#########",
+"(((((((((((#########"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/options_piechart.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/options_piechart.xpm
new file mode 100644
index 00000000..221c78de
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/options_piechart.xpm
@@ -0,0 +1,30 @@
+/* XPM */
+static const char *options_piechart[] = {
+"20 20 6 1",
+" c white",
+"! c None",
+"# c black",
+"$ c #00C900",
+"% c #E9FF00",
+"& c red1",
+"!!!!!!#######!!!!!!!",
+"!!!!##$$$$$$$##!!!!!",
+"!!!#%$$$$$$$$$$#!!!!",
+"!!#%%%$$$$$$$$$$#!!!",
+"!#%%%%%$$$$$$$$$$#!!",
+"!#%%%%%$$$$$$$$$$#!!",
+"#%%%%%%%$$$$$$$$$$#!",
+"#%%%%%%%%$$$$$$$$$#!",
+"#%%%%%%%%$$$$$$$$$#!",
+"#%%%%%%%%%$$$$$$$$#!",
+"#%%%%%%%%&&$$$$$$$#!",
+"#%%%%%%%&&&&$$$$$$#!",
+"#%%%%%%&&&&&&&$$$$#!",
+"#%%%%%&&&&&&&&&$$$#!",
+"!#%%%&&&&&&&&&&&&#!!",
+"!#%%&&&&&&&&&&&&&#!!",
+"!!#&&&&&&&&&&&&&#!!!",
+"!!!#&&&&&&&&&&&#!!!!",
+"!!!!##&&&&&&&##!!!!!",
+"!!!!!!#######!!!!!!!"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/options_setdata.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/options_setdata.xpm
new file mode 100644
index 00000000..4ff70a54
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/options_setdata.xpm
@@ -0,0 +1,34 @@
+/* XPM */
+static const char *options_setdata[] = {
+"20 20 10 1",
+" c white",
+"! c None",
+"# c grey40",
+"$ c #002EFF",
+"% c black",
+"& c red1",
+"( c #00C900",
+") c #A500FF",
+"* c #E9FF00",
+"+ c cyan1",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#####!$$!!#####!%%!",
+"!#####!$$!!#####!%%!",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#####!&&!!#####!%%!",
+"!#####!&&!!#####!%%!",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#####!((!!#####!%%!",
+"!#####!((!!#####!%%!",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#####!))!!#####!%%!",
+"!#####!))!!#####!%%!",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#####!**!!#####!%%!",
+"!#####!**!!#####!%%!",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#####!++!!#####!%%!",
+"!#####!++!!#####!%%!",
+"!!!!!!!!!!!!!!!!!!!!",
+"!!!!!!!!!!!!!!!!!!!!"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/options_setfont.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/options_setfont.xpm
new file mode 100644
index 00000000..ab552248
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/options_setfont.xpm
@@ -0,0 +1,27 @@
+/* XPM */
+static const char *options_setfont[] = {
+"20 20 3 1",
+" c white",
+"! c None",
+"# c #002EFF",
+"!!!!!!!!!!!!!!!!!!!!",
+"!!!!!!!!!!!!#####!!!",
+"!!!!!!!!!!!#######!!",
+"!!!!!!!!!!!##!!!!##!",
+"!!!!!!!!!!##!!!!###!",
+"!!!!!!!!!!##!!!!###!",
+"!!!!!!!!!###!!!!!!!!",
+"!!!!!!!!!##!!!!!!!!!",
+"!!!!!#############!!",
+"!!!!###!!########!!!",
+"!!!##!!!!##!!!!!!!!!",
+"!!!##!!!!#!!!!!!!!!!",
+"!!!!!!!!##!!!!!!!!!!",
+"!!!!!!!!##!!!!!!!!!!",
+"!!!!!!!###!!!!!!!!!!",
+"!!!!!!!##!!!!!!!!!!!",
+"!!!!!!##!!!!!!!!!!!!",
+"!#!!!###!!!!!!!!!!!!",
+"!######!!!!!!!!!!!!!",
+"!!####!!!!!!!!!!!!!!"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/options_setoptions.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/options_setoptions.xpm
new file mode 100644
index 00000000..029cf47d
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/options_setoptions.xpm
@@ -0,0 +1,32 @@
+/* XPM */
+static const char *options_setoptions[] = {
+"20 20 8 1",
+"( c #A500FF",
+" c white",
+") c grey30",
+"! c None",
+"# c #000",
+"$ c grey60",
+"% c grey100",
+"& c black",
+"!!!!!!!!!!!!!!!!!!!!",
+"!#############$$$$$!",
+"!#%%%%%%%%%%%%&$$$$!",
+"!#%%%%%%%%%%%%%&$$$!",
+"!#%%%%%%%%%%%%%%&$$!",
+"!#%%%%%%%%%%%%%%%&$!",
+"!#%%((%%%%%%%%%%%%#!",
+"!#%%((%%%%%%%%%%%%#!",
+"!#%%((%%%%%%%%%%%%#!",
+"!#(((((((%%%%%%%%%#!",
+"!#(((((((%%%%%%%%%#!",
+"!#%%((%%%%%)%))))%#!",
+"!#%%((%%%%%%%%%%%%#!",
+"!#%%((%)))%)))%))%#!",
+"!#%%%%%%%%%%%%%%%%#!",
+"!#%%))%)%))))%))%%#!",
+"!#%%%%%%%%%%%%%%%%#!",
+"!#%%%%%%%%%%%%%%%%#!",
+"!##################!",
+"!!!!!!!!!!!!!!!!!!!!"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/options_verticalbarchart.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/options_verticalbarchart.xpm
new file mode 100644
index 00000000..e812f0f9
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/options_verticalbarchart.xpm
@@ -0,0 +1,31 @@
+/* XPM */
+static const char *options_verticalbarchart[] = {
+"20 20 7 1",
+"( c #A500FF",
+" c white",
+"! c None",
+"# c #00C900",
+"$ c #E9FF00",
+"% c red1",
+"& c #002EFF",
+"!!!!!!!!####!!!!!!!!",
+"!!!!!!!!####!!!!!!!!",
+"!!!!!!!!####!!!!!!!!",
+"!!!!$$$$####!!!!!!!!",
+"!!!!$$$$####!!!!!!!!",
+"!!!!$$$$####!!!!!!!!",
+"%%%%$$$$####&&&&!!!!",
+"%%%%$$$$####&&&&!!!!",
+"%%%%$$$$####&&&&!!!!",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&((((",
+"%%%%$$$$####&&&&(((("
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern01.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern01.xpm
new file mode 100644
index 00000000..26a70cbd
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern01.xpm
@@ -0,0 +1,27 @@
+/* XPM */
+static const char *pattern01[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 1 1",
+" c black",
+/* pixels */
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern02.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern02.xpm
new file mode 100644
index 00000000..cc5b7948
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern02.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern02[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+". . . . . . . . . . ",
+" ",
+" ",
+" ",
+". . . . . . . . . . ",
+" ",
+" ",
+" ",
+". . . . . . . . . . ",
+" ",
+" ",
+" ",
+". . . . . . . . . . ",
+" ",
+" ",
+" ",
+". . . . . . . . . . ",
+" ",
+" ",
+" "
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern03.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern03.xpm
new file mode 100644
index 00000000..d9fc57a9
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern03.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern03[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+" . . . . . . . . . . ",
+" ",
+". . . . . . . . . . ",
+" ",
+" . . . . . . . . . . ",
+" ",
+". . . . . . . . . . ",
+" ",
+" . . . . . . . . . . ",
+" ",
+". . . . . . . . . . ",
+" ",
+" . . . . . . . . . . ",
+" ",
+". . . . . . . . . . ",
+" ",
+" . . . . . . . . . . ",
+" ",
+". . . . . . . . . . ",
+" "
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern04.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern04.xpm
new file mode 100644
index 00000000..85b9223b
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern04.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern04[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+". . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+" . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+" . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+" . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+" . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+" . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . ."
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern05.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern05.xpm
new file mode 100644
index 00000000..cc7beee9
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern05.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern05[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . ",
+" . . . . . . . . . . . . . . . . . . . .",
+". . . . . . . . . . . . . . . . . . . . "
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern06.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern06.xpm
new file mode 100644
index 00000000..ad8b0554
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern06.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern06[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+".. ... ... ... ... ... ... ... ... ... .",
+". . . . . . . . . . . . . . . . . . . . ",
+" ... ... ... ... ... ... ... ... ... ...",
+". . . . . . . . . . . . . . . . . . . . ",
+".. ... ... ... ... ... ... ... ... ... .",
+". . . . . . . . . . . . . . . . . . . . ",
+" ... ... ... ... ... ... ... ... ... ...",
+". . . . . . . . . . . . . . . . . . . . ",
+".. ... ... ... ... ... ... ... ... ... .",
+". . . . . . . . . . . . . . . . . . . . ",
+" ... ... ... ... ... ... ... ... ... ...",
+". . . . . . . . . . . . . . . . . . . . ",
+".. ... ... ... ... ... ... ... ... ... .",
+". . . . . . . . . . . . . . . . . . . . ",
+" ... ... ... ... ... ... ... ... ... ...",
+". . . . . . . . . . . . . . . . . . . . ",
+".. ... ... ... ... ... ... ... ... ... .",
+". . . . . . . . . . . . . . . . . . . . ",
+" ... ... ... ... ... ... ... ... ... ...",
+". . . . . . . . . . . . . . . . . . . . "
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern07.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern07.xpm
new file mode 100644
index 00000000..d01c55f9
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern07.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern07[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+" ... ... ... ... ... ... ... ... ... ...",
+"........................................",
+".. ... ... ... ... ... ... ... ... ... .",
+"........................................",
+" ... ... ... ... ... ... ... ... ... ...",
+"........................................",
+".. ... ... ... ... ... ... ... ... ... .",
+"........................................",
+" ... ... ... ... ... ... ... ... ... ...",
+"........................................",
+".. ... ... ... ... ... ... ... ... ... .",
+"........................................",
+" ... ... ... ... ... ... ... ... ... ...",
+"........................................",
+".. ... ... ... ... ... ... ... ... ... .",
+"........................................",
+" ... ... ... ... ... ... ... ... ... ...",
+"........................................",
+".. ... ... ... ... ... ... ... ... ... .",
+"........................................"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern08.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern08.xpm
new file mode 100644
index 00000000..b0ce09fe
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern08.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern08[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+"........................................",
+"........................................",
+"... ... ... ... ... ... ... ... ... ... ",
+"........................................",
+"........................................",
+"........................................",
+"... ... ... ... ... ... ... ... ... ... ",
+"........................................",
+"........................................",
+"........................................",
+"... ... ... ... ... ... ... ... ... ... ",
+"........................................",
+"........................................",
+"........................................",
+"... ... ... ... ... ... ... ... ... ... ",
+"........................................",
+"........................................",
+"........................................",
+"... ... ... ... ... ... ... ... ... ... ",
+"........................................"
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern09.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern09.xpm
new file mode 100644
index 00000000..7d34bc42
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern09.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern09[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+"........................................",
+" ",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+" ",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+" ",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+"........................................",
+" "
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern10.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern10.xpm
new file mode 100644
index 00000000..c908016d
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern10.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern10[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... .",
+".. ..... ..... ..... ..... ..... ..... ."
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern11.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern11.xpm
new file mode 100644
index 00000000..8feda9a4
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern11.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern11[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+" ",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+" ",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+" ",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... ..",
+". ..... ..... ..... ..... ..... ..... .."
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern12.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern12.xpm
new file mode 100644
index 00000000..a57233f2
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern12.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern12[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+"..... ....... ....... ....... ....... ..",
+".... ....... ....... ....... ....... ...",
+"... ....... ....... ....... ....... ....",
+".. ....... ....... ....... ....... .....",
+". ....... ....... ....... ....... ......",
+" ....... ....... ....... ....... .......",
+"....... ....... ....... ....... ....... ",
+"...... ....... ....... ....... ....... .",
+"..... ....... ....... ....... ....... ..",
+".... ....... ....... ....... ....... ...",
+"... ....... ....... ....... ....... ....",
+".. ....... ....... ....... ....... .....",
+". ....... ....... ....... ....... ......",
+" ....... ....... ....... ....... .......",
+"....... ....... ....... ....... ....... ",
+"...... ....... ....... ....... ....... .",
+"..... ....... ....... ....... ....... ..",
+".... ....... ....... ....... ....... ...",
+"... ....... ....... ....... ....... ....",
+".. ....... ....... ....... ....... ....."
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern13.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern13.xpm
new file mode 100644
index 00000000..97f874fe
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern13.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern13[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+" ....... ....... ....... ....... .......",
+". ....... ....... ....... ....... ......",
+".. ....... ....... ....... ....... .....",
+"... ....... ....... ....... ....... ....",
+".... ....... ....... ....... ....... ...",
+"..... ....... ....... ....... ....... ..",
+"...... ....... ....... ....... ....... .",
+"....... ....... ....... ....... ....... ",
+" ....... ....... ....... ....... .......",
+". ....... ....... ....... ....... ......",
+".. ....... ....... ....... ....... .....",
+"... ....... ....... ....... ....... ....",
+".... ....... ....... ....... ....... ...",
+"..... ....... ....... ....... ....... ..",
+"...... ....... ....... ....... ....... .",
+"....... ....... ....... ....... ....... ",
+" ....... ....... ....... ....... .......",
+". ....... ....... ....... ....... ......",
+".. ....... ....... ....... ....... .....",
+"... ....... ....... ....... ....... ...."
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/images/pattern14.xpm b/qtruby/rubylib/examples/qt-examples/chart/images/pattern14.xpm
new file mode 100644
index 00000000..e9e68845
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/images/pattern14.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static const char *pattern14[] = {
+/* columns rows colors chars-per-pixel */
+"40 20 2 1",
+" c black",
+". c white",
+/* pixels */
+"... . ..... . ..... . ..... . ..... . ..",
+".. ... ... ... ... ... ... ... ... ... .",
+". ..... . ..... . ..... . ..... . ..... ",
+" ....... ....... ....... ....... .......",
+". ..... . ..... . ..... . ..... . ..... ",
+".. ... ... ... ... ... ... ... ... ... .",
+"... . ..... . ..... . ..... . ..... . ..",
+".... ....... ....... ....... ....... ...",
+"... . ..... . ..... . ..... . ..... . ..",
+".. ... ... ... ... ... ... ... ... ... .",
+". ..... . ..... . ..... . ..... . ..... ",
+" ....... ....... ....... ....... .......",
+". ..... . ..... . ..... . ..... . ..... ",
+".. ... ... ... ... ... ... ... ... ... .",
+"... . ..... . ..... . ..... . ..... . ..",
+".... ....... ....... ....... ....... ...",
+"... . ..... . ..... . ..... . ..... . ..",
+".. ... ... ... ... ... ... ... ... ... .",
+". ..... . ..... . ..... . ..... . ..... ",
+" ....... ....... ....... ....... ......."
+};
diff --git a/qtruby/rubylib/examples/qt-examples/chart/main.rb b/qtruby/rubylib/examples/qt-examples/chart/main.rb
new file mode 100644
index 00000000..db395a3e
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/main.rb
@@ -0,0 +1,26 @@
+require 'Qt'
+
+require 'canvasview.rb'
+require 'canvastext.rb'
+require 'element.rb'
+require 'chartform.rb'
+require 'chartform_canvas.rb'
+require 'chartform_files.rb'
+require 'optionsform.rb'
+require 'setdataform.rb'
+
+app = Qt::Application.new( ARGV )
+
+if app.ARGV.length > 0
+ filename = app.ARGV[0]
+ if filename.rindex( /.cht$/ ).nil?
+ filename = nil
+ end
+end
+
+cf = ChartForm.new( filename )
+app.mainWidget = cf
+cf.show
+
+app.exec
+
diff --git a/qtruby/rubylib/examples/qt-examples/chart/optionsform.rb b/qtruby/rubylib/examples/qt-examples/chart/optionsform.rb
new file mode 100644
index 00000000..6b2eeac4
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/optionsform.rb
@@ -0,0 +1,127 @@
+class OptionsForm < Qt::Dialog
+ slots 'chooseFont()'
+
+ attr_reader :chartTypeComboBox,
+ :noRadioButton,
+ :yesRadioButton,
+ :asPercentageRadioButton,
+ :decimalPlacesSpinBox,
+ :font
+
+ def initialize( parent = nil, name = "options form",
+ modal = false, f = 0 )
+ super( parent, name, modal, f )
+ setCaption( "Chart -- Options" )
+ resize( 320, 290 )
+
+ @optionsFormLayout = Qt::VBoxLayout.new( self, 11, 6 )
+
+ @chartTypeLayout = Qt::HBoxLayout.new( nil, 0, 6 )
+
+ @chartTypeTextLabel = Qt::Label.new( "&Chart Type", self )
+ @chartTypeLayout.addWidget( @chartTypeTextLabel )
+
+ @chartTypeComboBox = Qt::ComboBox.new( false, self )
+ @chartTypeComboBox.insertItem( Qt::Pixmap.new( "images/options_piechart.xpm" ), "Pie Chart" )
+ @chartTypeComboBox.insertItem( Qt::Pixmap.new( "images/options_verticalbarchart.xpm" ),
+ "Vertical Bar Chart" )
+ @chartTypeComboBox.insertItem( Qt::Pixmap.new( "images/options_horizontalbarchart.xpm" ),
+ "Horizontal Bar Chart" )
+ @chartTypeLayout.addWidget( @chartTypeComboBox )
+ @optionsFormLayout.addLayout( @chartTypeLayout )
+
+ @fontLayout = Qt::HBoxLayout.new( nil, 0, 6 )
+
+ @fontPushButton = Qt::PushButton.new( "&Font...", self )
+ @fontLayout.addWidget( @fontPushButton )
+ @spacer = Qt::SpacerItem.new( 0, 0, Qt::SizePolicy::Expanding,
+ Qt::SizePolicy::Minimum )
+ @fontLayout.addItem( @spacer )
+
+ @fontTextLabel = Qt::Label.new( self ) # Must be set by caller via setFont()
+ @fontLayout.addWidget( @fontTextLabel )
+ @optionsFormLayout.addLayout( @fontLayout )
+
+ @addValuesFrame = Qt::Frame.new( self )
+ @addValuesFrame.setFrameShape( Qt::Frame::StyledPanel )
+ @addValuesFrame.setFrameShadow( Qt::Frame::Sunken )
+ @addValuesFrameLayout = Qt::VBoxLayout.new( @addValuesFrame, 11, 6 )
+
+ @addValuesButtonGroup = Qt::ButtonGroup.new( "Show Values", @addValuesFrame )
+ @addValuesButtonGroup.setColumnLayout(0, Qt::Vertical )
+ @addValuesButtonGroup.layout().setSpacing( 6 )
+ @addValuesButtonGroup.layout().setMargin( 11 )
+ @addValuesButtonGroupLayout = Qt::VBoxLayout.new(
+ @addValuesButtonGroup.layout() )
+ @addValuesButtonGroupLayout.setAlignment( Qt::AlignTop )
+
+ @noRadioButton = Qt::RadioButton.new( "&No", @addValuesButtonGroup )
+ @noRadioButton.setChecked( true )
+ @addValuesButtonGroupLayout.addWidget( @noRadioButton )
+
+ @yesRadioButton = Qt::RadioButton.new( "&Yes", @addValuesButtonGroup )
+ @addValuesButtonGroupLayout.addWidget( @yesRadioButton )
+
+ @asPercentageRadioButton = Qt::RadioButton.new( "As &Percentage",
+ @addValuesButtonGroup )
+ @addValuesButtonGroupLayout.addWidget( @asPercentageRadioButton )
+ @addValuesFrameLayout.addWidget( @addValuesButtonGroup )
+
+ @decimalPlacesLayout = Qt::HBoxLayout.new( nil, 0, 6 )
+
+ @decimalPlacesTextLabel = Qt::Label.new( "&Decimal Places", @addValuesFrame )
+ @decimalPlacesLayout.addWidget( @decimalPlacesTextLabel )
+
+ @decimalPlacesSpinBox = Qt::SpinBox.new( @addValuesFrame )
+ @decimalPlacesSpinBox.setMinValue( 0 )
+ @decimalPlacesSpinBox.setMaxValue( 9 )
+ @decimalPlacesLayout.addWidget( @decimalPlacesSpinBox )
+
+ @addValuesFrameLayout.addLayout( @decimalPlacesLayout )
+
+ @optionsFormLayout.addWidget( @addValuesFrame )
+
+ @buttonsLayout = Qt::HBoxLayout.new( nil, 0, 6 )
+ @spacer = Qt::SpacerItem.new( 0, 0,
+ Qt::SizePolicy::Expanding, Qt::SizePolicy::Minimum )
+ @buttonsLayout.addItem( @spacer )
+
+ @okPushButton = Qt::PushButton.new( "OK", self )
+ @okPushButton.setDefault( true )
+ @buttonsLayout.addWidget( @okPushButton )
+
+ @cancelPushButton = Qt::PushButton.new( "Cancel", self )
+ @buttonsLayout.addWidget( @cancelPushButton )
+ @optionsFormLayout.addLayout( @buttonsLayout )
+
+ connect( @fontPushButton, SIGNAL( 'clicked()' ), self, SLOT( 'chooseFont()' ) )
+ connect( @okPushButton, SIGNAL( 'clicked()' ), self, SLOT( 'accept()' ) )
+ connect( @cancelPushButton, SIGNAL( 'clicked()' ), self, SLOT( 'reject()' ) )
+
+ @chartTypeTextLabel.setBuddy( @chartTypeComboBox )
+ @decimalPlacesTextLabel.setBuddy( @decimalPlacesSpinBox )
+ end
+
+
+ def chooseFont()
+ ok = Qt::Boolean.new
+ font = Qt::FontDialog.getFont( ok, @font, self )
+ if !ok.nil?
+ setFont( font )
+ end
+ end
+
+
+ def font=( font )
+ label = font.family() + " " + font.pointSize().to_s + "pt"
+ if font.bold()
+ label += " Bold"
+ end
+ if font.italic()
+ label += " Italic"
+ end
+ @fontTextLabel.setText( label )
+ @font = font
+ end
+
+end
diff --git a/qtruby/rubylib/examples/qt-examples/chart/setdataform.rb b/qtruby/rubylib/examples/qt-examples/chart/setdataform.rb
new file mode 100644
index 00000000..81a9403b
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/chart/setdataform.rb
@@ -0,0 +1,184 @@
+class SetDataForm < Qt::Dialog
+
+ slots 'setColor()',
+ 'setChosenColor( int, int )',
+ 'currentChanged( int, int )',
+ 'valueChanged( int, int )',
+ 'accept()'
+
+ MAX_PATTERNS = 14
+
+
+ def initialize( elements, decimalPlaces,
+ parent = nil, name = "set data form",
+ modal = true, f = 0 )
+ super( parent, name, modal, f )
+
+ @elements = elements
+ @decimalPlaces = decimalPlaces
+
+ setCaption( "Chart -- Set Data" )
+ resize( 540, 440 )
+
+ @tableButtonBox = Qt::VBoxLayout.new( self, 11, 6, "@table button box layout" )
+
+ @table = Qt::Table.new( self, "data @table" )
+ @table.setNumCols( 5 )
+ @table.setNumRows( ChartForm::MAX_ELEMENTS )
+ @table.setColumnReadOnly( 1, true )
+ @table.setColumnReadOnly( 2, true )
+ @table.setColumnReadOnly( 4, true )
+ @table.setColumnWidth( 0, 80 )
+ @table.setColumnWidth( 1, 60 ) # Columns 1 and 4 must be equal
+ @table.setColumnWidth( 2, 60 )
+ @table.setColumnWidth( 3, 200 )
+ @table.setColumnWidth( 4, 60 )
+ th = @table.horizontalHeader()
+ th.setLabel( 0, "Value" )
+ th.setLabel( 1, "Color" )
+ th.setLabel( 2, "Pattern" )
+ th.setLabel( 3, "Label" )
+ th.setLabel( 4, "Color" )
+ @tableButtonBox.addWidget( @table )
+
+ @buttonBox = Qt::HBoxLayout.new( nil, 0, 6, "button box layout" )
+
+ @colorPushButton = Qt::PushButton.new( self, "color button" )
+ @colorPushButton.setText( "&Color..." )
+ @colorPushButton .setEnabled( false )
+ @buttonBox.addWidget( @colorPushButton )
+
+ spacer = Qt::SpacerItem.new( 0, 0, Qt::SizePolicy::Expanding,
+ Qt::SizePolicy::Minimum )
+ @buttonBox.addItem( spacer )
+
+ okPushButton = Qt::PushButton.new( self, "ok button" )
+ okPushButton.setText( "OK" )
+ okPushButton.setDefault( true )
+ @buttonBox.addWidget( okPushButton )
+
+ cancelPushButton = Qt::PushButton.new( self, "cancel button" )
+ cancelPushButton.setText( "Cancel" )
+ cancelPushButton.setAccel( Qt::KeySequence.new(Key_Escape) )
+ @buttonBox.addWidget( cancelPushButton )
+
+ @tableButtonBox.addLayout( @buttonBox )
+
+ connect( @table, SIGNAL( 'clicked(int,int,int,const QPoint&)' ),
+ self, SLOT( 'setChosenColor(int,int)' ) )
+ connect( @table, SIGNAL( 'currentChanged(int,int)' ),
+ self, SLOT( 'currentChanged(int,int)' ) )
+ connect( @table, SIGNAL( 'valueChanged(int,int)' ),
+ self, SLOT( 'valueChanged(int,int)' ) )
+ connect( @colorPushButton, SIGNAL( 'clicked()' ), self, SLOT( 'setColor()' ) )
+ connect( okPushButton, SIGNAL( 'clicked()' ), self, SLOT( 'accept()' ) )
+ connect( cancelPushButton, SIGNAL( 'clicked()' ), self, SLOT( 'reject()' ) )
+
+ patterns = Array.new(MAX_PATTERNS)
+ patterns[0] = Qt::Pixmap.new( "images/pattern01.xpm" )
+ patterns[1] = Qt::Pixmap.new( "images/pattern02.xpm" )
+ patterns[2] = Qt::Pixmap.new( "images/pattern03.xpm" )
+ patterns[3] = Qt::Pixmap.new( "images/pattern04.xpm" )
+ patterns[4] = Qt::Pixmap.new( "images/pattern05.xpm" )
+ patterns[5] = Qt::Pixmap.new( "images/pattern06.xpm" )
+ patterns[6] = Qt::Pixmap.new( "images/pattern07.xpm" )
+ patterns[7] = Qt::Pixmap.new( "images/pattern08.xpm" )
+ patterns[8] = Qt::Pixmap.new( "images/pattern09.xpm" )
+ patterns[9] = Qt::Pixmap.new( "images/pattern10.xpm" )
+ patterns[10] = Qt::Pixmap.new( "images/pattern11.xpm" )
+ patterns[11] = Qt::Pixmap.new( "images/pattern12.xpm" )
+ patterns[12] = Qt::Pixmap.new( "images/pattern13.xpm" )
+ patterns[13] = Qt::Pixmap.new( "images/pattern14.xpm" )
+
+ rect = @table.cellRect( 0, 1 )
+ pix = Qt::Pixmap.new( rect.width(), rect.height() )
+
+ for i in 0...ChartForm::MAX_ELEMENTS
+ element = @elements[i]
+
+ if element.isValid()
+ @table.setText(i, 0, "%.#{@decimalPlaces}f" % element.value() )
+ end
+
+ color = element.valueColor()
+ pix.fill( color )
+ @table.setPixmap( i, 1, pix )
+ @table.setText( i, 1, color.name() )
+
+ combobox = Qt::ComboBox.new
+ for j in 0...MAX_PATTERNS
+ combobox.insertItem( patterns[j] )
+ end
+ combobox.setCurrentItem( element.valuePattern() - 1 )
+ @table.setCellWidget( i, 2, combobox )
+
+ @table.setText( i, 3, element.label() )
+
+ color = element.labelColor()
+ pix.fill( color )
+ @table.setPixmap( i, 4, pix )
+ @table.setText( i, 4, color.name() )
+ end
+
+ end
+
+
+ def currentChanged( i, col )
+ @colorPushButton.setEnabled( col == 1 || col == 4 )
+ end
+
+
+ def valueChanged( row, col )
+ if col == 0
+ d = @table.text( row, col ).to_f
+ if d && d > EPSILON
+ @table.setText( row, col, "%.#{@decimalPlaces}f" % d )
+ elsif ! @table.text( row, col ).empty?
+ @table.setText( row, col, @table.text( row, col ) + "?" )
+ end
+ end
+ end
+
+
+ def setColor()
+ setChosenColor( @table.currentRow(), @table.currentColumn() )
+ @table.setFocus()
+ end
+
+
+ def setChosenColor( row, col )
+ if !( col == 1 || col == 4 )
+ return
+ end
+
+ color = Qt::ColorDialog.getColor(
+ Qt::Color.new( @table.text( row, col ) ),
+ self, "color dialog" )
+ if color.isValid()
+ pix = @table.pixmap( row, col )
+ pix.fill( color )
+ @table.setPixmap( row, col, pix )
+ @table.setText( row, col, color.name() )
+ end
+ end
+
+
+ def accept()
+ for i in 0...ChartForm::MAX_ELEMENTS
+ element = @elements[i]
+ d = @table.text( i, 0 ).to_f
+ if d
+ element.value = d
+ else
+ element.value = Element::INVALID
+ end
+ element.valueColor = Qt::Color.new( @table.text( i, 1 ) )
+ element.valuePattern = (@table.cellWidget( i, 2 )).currentItem() + 1
+ element.label = @table.text( i, 3 )
+ element.labelColor = Qt::Color.new( @table.text( i, 4 ) )
+ end
+
+ super
+ end
+
+end
diff --git a/qtruby/rubylib/examples/qt-examples/checklists/checklists.rb b/qtruby/rubylib/examples/qt-examples/checklists/checklists.rb
new file mode 100644
index 00000000..8f67d9aa
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/checklists/checklists.rb
@@ -0,0 +1,147 @@
+require 'Qt'
+
+class CheckLists < Qt::Widget
+ slots 'copy1to2()', 'copy2to3()'
+
+ # Constructor
+ #
+ # Create all child widgets of the CheckList Widget
+ def initialize
+ super()
+
+ lay = Qt::HBoxLayout.new(self)
+ lay.setMargin(5)
+
+ # create a widget which layouts its childs in a column
+ vbox1 = Qt::VBoxLayout.new(lay)
+ vbox1.setMargin(5)
+
+ # First child: a Label
+ vbox1.addWidget(Qt::Label.new('Check some items!', self))
+
+ # Second child: the ListView
+ @lv1 = Qt::ListView.new(self)
+ vbox1.addWidget(@lv1)
+ @lv1.addColumn('Items')
+ @lv1.setRootIsDecorated(true)
+
+ # create a list with 4 ListViewItems which will be parent items of other ListViewItems
+ parentList = Array.new
+
+
+ parentList.push(Qt::ListViewItem.new(@lv1, 'Parent Item 1'))
+ parentList.push(Qt::ListViewItem.new(@lv1, 'Parent Item 2'))
+ parentList.push(Qt::ListViewItem.new(@lv1, 'Parent Item 3'))
+ parentList.push(Qt::ListViewItem.new(@lv1, 'Parent Item 4'))
+
+ item = 0
+ num = 1
+ # go through the list of parent items...
+ parentList.each {|item|
+ item.setOpen(true)
+ # ...and create 5 checkable child ListViewItems for each parent item
+ for i in 1..5
+ str = sprintf('%s. Child of Parent %s', i, num)
+ Qt::CheckListItem.new(item, str, Qt::CheckListItem.CheckBox)
+ end
+ num = num + 1
+ }
+
+ # Create another widget for layouting
+ tmp = Qt::VBoxLayout.new(lay)
+ tmp.setMargin(5)
+
+ # create a pushbutton
+ copy1 = Qt::PushButton.new(' -> ', self)
+ tmp.addWidget(copy1)
+ copy1.setMaximumWidth(copy1.sizeHint.width)
+ # connect the SIGNAL clicked() of the pushbutton with the SLOT copy1to2()
+ connect(copy1, SIGNAL('clicked()'), self, SLOT('copy1to2()'))
+
+ # another widget for layouting
+ vbox2 = Qt::VBoxLayout.new(lay)
+ vbox2.setMargin(5)
+
+ # and another label
+ vbox2.addWidget(Qt::Label.new('Check one item!', self))
+
+ # create the second listview
+ @lv2 = Qt::ListView.new(self)
+ vbox2.addWidget(@lv2)
+ @lv2.addColumn('Items')
+ @lv2.setRootIsDecorated(true)
+
+ # another widget needed for layouting only
+ tmp = Qt::VBoxLayout.new(lay)
+ tmp.setMargin(5)
+
+ # create another pushbutton...
+ copy2 = Qt::PushButton.new(' -> ', self)
+ lay.addWidget( copy2 )
+ copy2.setMaximumWidth(copy2.sizeHint.width)
+ # ...and connect its clicked() SIGNAL to the copy2to3() SLOT
+ connect(copy2, SIGNAL('clicked()'), self, SLOT('copy2to3()'))
+
+ tmp = Qt::VBoxLayout.new(lay)
+ tmp.setMargin(5)
+
+ # and create a label which will be at the right of the window
+ @label = Qt::Label.new('No Item yet...', self)
+ tmp.addWidget(@label)
+ end
+
+ # SLOT copy1to2()
+ #
+ # Copies all checked ListViewItems from the first ListView to
+ # the second one, and inserts them as Radio-ListViewItem.
+ def copy1to2
+ @lv2.clear
+ it = Qt::ListViewItemIterator.new(@lv1)
+ # Insert first a controller Item into the second ListView. Always if Radio-ListViewItems
+ # are inserted into a Listview, the parent item of these MUST be a controller Item!
+ item = Qt::CheckListItem.new(@lv2, 'Controller', Qt::CheckListItem::Controller );
+ item.setOpen(true);
+
+ # iterate through the first ListView...
+ while (it.current)
+ # ...check state of childs, and...
+ if ( it.current.parent )
+ # ...if the item is checked...
+ if (it.current.isOn)
+ # ...insert a Radio-ListViewItem with the same text into the second ListView
+ Qt::CheckListItem.new(item, it.current.text(0), Qt::CheckListItem::RadioButton)
+ end
+ end
+ it += 1
+ end
+
+ if (item.firstChild)
+ item.firstChild.setOn(true)
+ end
+ end
+
+
+ # SLOT copy2to3()
+ #
+ # Copies the checked item of the second ListView into the
+ # Label at the right.
+ def copy2to3
+ # create an iterator which operates on the second ListView
+ it = Qt::ListViewItemIterator.new(@lv2)
+
+ @label.setText('No Item checked')
+
+ # iterate through the second ListView...
+ while (it.current)
+ # ...check state of childs, and...
+ if ( it.current.parent)
+ # ...if the item is checked...
+ if (it.current.isOn)
+ # ...set the text of the item to the label
+ @label.setText(it.current.text(0))
+ end
+ end
+ it += 1
+ end
+ end
+end
diff --git a/qtruby/rubylib/examples/qt-examples/checklists/main.rb b/qtruby/rubylib/examples/qt-examples/checklists/main.rb
new file mode 100755
index 00000000..0c0e755c
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/checklists/main.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+
+require 'checklists'
+
+a = Qt::Application.new(ARGV)
+
+checklists = CheckLists.new
+checklists.resize(650, 350)
+checklists.setCaption('QtRuby Example - CheckLists')
+a.setMainWidget(checklists)
+checklists.show
+
+a.exec()
diff --git a/qtruby/rubylib/examples/qt-examples/dclock/dclock.rb b/qtruby/rubylib/examples/qt-examples/dclock/dclock.rb
new file mode 100644
index 00000000..6ac52c4c
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/dclock/dclock.rb
@@ -0,0 +1,67 @@
+require 'Qt'
+
+class DigitalClock < Qt::LCDNumber
+
+ slots 'stopDate()', 'showTime()'
+
+ # Constructs a DigitalClock widget
+ def initialize
+ super
+
+ @showingColon = false
+ setFrameStyle(Qt::Frame.Panel | Qt::Frame.Raised)
+ setLineWidth(2) # set frame line width
+ showTime # display the current time
+ @normalTimer = startTimer(500) # 1/2 second timer events
+ @showDateTimer = -1 # not showingdate
+ end
+
+ # Handles timer events for the digital clock widget.
+ # There are two different timers; one timer for updating the clock
+ # and another one for switching back from date mode to time mode.
+ def timerEvent (e)
+ if (e.timerId == @showDateTimer) # stop showing date
+ stopDate
+ else # normal timer
+ if (@showDateTimer == -1) # not showing date
+ showTime()
+ end
+ end
+ end
+
+ # Enters date mode when the left mouse button is pressed.
+ def mousePressEvent (e)
+ if (e.button == Qt::MouseEvent.LeftButton) # left button pressed
+ showDate
+ end
+ end
+
+ def stopDate
+ killTimer(@showDateTimer)
+ @showDateTimer = -1
+ showTime
+ end
+
+ def showTime
+ @showingColon = !@showingColon # toggle/blink colon
+ s = Qt::Time.currentTime.toString[0..4]
+ if (!@showingColon)
+ s[2] = ' '
+ end
+ if (s[0] == '0')
+ s[0] = ' '
+ end
+ display(s) # set LCD number/text
+ end
+
+ def showDate
+ if (@showDateTimer != -1) # already showing date
+ return
+ end
+ date = Qt::Date.currentDate
+ s = sprintf('%2d %2d', date.month, date.day)
+ display(s) # sets the LCD number/text
+ @showDateTimer = startTimer(2000) # keep this state for 2 secs
+ end
+
+end
diff --git a/qtruby/rubylib/examples/qt-examples/dclock/main.rb b/qtruby/rubylib/examples/qt-examples/dclock/main.rb
new file mode 100755
index 00000000..c76ae55d
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/dclock/main.rb
@@ -0,0 +1,12 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+require 'dclock'
+
+a = Qt::Application.new(ARGV)
+clock = DigitalClock.new
+clock.resize(170,80)
+a.setMainWidget(clock)
+clock.setCaption('QtRuby Example - Digital Clock')
+clock.show
+a.exec
diff --git a/qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/main.rb b/qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/main.rb
new file mode 100755
index 00000000..9559a921
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/main.rb
@@ -0,0 +1,14 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+require 'viewer'
+$KCODE='u'
+
+
+a = Qt::Application.new(ARGV)
+
+textViewer = Viewer.new
+textViewer.setCaption('QtRuby Example - Simple QFont Demo')
+a.setMainWidget(textViewer)
+textViewer.show
+a.exec()
diff --git a/qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/viewer.rb b/qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/viewer.rb
new file mode 100644
index 00000000..d9c16a62
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/fonts/simple-qfont-demo/viewer.rb
@@ -0,0 +1,140 @@
+class Viewer < Qt::Widget
+ slots 'setDefault()', 'setSansSerif()', 'setItalics()'
+
+ def initialize
+ super
+
+ setFontSubstitutions
+
+ codec = Qt::TextCodec::codecForName("utf8")
+
+ # Shouldn't 'pack("U*")' for UTF-8 work here? - Richard
+ # The 'U' option packs each element into two bytes and doesn't work
+ # The 'c' option packs them into a single byte and does work
+ greeting_heb = codec.toUnicode([0327, 0251, 0327, 0234, 0327, 0225, 0327, 0235].pack("C*"))
+ greeting_ru = codec.toUnicode([0320, 0227, 0320, 0264, 0321, 0200, 0320, 0260, 0320, 0262, 0321, 0201, 0321, 0202, 0320, 0262, 0321, 0203, 0320, 0271, 0321, 0202, 0320, 0265].pack("C*"))
+ greeting_en = 'Hello'
+
+ @greetings = Qt::TextView.new(self, 'textview')
+ @greetings.setText(
+ greeting_en + "\n" +
+ greeting_ru + "\n" +
+ greeting_heb)
+
+ @fontInfo = Qt::TextView.new(self, 'fontinfo')
+
+ setDefault
+
+ @defaultButton = Qt::PushButton.new('Default', self, 'pushbutton1')
+ @defaultButton.setFont(Qt::Font.new('times'))
+ connect(@defaultButton, SIGNAL('clicked()'), self, SLOT('setDefault()'))
+
+
+ @sansSerifButton = Qt::PushButton.new('Sans Serif', self, 'pushbutton2')
+ @sansSerifButton.setFont(Qt::Font.new('Helvetica', 12))
+ connect(@sansSerifButton, SIGNAL('clicked()'), self, SLOT('setSansSerif()'))
+
+ @italicsButton = Qt::PushButton.new('Italics', self, 'pushbutton1')
+ @italicsButton.setFont(Qt::Font.new('lucida', 12, Qt::Font.Bold, true))
+ connect(@italicsButton, SIGNAL('clicked()'), self, SLOT('setItalics()'))
+
+ layout
+ end
+
+ def setDefault
+ font = Qt::Font.new('Bavaria')
+ font.setPointSize(24)
+ font.setWeight(Qt::Font.Bold)
+ font.setUnderline(true)
+
+ @greetings.setFont(font)
+ showFontInfo(font)
+ end
+
+ def setSansSerif
+ font = Qt::Font.new('Newyork', 18)
+ font.setStyleHint(Qt::Font.SansSerif)
+
+ @greetings.setFont(font)
+ showFontInfo(font)
+ end
+
+ def setItalics
+ font = Qt::Font.new('Tokyo')
+ font.setPointSize(32)
+ font.setWeight(Qt::Font.Bold)
+ font.setItalic(true)
+
+ @greetings.setFont(font)
+ showFontInfo(font)
+ end
+
+ def setFontSubstitutions
+ substitutes = Array.new
+
+ substitutes.push('Times')
+ substitutes.push('Mincho')
+ substitutes.push('Arabic Newspaper')
+ substitutes.push('crox')
+
+ Qt::Font.insertSubstitutions('Bavaria', substitutes)
+ Qt::Font.insertSubstitution('Tokyo', 'Lucida')
+ end
+
+ def layout
+ textViewContainer = Qt::HBoxLayout.new
+ textViewContainer.addWidget(@greetings)
+ textViewContainer.addWidget(@fontInfo)
+
+ buttonContainer = Qt::HBoxLayout.new
+ buttonContainer.addWidget(@defaultButton)
+ buttonContainer.addWidget(@sansSerifButton)
+ buttonContainer.addWidget(@italicsButton)
+
+ maxButtonHeight = @defaultButton.height
+
+ if (@sansSerifButton.height > maxButtonHeight)
+ maxButtonHeight = @sansSerifButton.height
+ end
+
+ if (@italicsButton.height > maxButtonHeight)
+ maxButtonHeight = @italicsButton.height
+ end
+
+ @defaultButton.setFixedHeight(maxButtonHeight)
+ @sansSerifButton.setFixedHeight(maxButtonHeight)
+ @italicsButton.setFixedHeight(maxButtonHeight)
+
+ container = Qt::VBoxLayout.new(self)
+ container.addLayout(textViewContainer)
+ container.addLayout(buttonContainer)
+
+ resize(700, 250)
+ end
+
+ def showFontInfo (font)
+ info = Qt::FontInfo.new(font)
+ messageText =
+ 'Font requested: "' +
+ font.family + '" ' +
+ font.pointSize.to_s + 'pt<BR>' +
+ 'Font used: "' +
+ info.family.to_s + '" ' +
+ info.pointSize.to_s + 'pt<P>'
+
+ substitutions = Qt::Font.substitutes(font.family)
+
+ unless substitutions.size == 0
+ messageText = messageText + 'The following substitutions exist for ' +
+ font.family + ':<UL>'
+ substitutions.each {|x|
+ messageText = messageText + '<LI>"' + x + '"'
+ }
+ messageText = messageText + '</UL>'
+ else
+ messageText = messageText + 'No substitutions exist for ' + font.family + '.'
+ end
+
+ @fontInfo.setText(messageText)
+ end
+end
diff --git a/qtruby/rubylib/examples/qt-examples/forever/forever.rb b/qtruby/rubylib/examples/qt-examples/forever/forever.rb
new file mode 100755
index 00000000..46849784
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/forever/forever.rb
@@ -0,0 +1,84 @@
+#!/usr/bin/env ruby -w
+
+require 'Qt'
+
+#
+# Forever - a widget that draws rectangles forever.
+#
+
+class Forever < Qt::Widget
+
+ NUM_COLORS = 120
+ #
+ # Constructs a Forever widget.
+ #
+
+ slots 'updateCaption()'
+
+ def initialize(*k)
+ super(nil)
+ @colors = []
+ 0.upto(NUM_COLORS-1) do |a|
+ @colors[a] = Qt::Color.new( rand(255),
+ rand(255),
+ rand(255) )
+ end
+ @rectangles = 0
+ startTimer( 0 ) # run continuous timer
+ counter = Qt::Timer.new( self )
+ connect( counter, SIGNAL("timeout()"),
+ self, SLOT("updateCaption()") )
+ counter.start( 1000 )
+ end
+
+
+ def updateCaption()
+ s = "Qt Example - Forever - " + @rectangles.to_s + " rectangles/second"
+ @rectangles = 0
+ self.caption = s
+ end
+
+
+ #
+ # Handles paint events for the Forever widget.
+ #
+
+ def paintEvent( e )
+ paint = Qt::Painter.new( self ) # painter object
+ w = width()
+ h = height()
+ if w <= 0 || h <= 0 then
+ return
+ end
+ paint.setPen( NoPen ) # do not draw outline
+ paint.setBrush( @colors[rand(NUM_COLORS)]) # set random brush color
+
+ p1 = Qt::Point.new( rand(w), rand(h)) # p1 = top left
+ p2 = Qt::Point.new( rand(w), rand(h)) # p2 = bottom right
+
+ r = Qt::Rect.new( p1, p2 )
+ paint.drawRect( r ) # draw filled rectangle
+ paint.end()
+ end
+
+ #
+ # Handles timer events for the Forever widget.
+ #
+
+ def timerEvent( e )
+ 0.upto(99) do |i|
+ repaint( false ) # repaint, don't erase
+ end
+ @rectangles += 100
+ end
+
+
+end
+
+a = Qt::Application.new(ARGV)
+always = Forever.new
+always.resize( 400, 250 ) # start up with size 400x250
+a.mainWidget = always # set as main widget
+always.caption = "QtRuby Example - Forever"
+always.show
+a.exec
diff --git a/qtruby/rubylib/examples/qt-examples/hello/hello.rb b/qtruby/rubylib/examples/qt-examples/hello/hello.rb
new file mode 100644
index 00000000..ce957c75
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/hello/hello.rb
@@ -0,0 +1,78 @@
+require 'Qt'
+
+class Hello < Qt::Widget
+
+ signals 'clicked()'
+ slots 'animate()'
+
+ # Constructs a Hello widget. Starts a 40 ms animation timer
+ def initialize (text)
+ super()
+
+ @b = 0
+ @text = text
+ @sin_tbl = [0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38]
+ timer = Qt::Timer.new(self);
+ connect(timer, SIGNAL('timeout()'), SLOT('animate()'))
+ timer.start(40);
+
+ resize(260, 130)
+ end
+
+ # This slot is called each time the timer fires.
+ def animate
+ @b = (@b + 1) & 15
+ repaint(false)
+ end
+
+ # Handles mouse button release events for the Hello widget.
+ #
+ # We emit the clicked() signal when the mouse is released inside
+ # the widget.
+ def mouseReleaseEvent(e)
+ if (rect.contains(e.pos))
+ emit clicked
+ end
+ end
+
+ # Handles paint events for the Hello widget.
+ #
+ # Flicker-free update. The text is first drawn in the pixmap and the
+ # pixmap is then blt'ed to the screen.
+ def paintEvent(e)
+ if @text.empty?
+ return
+ end
+
+ # 1: Compute some sizes, positions etc.
+ fm = fontMetrics
+
+ w = fm.width(@text) + 20
+ h = fm.height * 2
+ pmx = width/2 - w/2
+ pmy = height/2 - h/2
+
+ # 2: Create the pixmap and fill it with the widget's background
+ pm = Qt::Pixmap.new(w, h)
+ pm.fill(self, pmx, pmy)
+
+ # 3: Paint the pixmap. Cool wave effect
+ p = Qt::Painter.new;
+ x = 10
+ y = h/2 + fm.descent
+ i = 0
+ p.begin(pm)
+ p.setFont(font)
+
+ for i in 0..@text.size-1
+ j = (@b+i) & 15
+ p.setPen(Qt::Color.new((15-j)*16,255,255,Qt::Color.Hsv) )
+ p.drawText( x, y-@sin_tbl[j]*h/800, @text[i,1], 1 )
+ x += fm.width(@text[i,1])
+ end
+ p.end
+
+ #4: Copy the pixmap to the Hello widget
+ bitBlt(self, pmx, pmy, pm)
+ end
+end
diff --git a/qtruby/rubylib/examples/qt-examples/hello/main.rb b/qtruby/rubylib/examples/qt-examples/hello/main.rb
new file mode 100755
index 00000000..a6d3447f
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/hello/main.rb
@@ -0,0 +1,23 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+require 'hello'
+
+a = Qt::Application.new(ARGV)
+s = ''
+
+s = ARGV[0..ARGV.size-1].join(' ') if ARGV.length
+
+if (s.empty?)
+ s = 'Hello, World'
+end
+
+h = Hello.new(s)
+h.setCaption('QtRuby says hello')
+h.connect(h, SIGNAL('clicked()'), a, SLOT('quit()'))
+h.setFont(Qt::Font.new('times', 32, Qt::Font.Bold)) # default font
+h.setBackgroundColor(Qt::white) # default bg color
+a.setMainWidget(h)
+h.show
+
+a.exec
diff --git a/qtruby/rubylib/examples/qt-examples/progress/progress.rb b/qtruby/rubylib/examples/qt-examples/progress/progress.rb
new file mode 100644
index 00000000..02116958
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/progress/progress.rb
@@ -0,0 +1,275 @@
+#!/usr/bin/env ruby -w
+
+require 'Qt'
+
+class AnimatedThingy < Qt::Label
+ attr_accessor :label, :step
+ attr_accessor :ox0, :oy0, :ox1, :oy1
+ attr_accessor :x0, :y0, :x1, :y1
+ attr_accessor :dx0, :dx1, :dy0, :dy1
+ NQIX = 10
+
+ def initialize(*k)
+ super(*k)
+ @label = k[1] + "\n... and wasting CPU\nwith this animation!\n"
+ @step = 0
+ @ox0, @oy0, @ox1, @oy1 = *Array.new(4) { Array.new(10, 0) }
+ @x0 = @y0 = @x1 = @y1 = 0
+ @dx0 = rand(8)+2
+ @dy0 = rand(8)+2
+ @dx1 = rand(8)+2
+ @dy1 = rand(8)+2
+ end
+
+ def show
+ startTimer(100) unless isVisible
+ super
+ end
+
+ def hide
+ super
+ killTimers()
+ end
+
+ def sizeHint
+ Qt::Size.new(120,100)
+ end
+
+ def inc(x, dx, b)
+ x += dx
+ if x < 0
+ x = 0
+ dx = rand(8) + 2
+ elsif x >= b
+ x = b-1
+ dx = -(rand(8)+2)
+ end
+ yield x, dx
+ end
+
+ def timerEvent(e)
+ p = Qt::Painter.new(self)
+ pn = p.pen
+ pn.setWidth(2)
+ pn.setColor(backgroundColor)
+ p.setPen(pn)
+
+ @step = (@step + 1) % NQIX
+
+ p.drawLine(@ox0[@step], @oy0[@step], @ox1[@step], @oy1[@step])
+
+ inc(@x0, @dx0, width) { |x,dx| @x0, @dx0 = x, dx }
+ inc(@y0, @dy0, height) { |y,dy| @y0, @dy0 = y, dy }
+ inc(@x1, @dx1, width) { |x,dx| @x1, @dx1 = x, dx }
+ inc(@y1, @dy1, height) { |y,dy| @y1, @dy1 = y, dy }
+ @ox0[@step] = @x0
+ @oy0[@step] = @y0
+ @ox1[@step] = @x1
+ @oy1[@step] = @y1
+
+ c = Qt::Color.new
+ c.setHsv( (@step*255)/NQIX, 255, 255 ) # rainbow effect
+ pn.setColor(c)
+ pn.setWidth(2)
+ p.setPen(pn)
+ p.drawLine(@ox0[@step], @oy0[@step], @ox1[@step], @oy1[@step])
+ p.setPen(colorGroup().text())
+ p.drawText(rect(), AlignCenter, @label)
+ p.end()
+ end
+
+ def paintEvent(event)
+ p = Qt::Painter.new(self)
+ pn = p.pen()
+ pn.setWidth(2)
+ p.setPen(pn)
+ p.setClipRect(event.rect())
+ 0.upto(NQIX-1) do |i|
+ c = Qt::Color.new()
+ c.setHsv( (i*255)/NQIX, 255, 255 ) # rainbow effect
+ pn.setColor(c)
+ p.setPen(pn)
+ p.drawLine(@ox0[i], @oy0[i], @ox1[i], @oy1[i])
+ end
+ p.setPen(colorGroup().text())
+ p.drawText(rect(), AlignCenter, @label)
+ p.end
+ end
+end
+
+class CPUWaster < Qt::Widget
+ attr_accessor :menubar, :file, :options, :rects, :pb
+ attr_accessor :td_id , :ld_id, :dl_id, :cl_id, :md_id
+ attr_accessor :got_stop, :timer_driven, :default_label
+ slots 'drawItemRects(int)', 'doMenuItem(int)', 'stopDrawing()', 'timerDriven()'
+ slots 'loopDriven()', 'defaultLabel()', 'customLabel()', 'toggleMinimumDuration()'
+
+ FIRST_DRAW_ITEM = 1000
+ LAST_DRAW_ITEM = 1006
+
+ def initialize(*k)
+ super(*k)
+
+ @menubar = Qt::MenuBar.new(self, "menu")
+ @pb = nil
+
+ @file = Qt::PopupMenu.new
+ @menubar.insertItem( "&File", file )
+ FIRST_DRAW_ITEM.upto(LAST_DRAW_ITEM) {
+ |i| file.insertItem( "#{drawItemRects(i)} Rectangles", i)
+ }
+ connect( menubar, SIGNAL('activated(int)'), self, SLOT('doMenuItem(int)') )
+ @file.insertSeparator
+ @file.insertItem("Quit", $qApp, SLOT('quit()'))
+ @options = Qt::PopupMenu.new
+ @menubar.insertItem("&Options", options)
+ @td_id = options.insertItem("Timer driven", self, SLOT('timerDriven()'))
+ @ld_id = options.insertItem("Loop driven", self, SLOT('loopDriven()'))
+ @options.insertSeparator
+ @dl_id = options.insertItem("Default label", self, SLOT('defaultLabel()'))
+ @cl_id = options.insertItem("Custom label", self, SLOT('customLabel()'))
+ @options.insertSeparator
+ @md_id = options.insertItem("No minimum duration", self, SLOT('toggleMinimumDuration()'))
+ @options.setCheckable true
+
+ loopDriven
+ defaultLabel
+
+ setFixedSize(400, 300)
+ setBackgroundColor(black)
+ end
+
+ def drawItemRects(id)
+ n = id - FIRST_DRAW_ITEM - 1
+ r = 100
+ n.downto(0) { |n|
+ r *= (n%3 != 0) ? 5 : 4
+ }
+ r
+ end
+
+ def doMenuItem(id)
+ draw drawItemRects(id) if id >= FIRST_DRAW_ITEM && id <= LAST_DRAW_ITEM
+ end
+
+ def stopDrawing
+ @got_stop = true
+ end
+
+ def timerDriven
+ @timer_driven = true
+ @options.setItemChecked(@td_id, true)
+ @options.setItemChecked(@ld_id, false)
+ end
+
+ def loopDriven
+ @timer_driven = false
+ @options.setItemChecked(@td_id, false)
+ @options.setItemChecked(@ld_id, true)
+ end
+
+ def defaultLabel
+ @default_label = true
+ @options.setItemChecked(@dl_id, true)
+ @options.setItemChecked(@cl_id, false)
+ end
+
+ def customLabel
+ @default_label = false
+ @options.setItemChecked(@dl_id, false)
+ @options.setItemChecked(@cl_id, true)
+ end
+
+ def toggleMinimumDuration
+ checked = @options.isItemChecked(@md_id)
+ @options.setItemChecked(@md_id, !checked)
+ end
+
+ def timerEvent(e)
+ @pb.setProgress( @pb.totalSteps - @rects ) if @rects % 100 == 0
+ @rects -= 1
+
+ painter = Qt::Painter.new(self)
+
+ ww = width
+ wh = height
+
+ if ww > 8 and wh > 8
+ c = Qt::Color.new(rand(255), rand(255), rand(255))
+ x = rand(ww - 8)
+ y = rand(wh - 8)
+ w = rand(ww - x)
+ h = rand(wh - y)
+ painter.fillRect(x, y, w, h, Qt::Brush.new(c))
+ end
+
+ painter.end()
+
+ if @rects == 0 || @got_stop
+ @pb.setProgress(@pb.totalSteps)
+ painter = Qt::Painter.new(self)
+ painter.fillRect(0, 0, width(), height(), Qt::Brush.new(backgroundColor))
+ painter.end()
+ enableDrawingItems(true)
+ killTimers()
+ @pb = nil
+ end
+ end
+
+ def newProgressDialog(label, steps, modal)
+ d = Qt::ProgressDialog.new(label, "Cancel", steps, self, "progress", modal)
+ d.setMinimumDuration(0) if @options.isItemChecked(@md_id)
+ d.setLabel( AnimatedThingy.new(d, label) ) unless @default_label
+ d.show
+ d
+ end
+
+ def enableDrawingItems(yes)
+ FIRST_DRAW_ITEM.upto(LAST_DRAW_ITEM) {
+ |i| menubar.setItemEnabled(i, yes)
+ }
+ end
+
+ def draw(n)
+ if timer_driven
+ unless @pb.nil?
+ warn("This cannot happen!")
+ return
+ end
+ @rects = n
+ @pb = newProgressDialog("Drawing rectangles.\nUsing timer event.", n, false)
+ @pb.setCaption("Please Wait")
+ connect(@pb, SIGNAL('cancelled()'), self, SLOT('stopDrawing()'))
+ enableDrawingItems(false)
+ startTimer(0)
+ @got_stop = false
+ else
+ lpb = newProgressDialog("Drawing rectangles.\nUsing loop.", n, true)
+ lpb.setCaption("Please Wait")
+
+ painter = Qt::Painter.new(self)
+ 0.upto(n) { |i|
+ if (i % 100) == 0
+ lpb.setProgress(i)
+ break if lpb.wasCancelled
+ end
+ cw, ch = width, height
+ c = Qt::Color.new(rand(255), rand(255), rand(255))
+ x = rand(cw - 8)
+ y = rand(cw - 8)
+ w = rand(cw - x)
+ h = rand(cw - y)
+ painter.fillRect(x, y, w, h, Qt::Brush.new(c))
+ }
+ lpb.cancel
+ painter.fillRect(0, 0, width, height, Qt::Brush.new(backgroundColor))
+ painter.end()
+ end
+ end
+end
+
+a = Qt::Application.new(ARGV)
+w = CPUWaster.new
+w.show
+a.setMainWidget(w)
+a.exec
diff --git a/qtruby/rubylib/examples/qt-examples/tictac/main.rb b/qtruby/rubylib/examples/qt-examples/tictac/main.rb
new file mode 100755
index 00000000..024ae70c
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/tictac/main.rb
@@ -0,0 +1,13 @@
+#!/usr/bin/env ruby -w
+
+require 'Qt'
+require 'tictac'
+
+a = Qt::Application.new(ARGV)
+n = 3 # get board size n
+
+ttt = TicTacToe.new(n)
+a.setMainWidget(ttt)
+ttt.setCaption('QtRuby Example - TicTac')
+ttt.show()
+a.exec()
diff --git a/qtruby/rubylib/examples/qt-examples/tictac/tictac.rb b/qtruby/rubylib/examples/qt-examples/tictac/tictac.rb
new file mode 100644
index 00000000..04ab8b9d
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/tictac/tictac.rb
@@ -0,0 +1,311 @@
+require 'Qt'
+
+class TicTacButton < Qt::PushButton
+
+ attr_accessor :btype
+
+ Blank, Circle, Cross = 0, 1, 2
+
+ def initialize(p)
+ super(p)
+ @btype = Blank
+ end
+
+ def drawButtonLabel(p)
+ r = rect()
+ p.setPen( Qt::Pen.new( Qt::white,2 ) ) # set fat pen
+ if (@btype == Circle)
+ p.drawEllipse( r.left()+4, r.top()+4, r.width()-8, r.height()-8 )
+ elsif (@btype == Cross) # draw cross
+ p.drawLine( r.topLeft() +Qt::Point.new(4,4), r.bottomRight()-Qt::Point.new(4,4))
+ p.drawLine( r.bottomLeft()+Qt::Point.new(4,-4),r.topRight() -Qt::Point.new(4,-4))
+ end
+ super(p)
+ end
+end
+
+class TicTacGameBoard < Qt::Widget
+ signals 'finished()'
+ slots 'buttonClicked()'
+
+ Init, HumansTurn, HumanWon, ComputerWon, NobodyWon = 0, 1, 2, 3, 4
+
+ attr_accessor :state, :computer_starts
+
+ def initialize (n, parent)
+ super(parent)
+ @state = Init
+ @nBoard = n
+ n = n*n
+ @computer_starts = false
+ @buttons = Array.new(n)
+ @btArray = Array.new(n)
+
+ grid = Qt::GridLayout.new(self, n, n, 4)
+ p = Qt::Palette.new(Qt::blue)
+
+ for i in (0..n-1)
+ ttb = TicTacButton.new(self)
+ ttb.setPalette(p)
+ ttb.setEnabled(false)
+ connect(ttb, SIGNAL('clicked()'), self, SLOT('buttonClicked()'))
+ grid.addWidget(ttb, i % @nBoard, i / @nBoard)
+ @buttons[i] = ttb
+ @btArray[i] = TicTacButton::Blank
+ end
+ end
+
+ def newGame
+ @state = HumansTurn
+ for i in 0..(@nBoard*@nBoard)-1
+ @btArray[i] = TicTacButton::Blank
+ end
+ if @computer_starts == true
+ computerMove
+ else
+ updateButtons
+ end
+ end
+
+ def updateButtons
+ for i in 0..(@nBoard*@nBoard)-1
+ if @buttons[i].btype != @btArray[i]
+ @buttons[i].btype = @btArray[i]
+ end
+ if @buttons[i].btype == TicTacButton::Blank
+ @buttons[i].setEnabled(true)
+ else
+ @buttons[i].setEnabled(false)
+ end
+ @buttons[i].repaint
+ end
+ end
+
+ def checkBoard
+ t = 0
+ row = 0
+ col = 0
+ won = false
+
+ # check horizontal
+ for row in 0..@nBoard-1
+ if won == true
+ break
+ end
+ t = @btArray[row*@nBoard]
+ if (t == TicTacButton::Blank)
+ next
+ end
+ col = 1
+ while ( (col < @nBoard) && (@btArray[row*@nBoard+col] == t) )
+ col += 1
+ end
+ if (col == @nBoard)
+ won = true
+ end
+ end
+
+ # check vertical
+ for col in 0..@nBoard-1
+ if won == true
+ break
+ end
+ t = @btArray[col]
+ if (t == TicTacButton::Blank)
+ next
+ end
+ row = 1
+ while ( (row < @nBoard) && (@btArray[row*@nBoard+col] == t) )
+ row += 1
+ end
+ if (row == @nBoard)
+ won = true
+ end
+ end
+
+ # check diagonal top left to bottom right
+ if (won == false)
+ t = @btArray[0]
+ if (t != TicTacButton::Blank)
+ i = 1;
+ while (i<@nBoard && (@btArray[i*@nBoard+i] == t))
+ i += 1
+ end
+ if (i == @nBoard)
+ won = true
+ end
+ end
+ end
+
+ # check diagonal bottom left to top right
+ if (won == false)
+ j = @nBoard-1
+ i = 0;
+ t = @btArray[i+j*@nBoard];
+ if (t != TicTacButton::Blank)
+ i += 1
+ j -= 1
+ while ( (i<@nBoard) && (@btArray[i+j*@nBoard] == t) )
+ i += 1
+ j -= 1
+ end
+ if (i == @nBoard)
+ won = true
+ end
+ end
+ end
+
+ if (won == false)
+ # no winner
+ t = 0
+ end
+
+ t
+ end
+
+ def computerMove
+ numButtons = @nBoard*@nBoard
+ altv = Array.new
+ stopHuman = -1
+ i = 0
+
+ for i in 0..numButtons-1 # try all positions
+ if @btArray[i] != TicTacButton::Blank # already a piece there
+ next
+ end
+
+ @btArray[i] = TicTacButton::Cross # test if computer wins
+ if (checkBoard == @btArray[i]) # computer will win
+ @state = ComputerWon
+ stopHuman = -1
+ break
+ end
+
+ @btArray[i] = TicTacButton::Circle # test if human wins
+ if (checkBoard == @btArray[i]) # oops...
+ stopHuman = i # remember position
+ @btArray[i] = TicTacButton::Blank # restore button
+ next # computer still might win
+ end
+ @btArray[i] = TicTacButton::Blank; # restore button
+ altv.push(i) # remember alternative
+ end
+
+ if (stopHuman >= 0) # must stop human from winning
+ @btArray[stopHuman] = TicTacButton::Cross
+ elsif (i == numButtons-1) # tried all alternatives
+ if (altv.size > 0) # set random piece
+ @btArray[altv[rand(altv.size)]] = TicTacButton::Cross
+ end
+ if ((altv.size-1) == 0) # no more blanks
+ @state = NobodyWon
+ emit finished()
+ end
+ end
+ updateButtons # update buttons
+ end
+
+ def buttonClicked
+ unless @state == HumansTurn
+ return
+ end
+
+ at = nil
+ for i in 0..@buttons.size
+ if @buttons[i].object_id == sender.object_id
+ at = i
+ break
+ end
+ end
+ if @btArray[at] == TicTacButton::Blank
+ @btArray[at] = TicTacButton::Circle
+ updateButtons
+
+ if (checkBoard == 0)
+ computerMove
+ end
+ s = checkBoard
+ if (s != 0)
+ if (s == TicTacButton::Circle)
+ @state = HumanWon
+ else
+ @state = ComputerWon
+ end
+ emit finished()
+ end
+ end
+ end
+
+end
+
+class TicTacToe < Qt::Widget
+ slots 'newGameClicked()', 'gameOver()'
+
+ def initialize (boardSize)
+ super()
+
+ l = Qt::VBoxLayout.new(self, 6)
+
+ @state_msg = [
+ 'Click Play to start',
+ 'Make your move',
+ 'You won!',
+ 'Computer won!',
+ 'It\'s a draw']
+
+ # Create a message label
+ @message = Qt::Label.new(self)
+ @message.setFrameStyle((Qt::Frame.WinPanel|Qt::Frame.Sunken))
+ @message.setAlignment(Qt::AlignCenter)
+ l.addWidget(@message)
+
+ # Create the game board and connect the signal finished()
+ # to this/self gameOver() slot
+ @board = TicTacGameBoard.new(boardSize, self)
+ connect(@board, SIGNAL('finished()'), self, SLOT('gameOver()'));
+ l.addWidget(@board)
+
+ # Create a horizontal frame line
+ line = Qt::Frame.new(self)
+ line.setFrameStyle(Qt::Frame.HLine|Qt::Frame.Sunken)
+ l.addWidget(line)
+
+ # Create the combo box for deciding who should start
+ # and connect its clicked() signals to the buttonClicked() slot
+ @whoStarts = Qt::ComboBox.new(self)
+ @whoStarts.insertItem('Computer starts')
+ @whoStarts.insertItem('Human starts')
+ l.addWidget(@whoStarts);
+
+ # Create the push buttons and connect their signals to the right slots
+ @newGame = Qt::PushButton.new('Play!', self)
+ connect(@newGame, SIGNAL('clicked()'), self, SLOT('newGameClicked()'))
+ @quit = Qt::PushButton.new('Quit', self)
+ connect(@quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+ b = Qt::HBoxLayout.new
+ l.addLayout(b)
+ b.addWidget(@newGame)
+ b.addWidget(@quit)
+
+ newState()
+ end
+
+ def newState
+ @message.setText(@state_msg[@board.state])
+ end
+
+ def newGameClicked
+ if @whoStarts.currentItem == 0
+ @board.computer_starts = true
+ else
+ @board.computer_starts = false
+ end
+ @board.newGame()
+ newState()
+ end
+
+ def gameOver
+ # Update text box
+ newState()
+ end
+end
diff --git a/qtruby/rubylib/examples/qt-examples/tooltip/main.rb b/qtruby/rubylib/examples/qt-examples/tooltip/main.rb
new file mode 100755
index 00000000..f1f9ccda
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/tooltip/main.rb
@@ -0,0 +1,12 @@
+#!/usr/bin/env ruby
+
+require 'Qt'
+require 'tooltip'
+
+a = Qt::Application.new(ARGV)
+
+mw = TellMe.new
+mw.setCaption('QtRuby Example - Dynamic Tool Tips')
+a.setMainWidget(mw)
+mw.show
+a.exec
diff --git a/qtruby/rubylib/examples/qt-examples/tooltip/tooltip.rb b/qtruby/rubylib/examples/qt-examples/tooltip/tooltip.rb
new file mode 100644
index 00000000..181816da
--- /dev/null
+++ b/qtruby/rubylib/examples/qt-examples/tooltip/tooltip.rb
@@ -0,0 +1,95 @@
+require 'Qt'
+
+class DynamicTip < Qt::ToolTip
+ def initialize(p)
+ super(p)
+ end
+
+ def maybeTip(p)
+ if !parentWidget.inherits('TellMe')
+ return
+ end
+
+ r = parentWidget.tip(p)
+ if !r.isValid
+ return
+ end
+
+ s = 'position: ' + r.center.x.to_s + ', ' + r.center.y.to_s
+ tip(r,s)
+ end
+end
+
+class TellMe < Qt::Widget
+
+ def initialize
+ super
+
+ setMinimumSize(30, 30)
+
+ @r1 = randomRect
+ @r2 = randomRect
+ @r3 = randomRect
+
+ @t = DynamicTip.new(self)
+
+ Qt::ToolTip.add(self, @r3, 'this color is called red') #TT says this is helpful, I'm not so sure
+ end
+
+ def tip(point)
+ if (@r1.contains(point))
+ @r1
+ elsif (@r2.contains(point))
+ @r2
+ else
+ Qt::Rect.new(0,0, -1, -1)
+ end
+ end
+
+ def paintEvent(e)
+ p = Qt::Painter.new(self)
+
+ if (e.rect.intersects(@r1))
+ p.setBrush(Qt::blue)
+ p.drawRect(@r1)
+ end
+
+ if (e.rect.intersects(@r2))
+ p.setBrush(Qt::blue)
+ p.drawRect(@r2)
+ end
+
+ if (e.rect.intersects(@r3))
+ p.setBrush(Qt::red)
+ p.drawRect(@r3)
+ end
+
+ p.end
+ end
+
+ def mousePressEvent (e)
+ if (@r1.contains(e.pos))
+ @r1 = randomRect
+ end
+
+ if (@r2.contains(e.pos))
+ @r2 = randomRect
+ end
+
+ repaint
+ end
+
+ def resizeEvent(e)
+ unless rect.contains(@r1)
+ @r1 = randomRect
+ end
+
+ unless rect.contains(@r2)
+ @r2 = randomRect
+ end
+ end
+
+ def randomRect
+ Qt::Rect.new(rand(width - 20), rand(height - 20), 20, 20)
+ end
+end
diff --git a/qtruby/rubylib/examples/qtscribble/scribble.rb b/qtruby/rubylib/examples/qtscribble/scribble.rb
new file mode 100644
index 00000000..7c6e1ca5
--- /dev/null
+++ b/qtruby/rubylib/examples/qtscribble/scribble.rb
@@ -0,0 +1,274 @@
+#!/usr/bin/env ruby -w
+
+ #
+ # A class that lets the user draw with the mouse. The
+ # window knows how to redraw itself.
+ #
+
+require 'Qt'
+
+ class ScribbleArea < Qt::Widget
+
+ slots "setColor(QColor)", "slotLoad(const QString&)", "slotSave(const QString&)", "slotClearArea()"
+
+ #
+ # The constructor. Initializes the member variables.
+ #
+ def initialize()
+ super
+ # initialize member variables
+ @_buffer = Qt::Pixmap.new()
+ @_last = Qt::Point.new()
+ @_currentcolor = black
+
+ # don't blank the window before repainting
+ setBackgroundMode( NoBackground )
+
+ # create a pop-up menu
+ @_popupmenu = Qt::PopupMenu.new()
+ @_popupmenu.insertItem( "&Clear", self, SLOT( "slotClearArea()" ) )
+ end
+
+ #
+ # This slot sets the curren color for the scribble area. It will be
+ # connected with the colorChanged( Qt::Color ) signal from the
+ # ScribbleWindow.
+ #
+ def setColor( new_color )
+ @_currentcolor = new_color
+ end
+
+ #
+ # This slot clears the drawing area by filling the off-screen buffer with
+ # white and copying it over to the window.
+ #
+ def slotClearArea()
+ # fill the off screen buffer with plain white
+ @_buffer.fill( white )
+
+ # and copy it over to the window
+ bitBlt( self, 0, 0, @_buffer )
+ end
+
+
+ #
+ # This method does the actual loading. It relies on Qt::Pixmap (and the
+ # underlying I/O machinery) to determine the filetype.
+ #
+ def slotLoad( filename )
+ if !@_buffer.load( filename )
+ Qt::MessageBox.warning( nil, "Load error", "Could not load file" )
+ end
+
+ repaint() # refresh the window
+ end
+
+
+ #
+ # This method does the actual saving. We hard-code the file type as
+ # BMP. Unix users might want to replace this with something like XPM.
+ #
+ def slotSave( filename )
+ if !@_buffer.save( filename, "BMP" )
+ Qt::MessageBox.warning( nil, "Save error", "Could not save file" )
+ end
+ end
+
+
+ #
+ # This method is called whenever the user presses the
+ # mouse over the window. It just records the position of the mouse
+ # at the time of the click.
+ #
+ def mousePressEvent(event)
+ if event.button() == RightButton
+ @_popupmenu.exec( Qt::Cursor.pos() )
+ else
+ @_last = event.pos() # retrieve the coordinates from the event
+ end
+ end
+
+
+ #
+ # The method is called whenever the usr moves the mouse
+ # while the mouse button is pressed. If we had called
+ # setMouseTracking(true) before, the method would also be called
+ # when the mouse was moved with any button pressed. We know that
+ # we haven't, and thus don't have to check whether any buttons are
+ # pressed.
+ #
+ def mouseMoveEvent(event)
+ # create a Qt::Painter object for drawing onto the window
+ windowpainter = Qt::Painter.new()
+ # and another Qt::Painter object for drawing int an off-screen pixmap
+ bufferpainter = Qt::Painter.new()
+
+ # start painting
+ windowpainter.begin( self ) # This painter paints onto the window
+ bufferpainter.begin( @_buffer ) # and this one paints in the buffer
+
+ # set a standard pen with the currently selected color
+ windowpainter.setPen( @_currentcolor )
+ bufferpainter.setPen( @_currentcolor )
+
+ # draw a line in both the window and the buffer
+ windowpainter.drawLine( @_last, event.pos() )
+ bufferpainter.drawLine( @_last, event.pos() )
+
+ # done with painting
+ windowpainter.end()
+ bufferpainter.end()
+
+ # remember the current mouse position
+ @_last = event.pos()
+ end
+
+ #
+ # This method is called whenever the widget needs
+ # painting, for example when it has been obscured and then revealed again.
+ #
+ def paintEvent(event)
+ bitBlt(self, 0, 0, @_buffer)
+ end
+
+ #
+ # This method get called whenever the widget needs
+ # painting, for example, when it has been obscured and then revealed again.
+ #
+ def resizeEvent(event)
+ save = Qt::Pixmap.new( @_buffer )
+ @_buffer.resize( event.size() )
+ @_buffer.fill( white )
+ bitBlt( @_buffer, 0, 0, save )
+ end
+ end
+
+class ScribbleWindow < Qt::Widget
+
+ slots "slotAbout()", "slotAboutQt()", "slotColorMenu(int)", "slotLoad()", "slotSave()"
+ signals "colorChanged(QColor)", "load(const QString&)", "save(const QString&)"
+
+ COLOR_MENU_ID_BLACK = 0
+ COLOR_MENU_ID_RED = 1
+ COLOR_MENU_ID_BLUE = 2
+ COLOR_MENU_ID_GREEN = 3
+ COLOR_MENU_ID_YELLOW = 4
+
+ def initialize()
+ super
+ # The next lines build the menu bar. We first create the menus
+ # one by one, then add them to the menu bar. #
+ @_filemenu = Qt::PopupMenu.new() # create a file menu
+ @_filemenu.insertItem( "&Load", self, SLOT( "slotLoad()" ) )
+ @_filemenu.insertItem( "&Save", self, SLOT( "slotSave()" ) )
+ @_filemenu.insertSeparator()
+ @_filemenu.insertItem( "&Quit", $qApp, SLOT( "quit()" ) )
+
+ @_colormenu = Qt::PopupMenu.new() # create a color menu
+ @_colormenu.insertItem( "B&lack", COLOR_MENU_ID_BLACK)
+ @_colormenu.insertItem( "&Red", COLOR_MENU_ID_RED)
+ @_colormenu.insertItem( "&Blue", COLOR_MENU_ID_BLUE)
+ @_colormenu.insertItem( "&Green", COLOR_MENU_ID_GREEN)
+ @_colormenu.insertItem( "&Yellow", COLOR_MENU_ID_YELLOW)
+ Qt::Object.connect( @_colormenu, SIGNAL( "activated( int )" ),
+ self, SLOT( "slotColorMenu( int )" ) )
+
+ @_helpmenu = Qt::PopupMenu.new() # create a help menu
+ @_helpmenu.insertItem( "&About QtScribble", self, SLOT( "slotAbout()" ) )
+ @_helpmenu.insertItem( "&About Qt", self, SLOT( "slotAboutQt()" ) )
+
+ @_menubar = Qt::MenuBar.new( self, "" ) # create a menu bar
+ @_menubar.insertItem( "&File", @_filemenu )
+ @_menubar.insertItem( "&Color", @_colormenu )
+ @_menubar.insertItem( "&Help", @_helpmenu )
+
+ # We create a Qt::ScrollView and a ScribbleArea. The ScribbleArea will
+ # be managed by the scroll view.#
+ @_scrollview = Qt::ScrollView.new( self )
+ @_scrollview.setGeometry( 0, @_menubar.height(),
+ width(), height() - @_menubar.height() )
+ @_scribblearea = ScribbleArea.new()
+ @_scribblearea.setGeometry( 0, 0, 1000, 1000 )
+ @_scrollview.addChild( @_scribblearea )
+ Qt::Object.connect( self, SIGNAL( "colorChanged(QColor)" ),
+ @_scribblearea, SLOT( "setColor(QColor)" ) )
+ Qt::Object.connect( self, SIGNAL( "save(const QString&)" ),
+ @_scribblearea, SLOT( "slotSave(const QString&)" ) )
+ Qt::Object.connect( self, SIGNAL( "load(const QString&)" ),
+ @_scribblearea, SLOT( "slotLoad(const QString&)" ) )
+ end
+
+ def resizeEvent( event )
+ # When the whole window is resized, we have to rearrange the geometry
+ # in the ScribbleWindow as well. Note that the ScribbleArea does not need
+ # to be changed.
+ @_scrollview.setGeometry( 0, @_menubar.height(),
+ width(), height() - @_menubar.height() )
+ end
+
+
+
+ def slotAbout()
+ Qt::MessageBox.information( self, "About QtScribble 5",
+ "This is the Scribble 5 application\n" +
+ "Copyright 1998 by Mathias Kalle Dalheimer\n")
+ end
+
+ def slotAboutQt()
+ Qt::MessageBox.aboutQt( self, "About Qt" )
+ end
+
+ def slotColorMenu( item )
+ case item
+ when COLOR_MENU_ID_BLACK
+ emit colorChanged( black )
+ when COLOR_MENU_ID_RED
+ emit colorChanged( darkRed )
+ when COLOR_MENU_ID_BLUE
+ emit colorChanged( darkBlue )
+ when COLOR_MENU_ID_GREEN
+ emit colorChanged( darkGreen )
+ when COLOR_MENU_ID_YELLOW
+ emit colorChanged( yellow )
+ end
+ end
+
+
+ #
+ # This is the slot for the menu item File/Load. It opens a
+ # Qt::FileDialog to ask the user for a filename, then emits a save()
+ # signal with the filename as parameter.
+ #
+ def slotLoad()
+ # Open a file dialog for loading. The default directory is the
+ # current directory, the filter *.bmp.
+ #
+ filename = Qt::FileDialog.getOpenFileName( ".", "*.bmp", self )
+ if !filename.nil?
+ emit load( filename )
+ end
+ end
+
+ #
+ # This is the slot for the menu item File/Load. It opens a
+ # Qt::FileDialog to ask the user for a filename, then emits a save()
+ # signal with the filename as parameter.
+ #
+ def slotSave()
+ # Open a file dialog for saving. The default directory is the
+ # current directory, the filter *.bmp.
+ #
+ filename = Qt::FileDialog.getSaveFileName( ".", "*.bmp", self )
+ if !filename.nil?
+ emit save( filename )
+ end
+ end
+end
+
+myapp = Qt::Application.new(ARGV)
+mywidget = ScribbleWindow.new()
+mywidget.setGeometry(50, 500, 400, 400)
+
+myapp.setMainWidget(mywidget)
+mywidget.show()
+myapp.exec()
diff --git a/qtruby/rubylib/examples/ruboids/Manifest b/qtruby/rubylib/examples/ruboids/Manifest
new file mode 100644
index 00000000..4fe3f97a
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/Manifest
@@ -0,0 +1,26 @@
+Manifest
+README
+TODO
+boids.properties
+generateManifest.rb
+index.html
+release.rb
+ruboids/
+ Boid.rb
+ BoidView.rb
+ Camera.rb
+ CameraDialog.rb
+ Canvas.rb
+ Cloud.rb
+ CloudView.rb
+ Flock.rb
+ Graphics.rb
+ Params.rb
+ Point.rb
+ Thing.rb
+ Triangle.rb
+ View.rb
+ World.rb
+ WorldWindow.rb
+ info.rb
+ ruboids.rb
diff --git a/qtruby/rubylib/examples/ruboids/README b/qtruby/rubylib/examples/ruboids/README
new file mode 100644
index 00000000..5417037a
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/README
@@ -0,0 +1,53 @@
+INTRODUCTION
+============
+
+RuBoids is a Boids simulation written in Ruby and using OpenGL and Qt. For
+information on Boids, see http://www.red3d.com/cwr/boids/.
+
+Ruby is an object-oriented scripting language by Yukihiro Matsumoto. The
+official Ruby Web site (http://www.ruby-lang.org/) contains information and
+pointers to resources for this wonderful language.
+
+RuBoids is developed and maintained by Jim Menard (<jimm@io.com>). The
+latest version of RuBoids can be found on the Ruby Application Archive or
+on the official RuBoids Web page
+(http://www.io.com/~jimm/downloads/ruboids/).
+
+RUNNING
+=======
+
+ cd ruboids
+ ruboids.rb
+
+RuBoids looks for an optional properties file. If none is specified on the
+command line, it looks for a file named 'boids.properties' in the current
+directory. For example, to load the example properties file in this
+directory:
+
+ cd ruboids
+ ruboids.rb ../boids.properties
+
+DEPENDENCIES
+============
+
+RuBoids requires the OpenGL and Qt packages, which can be found on the Ruby
+Application Archive.
+
+COPYING
+=======
+
+RuBoids is copyrighted free software by Jim Menard and is released under the
+same license as Ruby. See the Ruby license
+(http://www.ruby-lang.org/en/LICENSE.txt).
+
+RuBoids may be freely copied in its entirety providing this notice, all
+source code, all documentation, and all other files are included.
+
+RuBoids is copyright (c) 2001 by Jim Menard.
+
+WARRANTY
+========
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/qtruby/rubylib/examples/ruboids/TODO b/qtruby/rubylib/examples/ruboids/TODO
new file mode 100644
index 00000000..25fe501d
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/TODO
@@ -0,0 +1,29 @@
+BUGS
+====
+
+* Boid rotation.
+
+* Frustum.
+
+TO DO
+=====
+
+* Comment the code.
+
+* More documentation.
+
+* Save/restore params (e.g. camera position).
+
+POSSIBLE ADDITIONS
+==================
+
+* Make sphere output more efficient by using strips or fans.
+
+* Boids-eye view: camera follows position of a boid. This is not hard, but
+ I have to fix boid rotation first.
+
+* Velocity and destination influence proportional to distance from other
+ boids. Boids that are farther away have less influence on your velocity
+ and destination.
+
+* Boids that are behind you don't influence you because you can't see them.
diff --git a/qtruby/rubylib/examples/ruboids/boids.properties b/qtruby/rubylib/examples/ruboids/boids.properties
new file mode 100644
index 00000000..20bb5001
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/boids.properties
@@ -0,0 +1,33 @@
+# This is an example configuration file for RuBoids. It sets all of the
+# possible properties. The values here are the default values set in
+# Params.rb.
+
+world.sleep_millis = 75
+world.width = 400
+world.height = 400
+world.depth = 400
+window.width = 500
+window.height = 500
+flock.boids = 10
+boid.max_speed = 30
+boid.bounds_limit_pull = 5
+boid.bounds_limit_above_ground_level = 5
+boid.wing_length = 10
+boid.personal_space_dist = 12
+boid.square_of_personal_space_dist = 144
+boid.max_perching_turns = 150
+boid.perch_wing_flap_percent = 30
+cloud.count = 10
+cloud.min_speed = 2
+cloud.max_speed = 50
+cloud.min_bubbles = 3
+cloud.max_bubbles = 10
+cloud.max_bubble_radius = 10
+cloud.min_altitude = 250
+camera.x = 0
+camera.y = 0
+camera.z = 60
+camera.rot_x = 50
+camera.rot_y = 10
+camera.rot_z = 0
+camera.zoom = 1
diff --git a/qtruby/rubylib/examples/ruboids/generateManifest.rb b/qtruby/rubylib/examples/ruboids/generateManifest.rb
new file mode 100755
index 00000000..f877b0b3
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/generateManifest.rb
@@ -0,0 +1,42 @@
+#! /usr/bin/env ruby
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+# This script builds the Manifest file. It can be run stand-alone, but
+# is normally used from within release.rb.
+#
+
+def recurseDirectory(io, dirName, indentLevel)
+ Dir.entries(dirName).sort.each { | f |
+ next if f =~ /^\.\.?/
+ fileName = "#{dirName}/#{f}"
+ fileName.sub!(/^\.\//, '')
+ if File.directory?(fileName)
+ io.puts "\t" * indentLevel + fileName + '/'
+ recurseDirectory(io, fileName, indentLevel + 1)
+ else
+ io.puts "\t" * indentLevel + f
+ end
+ }
+end
+
+def generateManifest
+ io = nil
+ begin
+ io = File.open('Manifest', 'w')
+ recurseDirectory(io, '.', 0)
+ ensure
+ io.close() if io
+ end
+end
+
+if $0 == __FILE__
+ generateManifest()
+end
+
+
+
+
diff --git a/qtruby/rubylib/examples/ruboids/index.html b/qtruby/rubylib/examples/ruboids/index.html
new file mode 100644
index 00000000..9b320f8e
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/index.html
@@ -0,0 +1,147 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<html>
+<head>
+<title>RuBoids</title>
+<link rel="stylesheet" href="../../style.css" type="text/css">
+</head>
+<body background="../../images/gradient_bg.gif" bgcolor="white">
+<!--#exec cgi="../../cgi-bin/log_visitor.cgi" -->
+
+<table width="100%">
+ <tr>
+ <td valign="top">
+ <table width="100" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td valign="top"><font size="-1">
+<script language="JavaScript"><!--
+PREFIX = "../../"; // -->
+</script>
+<!-- #include virtual="/~jimm/menu.js"-->
+<A href="../../index.html">
+<IMG src="../../images/KeyMaster.gif"
+width="32" height="32" alt="Home" border="0"></A><BR>
+<A href="../../index.html">Home</A><BR>
+<A href="../nqxml/index.html">NQXML</A><BR>
+RuBoids<BR>
+<A href="../../computers.html">Computers</A><BR>
+<A href="../../java.html">Java</A><BR>
+<A href="../../beos.html">BeOS</A><BR>
+<A href="../../ftp_sites.html">FTP sites</A><BR>
+<A href="../../music.html">Music</A><BR>
+<A href="../../midi_ref.html">MIDI Reference</A><BR>
+<A href="../../keymaster.html">KeyMaster</A><BR>
+<A href="../../MIDI_Through.html">MIDI Through</A><BR>
+<A href="../../jimm.html">Narcissism</A><BR>
+<A href="../../resume.html">Resume</A><BR>
+<A href="../../urls.html">Links</A><BR>
+<A href="../../map.html">Site Map</A><BR>
+
+
+ </font></td>
+ </tr>
+ </table>
+ </td>
+ <td valign="top">
+ <table border="0" cellpadding="0" cellspacing="0">
+ <tr valign="top">
+ <td>
+
+<div align="right">
+<font size="+3"><b>RuBoids</b></font>
+<img src="../../images/computer.gif" width="32" height="32"
+ alt="[home]" border="0">
+</div><br>
+<hr>
+
+<h1>Introduction</h1>
+
+<p>
+RuBoids is a Boids simulation written in Ruby and using OpenGL and Qt. For
+information on Boids, see <a
+href="http://www.red3d.com/cwr/boids/">http://www.red3d.com/cwr/boids/</a>.
+</p>
+
+<p>
+Ruby is an object-oriented scripting language by Yukihiro Matsumoto. Visit
+the official <a href="http://www.ruby-lang.org/">Ruby Web site</a> for more
+information.
+</p>
+
+<p>
+</p>
+
+<p>
+RuBoids is developed and maintained by Jim Menard, <a
+href="mailto:jimm@io.com">jimm@io.com</a>. The official
+Web page of RuBoids is <a
+href="http://www.io.com/~jimm/downloads/RuBoids/">http://www.io.com/~jimm/downloads/RuBoids/</a>,
+where the latest release may be found.
+</p>
+
+
+<h1>Dependencies</h1>
+
+<p>
+RuBoids requires the OpenGL and Qt packages, which can be found on the <a
+href="html://www.ruby-lang.org/en/raa.html">Ruby Application Archive</a>.
+</p>
+
+
+<h1>Download</h1>
+
+<p>
+Download the latest version, <a href="ruboids-0.0.1.tar.gz">RuBoids version
+0.0.1</a>.
+</p>
+
+<!--
+<p>
+Earlier versions:
+</p>
+
+<ul>
+<li><a href="RuBoids-0.0.1.tar.gz">Version 0.0.1</a></li>
+</ul>
+-->
+
+<h1>Bugs</h1>
+
+<p>
+Boids don't rotate properly. In other words, they point in the wrong
+direction.
+</p>
+
+
+<h1>Copying</h1>
+
+<p>
+RuBoids is copyrighted free software by Jim Menard and is released under
+the same license as Ruby.
+</p>
+
+<h1>Warranty</h1>
+
+<p>
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+</p>
+
+<hr>
+Back to my <a href="../../index.html">home page</a>, or the
+<a href="../../map.html">Site Map</a>.<br>
+<font size="-1">
+<i>Page last modified on
+<!--#config timefmt="%B %d, %Y" -->
+<!--#echo var="LAST_MODIFIED" -->
+by <a href="mailto:jimm@io.com">me</a>.</i>
+<br>Contents &copy; 2001 by Jim Menard. All rights reserved.
+</font>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/qtruby/rubylib/examples/ruboids/release.rb b/qtruby/rubylib/examples/ruboids/release.rb
new file mode 100755
index 00000000..d82ba154
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/release.rb
@@ -0,0 +1,152 @@
+#! /usr/bin/env ruby
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+# This script gathers everything needed to release RuBoids into one directory
+# and, if requested, publishes the contents to the RuBoids Web site.
+#
+# usage:
+#
+# release.rb [--publish, -p]
+#
+# Specifying --publish or -p causes the resulting files to be published
+# to the Web site.
+#
+
+require 'net/ftp'
+require 'ftools' # For makedirs and install
+require 'generateManifest' # For--you guessed it--generating the Manifest
+
+# Start looking for RUBOIDS classes in this directory.
+# This forces us to use the local copy of RUBOIDS, even if there is
+# a previously installed version out there somewhere.
+$LOAD_PATH[0, 0] = '.'
+
+require 'ruboids/info' # For Version string
+
+FILE_PERMISSION = 0644
+DIR_PERMISSION = 0755
+
+PUBLISH_FLAG = '-p'
+RUBOIDS_DIR = 'ruboids'
+DOCS_DIR = '.'
+#DOCS_HTML_DIR = "#{DOCS_DIR}/README"
+
+RUBOIDS_DIR_WITH_VERSION = "#{RUBOIDS_DIR}-#{Version}"
+RELEASE_DIR = "/tmp/#{RUBOIDS_DIR_WITH_VERSION}_release"
+#RELEASE_HTML_DIR = "#{RELEASE_DIR}/README"
+
+DOWNLOAD_FILE = "#{DOCS_DIR}/index.html"
+#DOCBOOK_FILE = "#{DOCS_DIR}/README.sgml"
+
+WEB_SITE = 'io.com'
+WEB_DIR = 'public-web/downloads/ruboids'
+
+# Copies all files from `fromDir' into the release directory. Sets the
+# permissions of all files to 0644.
+def copyFiles(fromDir, toDir, match=nil)
+ Dir.foreach(fromDir) { | f |
+ next if f =~ /^\.\.?/ || (!match.nil? && !(f =~ match))
+ File.install("#{fromDir}/#{f}", toDir, FILE_PERMISSION)
+ }
+end
+
+# Recursively removes the contents of a directory.
+def rmDirectory(dirName)
+ return unless File.exists?(dirName)
+ Dir.foreach(dirName) { | f |
+ next if f =~ /^\.\.?/
+ path = "#{dirName}/#{f}"
+ rmDirectory(path) if File.directory?(path)
+ File.delete(path) if !File.directory?(path)
+ }
+
+end
+
+# Recursively sends files and directories.
+def sendToWebSite(ftp, releaseDir, webDir)
+ ftp.chdir(webDir)
+ Dir.foreach(releaseDir) { | f |
+ next if f =~ /^\.\.?/
+ path = "#{releaseDir}/#{f}"
+ if File.directory?(path)
+ begin
+ ftp.mkdir(f)
+ rescue Net::FTPPermError
+ # ignore; it's OK if the directory already exists
+ end
+ sendToWebSite(ftp, path, f)
+ ftp.chdir('..')
+ else
+ ftp.putbinaryfile(path, f)
+ end
+ }
+end
+
+def ensureVersionInFile(fileName, regex)
+ lines = File.open(fileName).grep(regex)
+ found = lines.detect { | line | line =~ /#{Version}/o }
+ if !found
+ $stderr.puts "Warning: it looks like the #{fileName} version number" +
+ " is incorrect"
+ end
+end
+
+# ================================================================
+# main
+# ================================================================
+
+# Make sure the docs mention the correct version number.
+#ensureVersionInFile(DOWNLOAD_FILE, /Download the latest/)
+#ensureVersionInFile(DOCBOOK_FILE, /releaseinfo/)
+
+# Empty release dir if it already exists.
+rmDirectory(RELEASE_DIR)
+
+# (Re)create release dir. This makes RELEASE_HTML_DIR, whose parent
+# is RELEASE_DIR. Therefore, RELEASE_DIR is created as well.
+#File.makedirs(RELEASE_HTML_DIR)
+File.makedirs(RELEASE_DIR)
+
+# Recreate the full documentation (creating README and docs/README) and copy
+# the HTML files to the release directory. Finally, clean up the docs
+# directory.
+
+#system("cd #{DOCS_DIR} && make")
+#copyFiles(DOCS_DIR, RELEASE_DIR, /\.html$/)
+#copyFiles(DOCS_HTML_DIR, RELEASE_HTML_DIR, /\.html$/)
+copyFiles(DOCS_DIR, RELEASE_DIR, 'index.html')
+
+# Generate the Manifest file.
+generateManifest()
+
+# Create .tar.gz file. We temporarily rename the RUBOIDS folder to
+# "ruboids-X.Y.Z", tar and gzip that directory, then restore its original
+# name.
+Dir.chdir('..')
+File.rename(RUBOIDS_DIR, RUBOIDS_DIR_WITH_VERSION)
+system("tar -czf #{RELEASE_DIR}/#{RUBOIDS_DIR_WITH_VERSION}.tar.gz " +
+ RUBOIDS_DIR_WITH_VERSION)
+File.chmod(FILE_PERMISSION, "#{RELEASE_DIR}/#{RUBOIDS_DIR_WITH_VERSION}.tar.gz")
+File.rename(RUBOIDS_DIR_WITH_VERSION, RUBOIDS_DIR)
+
+# ftp files if requested
+if !ARGV.empty? && ARGV[0] == PUBLISH_FLAG
+ require 'net/ftp'
+
+ # Ask for ftp username and password
+ guess = ENV['LOGNAME'] || ENV['USER']
+ print "username [#{guess}]: "
+ username = $stdin.gets().chomp()
+ username = guess if username.empty?
+ print "password: "
+ password = $stdin.gets().chomp()
+
+ # ftp files to web site
+ ftp = Net::FTP.open(WEB_SITE, username, password)
+ sendToWebSite(ftp, RELEASE_DIR, WEB_DIR)
+ ftp.close()
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Boid.rb b/qtruby/rubylib/examples/ruboids/ruboids/Boid.rb
new file mode 100644
index 00000000..38ac7bcc
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Boid.rb
@@ -0,0 +1,141 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'BoidView'
+require 'Flock'
+require 'Point'
+require 'Params'
+
+class Boid < Thing
+
+ attr_accessor :maxSpeed, :maxSpeedSquared, :perchingTurnsLeft,
+ :wingFlapPos, :almostGroundLevel, :flock
+
+ def initialize(pos = nil)
+ super(pos, nil)
+ init
+ end
+
+ def init
+ @maxSpeed = $PARAMS['boid_max_speed']
+ @maxSpeedSquared = @maxSpeed * @maxSpeed
+ @flock = nil # set by flock when flock adds to self
+ @wingFlapPos = rand(7)
+ @perchingTurnsLeft = 0
+ @almostGroundLevel = 5.0
+
+ @view = BoidView.new(self)
+ end
+
+ def move
+ # Flap wings. Only flap occasionally if not perching.
+ if (@perchingTurnsLeft == 0 ||
+ rand(100) < $PARAMS['boid_perch_wing_flap_percent'])
+ @wingFlapPos = (@wingFlapPos + 1) & 7
+ end
+
+ if @perchingTurnsLeft > 0
+ # Only take off when wing flap position == 2.
+ if --@perchingTurnsLeft == 0 && @wingFlapPos != 2
+ @perchingTurnsLeft = (8 + 2 - @wingFlapPos) & 7
+ return
+ end
+ end
+
+ moveTowardsFlockCenter()
+ avoidOthers()
+ matchOthersVelocities()
+ boundPosition()
+ limitSpeed()
+
+ super() # Add velocity vector to position.
+
+ # Boids at ground level perch for a while.
+ if @position.y < @almostGroundLevel
+ @position.y = @almostGroundLevel
+ @vector.x = @vector.y = @vector.z = 0
+ @perchingTurnsLeft =
+ rand($PARAMS['boid_max_perching_turns'])
+ end
+ end
+
+ def moveTowardsFlockCenter()
+ flockCenter = @flock.centerExcluding(self)
+ flockCenter.subtractPoint(@position)
+ # Move 1% of the way towards the center
+ flockCenter.divideBy(100.0)
+
+ @vector.addPoint(flockCenter)
+ end
+
+ def avoidOthers()
+ c = Point.new()
+ @flock.members.each { | b |
+ if b != self
+ otherPos = b.position
+ if @position.squareOfDistanceTo(otherPos) <
+ $PARAMS['boid_square_of_personal_space_dist']
+ c.addPoint(@position)
+ c.subtractPoint(otherPos)
+ end
+ end
+ }
+ @vector.addPoint(c)
+ end
+
+ def matchOthersVelocities()
+ vel = Point.new()
+ flock.members.each { | b |
+ if b != self
+ vel.addPoint(b.vector)
+ end
+ }
+ vel.divideBy(flock.members.length - 1)
+ vel.subtractPoint(@vector)
+ vel.divideBy(8)
+
+ @vector.addPoint(vel)
+ end
+
+ def boundPosition()
+ v = Point.new
+
+ halfWidth = $PARAMS['world_width'] / 2
+ halfHeight = $PARAMS['world_height'] / 2
+ halfDepth = $PARAMS['world_depth'] / 2
+
+ if position.x < -halfWidth
+ v.x = $PARAMS['boid_bounds_limit_pull']
+ elsif position.x > halfWidth
+ v.x = -$PARAMS['boid_bounds_limit_pull']
+ end
+
+ if position.y < -halfHeight + almostGroundLevel +
+ $PARAMS['boid_bounds_limit_above_ground_level']
+ v.y = $PARAMS['boid_bounds_limit_pull']
+ elsif position.y > halfHeight
+ v.y = -$PARAMS['boid_bounds_limit_pull']
+ end
+
+ if position.z < -halfDepth
+ v.z = $PARAMS['boid_bounds_limit_pull']
+ elsif position.z > halfDepth
+ v.z = -$PARAMS['boid_bounds_limit_pull']
+ end
+
+ @vector.addPoint(v)
+ end
+
+ def limitSpeed()
+ speedSquared = Point::ORIGIN.squareOfDistanceTo(@vector)
+ if speedSquared > @maxSpeedSquared
+ f = Math.sqrt(speedSquared) * @maxSpeed
+ @vector.divideBy(f)
+ end
+ end
+end
+
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/BoidView.rb b/qtruby/rubylib/examples/ruboids/ruboids/BoidView.rb
new file mode 100644
index 00000000..f2fc1288
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/BoidView.rb
@@ -0,0 +1,159 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'View'
+
+class BoidView < View
+
+ BODY_COLOR = [0, 0, 0]
+ BEAK_COLOR = [0.75, 0.5, 0.0]
+ SHADOW_COLOR = [0.25, 0.55, 0.25]
+
+ HALF_WING_BASE = 3
+ HALF_LENGTH = 5
+ HALF_THICKNESS = 1
+ NOSE_LENGTH = 3
+
+ @@object = nil
+ @@shadow = nil
+ @@wings = nil
+ @@wingsShadows = nil
+
+ def initialize(model)
+ super(model, [0, 0, 0])
+ @wings = nil
+ @wingsShadows = nil
+ end
+
+ def makeObject
+ @@object = BoidView.makeObject() unless @@object
+ @object = @@object
+ @wings = @@wings
+ end
+
+ def makeShadow
+ BoidView.makeShadow() unless @@shadow
+ @shadow = @@shadow
+ @wingsShadows = @@wingsShadows
+ end
+
+ def drawObject
+ super()
+
+ angle = 0
+ case model.wingFlapPos
+ when 0
+ angle = 60
+ when 1, 7
+ angle = 30
+ when 2, 6
+ angle = 0
+ when 3, 5
+ angle = -30
+ when 4
+ angle = -60
+ end
+
+ PushMatrix()
+ Rotate(angle, 0, 0, 1)
+ CallList(@wings[0])
+ Rotate(angle * -2, 0, 0, 1)
+ CallList(@wings[1])
+ PopMatrix()
+ end
+
+ def BoidView.makeObject
+ makeWings()
+
+ object = GenLists(1)
+ NewList(object, COMPILE)
+
+ makeBody()
+ makeNose()
+
+ EndList()
+
+ return object
+ end
+
+ def BoidView.makeShadow
+ @@shadow = GenLists(1)
+ NewList(@@shadow, COMPILE)
+
+ p0 = Point::ORIGIN.dup()
+ p1 = Point::ORIGIN.dup()
+ dims = Point.new(HALF_THICKNESS, HALF_THICKNESS, HALF_LENGTH)
+ p0.subtractPoint(dims)
+ p1.addPoint(dims)
+
+ groundLevel = -($PARAMS['world_height'] / 2) + 1
+
+ Color(SHADOW_COLOR)
+ Begin(QUADS)
+ Vertex(p1.x, groundLevel, p0.z)
+ Vertex(p0.x, groundLevel, p0.z)
+ Vertex(p0.x, groundLevel, p1.z)
+ Vertex(p1.x, groundLevel, p1.z)
+ End()
+# Begin(TRIANGLES)
+# Vertex(p1.x, groundLevel, p1.z)
+# Vertex(0, groundLevel, p0.z)
+# Vertex(p0.x, groundLevel, p1.z)
+# End()
+
+ EndList()
+ end
+
+ def BoidView.makeBody
+ p0 = Point::ORIGIN.dup()
+ p1 = Point::ORIGIN.dup()
+ dims = Point.new(HALF_THICKNESS, HALF_THICKNESS, HALF_LENGTH)
+ p0.subtractPoint(dims)
+ p1.addPoint(dims)
+
+ Color(BODY_COLOR)
+ Graphics.boxFromCorners(p0, p1)
+ end
+
+ def BoidView.makeWings
+ @@wings = []
+ len = -$PARAMS['boid_wing_length']
+ @@wings << makeOneWing(len)
+ @@wings << makeOneWing(-len)
+ end
+
+ def BoidView.makeOneWing(len)
+ wing = GenLists(1)
+ NewList(wing, COMPILE)
+
+ Color(BODY_COLOR)
+ Begin(TRIANGLES)
+
+ Vertex(0, 0, -HALF_WING_BASE)
+ Vertex(len, 0, 0)
+ Vertex(0, 0, HALF_WING_BASE)
+
+ End()
+ EndList()
+ return wing
+ end
+
+ def BoidView.makeNose()
+ Color(BEAK_COLOR)
+ Begin(TRIANGLE_FAN)
+
+ Vertex(0, 0, HALF_LENGTH + NOSE_LENGTH)
+ Vertex( HALF_THICKNESS, HALF_THICKNESS, HALF_LENGTH)
+ Vertex(-HALF_THICKNESS, HALF_THICKNESS, HALF_LENGTH)
+ Vertex(-HALF_THICKNESS, -HALF_THICKNESS, HALF_LENGTH)
+ Vertex( HALF_THICKNESS, -HALF_THICKNESS, HALF_LENGTH)
+
+ End()
+ end
+
+end
+
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Camera.rb b/qtruby/rubylib/examples/ruboids/ruboids/Camera.rb
new file mode 100644
index 00000000..787fc4af
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Camera.rb
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Params'
+
+class Camera
+
+ attr_accessor :position, :rotation, :zoom
+
+ def initialize
+ @position = Point.new($PARAMS['camera_x'],
+ $PARAMS['camera_y'],
+ $PARAMS['camera_z'])
+ @rotation = Point.new($PARAMS['camera_rot_x'],
+ $PARAMS['camera_rot_y'],
+ $PARAMS['camera_rot_z'])
+ @zoom = $PARAMS['camera_zoom']
+ end
+end
+
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/CameraDialog.rb b/qtruby/rubylib/examples/ruboids/ruboids/CameraDialog.rb
new file mode 100644
index 00000000..6e01db15
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/CameraDialog.rb
@@ -0,0 +1,213 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Qt'
+require 'World'
+require 'Camera'
+
+class Adjustor
+ attr_accessor :slider, :num, :origValue
+ def initialize(slider, num, origValue = 0)
+ @slider = slider
+ @num = num
+ @origValue = origValue
+ end
+ def setSlider(val); @slider.setValue(val); end
+ def setNum(val); @num.setNum(val); end
+ def set(val)
+ setSlider(val)
+ setNum(val)
+ end
+ def reset
+ set(@origValue)
+ return @origValue
+ end
+end
+
+class CameraDialog < Qt::Dialog
+ slots 'slotReset()', 'slotLocXChanged(int)',
+ 'slotLocYChanged(int)', 'slotLocZChanged(int)',
+ 'slotRotationXChanged(int)', 'slotRotationYChanged(int)',
+ 'slotRotationZChanged(int)', 'slotZoomChanged(int)'
+
+ def initialize(parent)
+ super
+ @locAdjustors = []
+ @rotationAdjustors = []
+ @otherAdjustors = []
+ @avoidUpdates = false
+
+ @camera = World.instance.camera
+
+ # Remember values for reset
+ @origCamera = @camera.dup()
+
+ # Group and layout widgets
+ vLayout = Qt::VBoxLayout.new(self, 5)
+
+ locBox = Qt::GroupBox.new('Location', self, 'locBox')
+ rotationBox = Qt::GroupBox.new('Rotation', self, 'rotationBox')
+ otherBox = Qt::GroupBox.new('Other', self, 'otherBox')
+
+ locLayout = Qt::GridLayout.new(locBox, 5, 3, 20)
+ rotationLayout = Qt::GridLayout.new(rotationBox, 5, 3, 20)
+ otherLayout = Qt::GridLayout.new(otherBox, 3, 3, 20)
+ buttonLayout = Qt::HBoxLayout.new()
+
+ vLayout.addWidget(locBox)
+ vLayout.addWidget(rotationBox)
+ vLayout.addWidget(otherBox)
+ vLayout.addSpacing(10)
+ vLayout.addLayout(buttonLayout)
+
+ # Add extra space at the top of each layout so the group box title
+ # doesn't get squished.
+ locLayout.addRowSpacing(0, 15)
+ rotationLayout.addRowSpacing(0, 15)
+ otherLayout.addRowSpacing(0, 15)
+
+ # Contents of camera location box
+ @locAdjustors << addSlider(1, locBox, locLayout, 'X', -1000, 1000, 1,
+ 'slotLocXChanged(int)', @camera.position.x)
+ @locAdjustors << addSlider(2, locBox, locLayout, 'Y', -1000, 1000, 1,
+ 'slotLocYChanged(int)', @camera.position.y)
+ @locAdjustors << addSlider(3, locBox, locLayout, 'Z', -1000, 1000, 1,
+ 'slotLocZChanged(int)', @camera.position.z)
+
+ # Contents of camera rotation box
+ @rotationAdjustors << addSlider(1, rotationBox, rotationLayout, 'X',
+ 0, 360, 1, 'slotRotationXChanged(int)',
+ @camera.rotation.x)
+ @rotationAdjustors << addSlider(2, rotationBox, rotationLayout, 'Y',
+ 0, 360, 1, 'slotRotationYChanged(int)',
+ @camera.rotation.y)
+ @rotationAdjustors << addSlider(3, rotationBox, rotationLayout, 'Z',
+ 0, 360, 1, 'slotRotationZChanged(int)',
+ @camera.rotation.z)
+
+ @otherAdjustors << addSlider(1, otherBox, otherLayout, 'Zoom',
+ 1, 100, 1, 'slotZoomChanged(int)',
+ @camera.zoom * 10.0)
+ @otherAdjustors[0].origValue = @camera.zoom
+
+ # The Close button
+ button = Qt::PushButton.new('Close', self, 'Dialog Close')
+ connect(button, SIGNAL('clicked()'), self, SLOT('close()'))
+ button.setDefault(true)
+ button.setFixedSize(button.sizeHint())
+ buttonLayout.addWidget(button)
+
+ # The Close button
+ button = Qt::PushButton.new('Reset', self, 'Dialog Reset')
+ connect(button, SIGNAL('clicked()'), self, SLOT('slotReset()'))
+ button.setFixedSize(button.sizeHint())
+ buttonLayout.addWidget(button)
+
+ # 15 layout management
+ locLayout.activate()
+ rotationLayout.activate()
+ otherLayout.activate()
+ vLayout.activate()
+
+ resize(0, 0)
+
+ setCaption('Camera Settings')
+ end
+
+ def addSlider(row, box, layout, label, min, max, pageStep, slot,
+ initialValue)
+ # Label
+ text = Qt::Label.new(label, box)
+ text.setMinimumSize(text.sizeHint())
+ layout.addWidget(text, row, 0)
+
+ # Slider
+ slider = Qt::Slider.new(min, max, pageStep, initialValue,
+ Qt::Slider::Horizontal, box)
+ slider.setMinimumSize(slider.sizeHint())
+ slider.setMinimumWidth(180)
+ layout.addWidget(slider, row, 1)
+
+ # Connection from slider signal to our slot
+ connect(slider, SIGNAL('valueChanged(int)'), self, SLOT(slot))
+
+ # Number display
+ num = Qt::Label.new('XXXXX', box)
+ num.setMinimumSize(num.sizeHint())
+ num.setFrameStyle(Qt::Frame::Panel | Qt::Frame::Sunken)
+ num.setAlignment(AlignRight | AlignVCenter)
+ num.setNum(initialValue)
+
+ layout.addWidget(num, row, 2)
+
+ return Adjustor.new(slider, num, initialValue)
+ end
+
+ def cameraChanged
+ World.instance.setupTranslation() unless @avoidUpdates
+ end
+
+ def slotLocXChanged(val)
+ @locAdjustors[0].setNum(val)
+ @camera.position.x = val
+ cameraChanged()
+ end
+
+ def slotLocYChanged(val)
+ @locAdjustors[1].setNum(val)
+ @camera.position.y = val
+ cameraChanged()
+ end
+
+ def slotLocZChanged(val)
+ @locAdjustors[2].setNum(val)
+ @camera.position.z = val
+ cameraChanged()
+ end
+
+ def slotRotationXChanged(val)
+ @rotationAdjustors[0].setNum(val)
+ @camera.rotation.x = val
+ cameraChanged()
+ end
+
+ def slotRotationYChanged(val)
+ @rotationAdjustors[1].setNum(val)
+ @camera.rotation.y = val
+ cameraChanged()
+ end
+
+ def slotRotationZChanged(val)
+ @rotationAdjustors[2].setNum(val)
+ @camera.rotation.z = val
+ cameraChanged()
+ end
+
+ def slotZoomChanged(val)
+ @otherAdjustors[0].setNum(val)
+ @camera.zoom = val / 10.0
+ cameraChanged()
+ end
+
+ def slotReset
+ @avoidUpdates = true
+
+ @camera.position.x = @locAdjustors[0].reset()
+ @camera.position.y = @locAdjustors[1].reset()
+ @camera.position.z = @locAdjustors[2].reset()
+
+ @camera.rotation.x = @rotationAdjustors[0].reset()
+ @camera.rotation.y = @rotationAdjustors[1].reset()
+ @camera.rotation.z = @rotationAdjustors[2].reset()
+
+ @camera.zoom = @otherAdjustors[0].reset()
+
+ @avoidUpdates = false
+ cameraChanged()
+ end
+
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Canvas.rb b/qtruby/rubylib/examples/ruboids/ruboids/Canvas.rb
new file mode 100644
index 00000000..91ed934b
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Canvas.rb
@@ -0,0 +1,144 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Qt'
+require 'opengl'
+require 'World'
+require 'Cloud'
+require 'Flock'
+require 'Params'
+require 'Camera'
+
+include GL
+
+class Canvas < Qt::GLWidget
+
+ GRASS_COLOR = [0, 0.75, 0]
+ MDA_ROTATE = :MDA_ROTATE
+ MDA_ZOOM = :MDA_ZOOM
+ MDA_CHANGE_FOCUS = :MDA_CHANGE_FOCUS
+
+ def initialize(parent = nil, name = '')
+ super
+ @grassObject = nil
+# catchEvent
+ end
+
+ def update
+ updateGL()
+ end
+
+ def initializeGL()
+ ClearColor(0.4, 0.4, 1.0, 0.0) # Let OpenGL clear to light blue
+ @grassObject = makeGrassObject()
+ ShadeModel(FLAT)
+ end
+
+ def paintGL()
+ Enable(DEPTH_TEST)
+ Clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT)
+
+ MatrixMode(MODELVIEW)
+
+ camera = World.instance.camera
+
+ LoadIdentity()
+ Rotate(camera.rotation.x, 1, 0, 0)
+ Rotate(camera.rotation.y, 0, 1, 0)
+ Rotate(camera.rotation.z, 0, 0, 1.0)
+ Translate(-camera.position.x, -camera.position.y, -camera.position.z)
+ Scale(camera.zoom, camera.zoom, camera.zoom)
+
+ CallList(@grassObject)
+
+ World.instance.clouds.each { | cloud | cloud.draw() }
+ World.instance.flock.draw()
+ end
+
+ # Set up the OpenGL view port, matrix mode, etc.
+ def resizeGL(w, h)
+ Viewport(0, 0, w, h)
+ MatrixMode(PROJECTION)
+ LoadIdentity()
+
+# # left, right, bottom, top, front, back (focal_length)
+ halfXSize = $PARAMS['world_width'] / 2 * 1.25
+ halfYSize = $PARAMS['world_height'] / 2 * 1.25
+ halfZSize = $PARAMS['world_depth'] / 2 * 1.25
+
+# Frustum(-halfXSize, halfXSize, -halfYSize, halfYSize,
+# 5, halfZSize * 2)
+
+ Ortho(-halfXSize, halfXSize, -halfYSize, halfYSize,
+ -halfZSize, halfZSize)
+
+ MatrixMode(MODELVIEW)
+ end
+
+ def makeGrassObject
+ halfXSize = $PARAMS['world_width']
+ halfYSize = $PARAMS['world_depth'] / 2
+ halfZSize = $PARAMS['world_height']
+
+ list = GenLists(1)
+ NewList(list, COMPILE)
+ LineWidth(2.0)
+ Begin(QUADS)
+
+ Color(GRASS_COLOR)
+ # Counter-clockwise
+ Vertex( halfXSize, -halfYSize, halfZSize)
+ Vertex(-halfXSize, -halfYSize, halfZSize)
+ Vertex(-halfXSize, -halfYSize, -halfZSize)
+ Vertex( halfXSize, -halfYSize, -halfZSize)
+
+ End()
+ EndList()
+ return list
+ end
+
+ def mousePressEvent(e)
+ @mouseLoc = e.pos()
+ case e.button()
+ when Qt::LeftButton
+ @mouseDragAction = MDA_ZOOM
+ when Qt::RightButton
+ @mouseDragAction = MDA_ROTATE
+ when Qt::MidButton
+ @mouseDragAction = MDA_CHANGE_FOCUS
+ end
+ end
+
+ # Rotate around sphere with right (#2) button. Zoom with left button.
+ # Change focus with left button.
+ def mouseMoveEvent(e)
+ return if @mouseLoc.nil?
+
+ dx = dy = 0
+ if e.x() != @mouseLoc.x()
+ dx = e.x() - @mouseLoc.x() # move right increases dx
+ @mouseLoc.setX(e.x())
+ end
+ if e.y() != @mouseLoc.y()
+ dy = @mouseLoc.y() - e.y() # move up increases dy
+ @mouseLoc.setY(e.y())
+ end
+
+ return if dx == 0 && dy == 0
+
+ case @mouseDragAction
+ when MDA_ZOOM
+ return if (dy == 0)
+ World.instance.camera.zoom += 0.1 * -dy
+ when MDA_ROTATE
+ break
+ when MDA_CHANGE_FOCUS
+ break
+ end
+ World.instance.setupTranslation()
+ end
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Cloud.rb b/qtruby/rubylib/examples/ruboids/ruboids/Cloud.rb
new file mode 100644
index 00000000..5d30222a
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Cloud.rb
@@ -0,0 +1,61 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Thing'
+require 'CloudView'
+require 'Params'
+
+class Bubble
+
+ attr_reader :loc, :radius, :color
+
+ def initialize
+ @radius = rand($PARAMS['cloud_max_bubble_radius']) + 1
+ @loc = Point.new(0, rand(8) - 4, rand(8) - 4)
+ c = 0.85 + rand() * 0.15
+ @color = [c, c, c]
+ end
+
+end
+
+
+class Cloud < Thing
+
+ attr_reader :speed, :bubbles, :width
+
+ def initialize
+ minSpeed = $PARAMS['cloud_min_speed']
+ minBubbles = $PARAMS['cloud_min_bubbles']
+ @speed = rand($PARAMS['cloud_max_speed'] - minSpeed) + minSpeed
+ numBubbles = rand($PARAMS['cloud_max_bubbles'] - minBubbles) +
+ minBubbles
+ @bubbles = []
+ prevBubble = nil
+ (0 ... numBubbles).each { | i |
+ bubble = Bubble.new()
+ if !prevBubble.nil?
+ bubble.loc.x = prevBubble.loc.x +
+ rand((prevBubble.radius + bubble.radius) * 0.66)
+ end
+
+ @bubbles[i] = prevBubble = bubble
+ }
+
+ @width = bubbles.last.loc.x +
+ @bubbles.first.radius + @bubbles.last.radius
+
+ @view = CloudView.new(self)
+ end
+
+ def move
+ @position.x += pixelsPerSecToPixelsPerMove(speed)
+ halfWorldWidth = $PARAMS['world_width']
+ if (@position.x >= halfWorldWidth / 2)
+ @position.x = -(halfWorldWidth + @width)
+ end
+ end
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/CloudView.rb b/qtruby/rubylib/examples/ruboids/ruboids/CloudView.rb
new file mode 100644
index 00000000..75c62177
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/CloudView.rb
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Qt'
+require 'View'
+require 'Cloud'
+require 'Params'
+require 'World'
+require 'Graphics'
+
+class CloudView < View
+
+ def initialize(cloud)
+ super(cloud)
+ end
+
+ def makeObject
+ @object = GenLists(1)
+ NewList(@object, COMPILE)
+
+ @model.bubbles.each { | bubble |
+ Color(bubble.color)
+ PushMatrix()
+ Translate(bubble.loc.x, bubble.loc.y, bubble.loc.z)
+ Scale(bubble.radius, bubble.radius, bubble.radius)
+ Graphics.sphere()
+ PopMatrix()
+ }
+
+ EndList()
+ end
+
+ def makeShadow
+ @shadow = GenLists(1)
+ NewList(@shadow, COMPILE)
+
+ groundLevel = -($PARAMS['world_height'] / 2) + 1
+ @model.bubbles.each { | bubble |
+ Color(shadowColorForHeight(model.position.y + bubble.loc.y))
+ PushMatrix()
+ Translate(bubble.loc.x, groundLevel, bubble.loc.z)
+ Scale(bubble.radius, 1.0, bubble.radius)
+ Graphics.circle(2)
+ PopMatrix()
+ }
+
+ EndList()
+ end
+
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Flock.rb b/qtruby/rubylib/examples/ruboids/ruboids/Flock.rb
new file mode 100644
index 00000000..4d476a2b
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Flock.rb
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Flock'
+require 'Boid'
+require 'Params'
+
+class Flock
+ attr_reader :members
+
+ def initialize
+ @members = []
+ end
+
+ def add(boid)
+ @members << boid
+ boid.flock = self
+ end
+
+ def draw
+ @members.each { | boid | boid.draw() }
+ end
+
+ def move
+ @members.each { | boid | boid.move() }
+ end
+
+ # Return distance between two boid's positions.
+ def distBetween(b1, b2)
+ return b1.position.distanceTo(b2.position)
+ end
+
+ # Center of mass
+ def centerExcluding(b)
+ p = Point.new()
+ @members.each { | boid |
+ p.addPoint(boid.position) unless boid == b
+ }
+ p.divideBy(@members.length - 1)
+ return p
+ end
+end
+
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Graphics.rb b/qtruby/rubylib/examples/ruboids/ruboids/Graphics.rb
new file mode 100644
index 00000000..5e982208
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Graphics.rb
@@ -0,0 +1,278 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Triangle'
+
+class Graphics
+
+ DEFAULT_SPHERE_ITERATIONS = 3
+
+ XPLUS = Point.new(1, 0, 0) # X
+ XMINUS = Point.new(-1, 0, 0)# -X
+ YPLUS = Point.new(0, 1, 0) # Y
+ YMINUS = Point.new(0, -1, 0)# -Y
+ ZPLUS = Point.new(0, 0, 1) # Z
+ ZMINUS = Point.new(0, 0, -1)# -Z
+
+ # defined w/counter-clockwise triangles
+ OCTAHEDRON = [
+ Triangle.new(YPLUS, ZPLUS, XPLUS),
+ Triangle.new(XMINUS, ZPLUS, YPLUS),
+ Triangle.new(YMINUS, ZPLUS, XMINUS),
+ Triangle.new(XPLUS, ZPLUS, YMINUS),
+ Triangle.new(ZMINUS, YPLUS, XPLUS),
+ Triangle.new(ZMINUS, XMINUS , YPLUS),
+ Triangle.new(ZMINUS, YMINUS , XMINUS),
+ Triangle.new(ZMINUS, XPLUS, YMINUS)
+ ]
+ # Defines counter-clockwise points used in OpenGL TRIANGLE_STRIP to
+ # create a circle on the X/Z plane. Don't include center point here;
+ # It is added when outputting the circle.
+ SQUARE = [
+ XPLUS, ZMINUS, XMINUS, ZPLUS, XPLUS
+ ]
+
+ @@spheres = Hash.new()
+ @@circles = Hash.new()
+
+ def Graphics.radiansToDegrees(rad)
+ return rad * 180.0 / Math::PI
+ end
+
+ def Graphics.degreesToRadians(deg)
+ return deg * Math::PI / 180.0
+ end
+
+ # Given a vector, return a point containing x, y, z rotation angles.
+ #
+ # atan2(x, y) = the angle formed with the x axis by the ray from the
+ # origin to the point {x,y}
+ def Graphics.rotations(v)
+ return Point::ORIGIN.dup() if v.nil?
+ return v if v == Point::ORIGIN
+
+ x = Math.atan2(v.y, v.z)
+ y = Math.atan2(v.z, v.x)
+ z = Math.atan2(v.y, v.x)
+
+ rot = Point.new(z, x, y)
+ rot.add(Math::PI).multiplyBy(180.0).divideBy(Math::PI)
+
+ rot.x = rot.x.to_i
+ rot.y = rot.y.to_i
+ rot.z = rot.z.to_i
+
+ return rot
+ end
+
+ # Build box from corners. All faces are counter-clockwise.
+ def Graphics.boxFromCorners(p0, p1)
+ pa = p0.dup()
+ pb = p1.dup()
+
+ # Make sure all coords of pa are < all coords of pb
+ if pa.x > pb.x
+ tmp = pa.x; pa.x = pb.x; pb.x = tmp
+ end
+ if pa.y > pb.y
+ tmp = pa.y; pa.y = pb.y; pb.y = tmp
+ end
+ if pa.z > pb.z
+ tmp = pa.z; pa.z = pb.z; pb.z = tmp
+ end
+
+ Begin(QUAD_STRIP)
+
+ # top
+ Vertex(pb.x, pb.y, pa.z)
+ Vertex(pa.x, pb.y, pa.z)
+ # top/front
+ Vertex(pb.x, pb.y, pb.z)
+ Vertex(pa.x, pb.y, pb.z)
+ # front/bottom
+ Vertex(pb.x, pa.y, pb.z)
+ Vertex(pa.x, pa.y, pb.z)
+ # bottom/back
+ Vertex(pb.x, pa.y, pa.z)
+ Vertex(pa.x, pa.y, pa.z)
+ # back/top
+ Vertex(pb.x, pb.y, pa.z)
+ Vertex(pa.x, pb.y, pa.z)
+
+ End()
+
+ Begin(QUADS)
+
+ # left
+ Vertex(pa.x, pa.y, pb.z)
+ Vertex(pa.x, pa.y, pa.z)
+ Vertex(pa.x, pb.y, pa.z)
+ Vertex(pa.x, pb.y, pb.z)
+
+ # right
+ Vertex(pb.x, pa.y, pb.z)
+ Vertex(pb.x, pa.y, pa.z)
+ Vertex(pb.x, pb.y, pa.z)
+ Vertex(pb.x, pb.y, pb.z)
+
+ End()
+ end
+
+ # sphere() (and buildSphere()) - generate a triangle mesh approximating
+ # a sphere by recursive subdivision. First approximation is an
+ # octahedron; each level of refinement increases the number of
+ # triangles by a factor of 4.
+ #
+ # Level 3 (128 triangles) is a good tradeoff if gouraud shading is used
+ # to render the database.
+ #
+ # Usage: sphere [level] [counterClockwise]
+ #
+ # The value level is an integer >= 1 setting the recursion level
+ # (default = DEFAULT_SPHERE_ITERATIONS).
+ # The boolean counterClockwise causes triangles to be generated
+ # with vertices in counterclockwise order as viewed from
+ # the outside in a RHS coordinate system. The default is
+ # counter-clockwise.
+ #
+ # @author Jon Leech (leech@cs.unc.edu) 3/24/89 (C version)
+ # Ruby version by Jim Menard (jimm@io.com), May 2001.
+ def Graphics.sphere(iterations = DEFAULT_SPHERE_ITERATIONS,
+ counterClockwise = true)
+ if @@spheres[iterations].nil?
+ @@spheres[iterations] = buildSphere(iterations, OCTAHEDRON)
+ end
+ sphere = @@spheres[iterations]
+
+ Begin(TRIANGLES)
+ sphere.each { | triangle |
+ triangle.points.each { | p |
+ Vertex(p.x, p.y, p.z) if counterClockwise
+ Vertex(p.z, p.y, p.x) if !counterClockwise
+ }
+ }
+ End()
+ end
+
+ #
+ # Subdivide each triangle in the oldObj approximation and normalize
+ # the new points thus generated to lie on the surface of the unit
+ # sphere.
+ # Each input triangle with vertices labelled [0,1,2] as shown
+ # below will be turned into four new triangles:
+ #
+ # Make new points
+ # a = (0+2)/2
+ # b = (0+1)/2
+ # c = (1+2)/2
+ # 1
+ # /\ Normalize a, b, c
+ # / \
+ # b/____\ c Construct new counter-clockwise triangles
+ # /\ /\ [a,b,0]
+ # / \ / \ [c,1,b]
+ # /____\/____\ [c,b,a]
+ # 0 a 2 [2,c,a]
+ #
+ #
+ # The normalize step (which makes each point a, b, c unit distance
+ # from the origin) is where we can modify the sphere's shape.
+ #
+ def Graphics.buildSphere(iterations, sphere)
+ oldObj = sphere
+ # Subdivide each starting triangle (maxlevel - 1) times
+ iterations -= 1
+ iterations.times {
+ # Create a new object. Allocate 4 * the number of points in the
+ # the current approximation.
+ newObj = Array.new(oldObj.length * 4)
+
+ j = 0
+ oldObj.each { | oldt |
+ # New midpoints
+ a = Point.midpoint(oldt.points[0], oldt.points[2])
+ a.normalize!()
+ b = Point.midpoint(oldt.points[0], oldt.points[1])
+ b.normalize!()
+ c = Point.midpoint(oldt.points[1], oldt.points[2])
+ c.normalize!()
+
+ # New triangeles. Their vertices are counter-clockwise.
+ newObj[j] = Triangle.new(a, b, oldt.points[0])
+ j += 1
+ newObj[j] = Triangle.new(c, oldt.points[1], b)
+ j += 1
+ newObj[j] = Triangle.new(c, b, a)
+ j += 1
+ newObj[j] = Triangle.new(oldt.points[2], c, a)
+ j += 1
+ }
+
+ # Continue subdividing new triangles
+ oldObj = newObj
+ }
+ return oldObj
+ end
+
+ # Creates a circle in the X/Z plane. To have the circle's normal
+ # point down (-Y), specify clockwise instead of counter-clockwise.
+ # To create the circle in another plane, call OpenGL's Rotate() method
+ # before calling this.
+ def Graphics.circle(iterations = DEFAULT_SPHERE_ITERATIONS,
+ counterClockwise = true)
+ if @@circles[iterations].nil?
+ @@circles[iterations] = buildCircle(iterations, SQUARE)
+ end
+ circle = @@circles[iterations]
+
+ Begin(TRIANGLE_FAN)
+ Vertex(0, 0, 0)
+ if counterClockwise
+ circle.each { | p | Vertex(p.x, 0, p.z) }
+ else
+ circle.reverse.each { | p | Vertex(p.x, 0, p.z) }
+ end
+ End()
+ end
+
+ # Different than buildSphere because we are creating triangles to
+ # be used in an OpenGL TRIANGLE_FAN operation. Thus the first point
+ # (the center) is always inviolate. We create new points between
+ # the remaining points.
+ def Graphics.buildCircle(iterations, circle)
+ oldObj = circle
+ # Subdivide each starting line segment (maxlevel - 1) times
+ iterations -= 1
+ iterations.times {
+ # Create a new object. Allocate 2 * the number of points in the
+ # the current approximation. Subtract one because the last point
+ # (same as the first point) is simply copied.
+ newObj = Array.new(oldObj.length * 2 - 1)
+
+ prevP = nil
+ j = 0
+ oldObj.each { | p |
+ if !prevP.nil?
+ newObj[j] = prevP
+ j += 1
+
+ # New midpoint
+ a = Point.midpoint(prevP, p)
+ a.normalize!()
+ newObj[j] = a
+ j += 1
+ end
+ prevP = p
+ }
+ newObj[j] = prevP # Copy last point
+
+ # Continue subdividing new triangles
+ oldObj = newObj
+ }
+ return oldObj
+ end
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Params.rb b/qtruby/rubylib/examples/ruboids/ruboids/Params.rb
new file mode 100644
index 00000000..9ff57851
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Params.rb
@@ -0,0 +1,87 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'singleton'
+
+$PARAMS = {
+ 'world_sleep_millis' => 75,
+ 'world_width' => 400,
+ 'world_height' => 400,
+ 'world_depth' => 400,
+ 'window_width' => 500,
+ 'window_height' => 500,
+ 'flock_boids' => 10,
+ 'boid_max_speed' => 30,
+ 'boid_bounds_limit_pull' => 5,
+ 'boid_bounds_limit_above_ground_level' => 5,
+ 'boid_wing_length' => 10,
+ 'boid_personal_space_dist' => 12,
+ 'boid_square_of_personal_space_dist' => 144,
+ 'boid_max_perching_turns' => 150,
+ 'boid_perch_wing_flap_percent' => 30,
+ 'cloud_count' => 10,
+ 'cloud_min_speed' => 2,
+ 'cloud_max_speed' => 50,
+ 'cloud_min_bubbles' => 3,
+ 'cloud_max_bubbles' => 10,
+ 'cloud_max_bubble_radius' => 10,
+ 'cloud_min_altitude' => 250,
+ 'camera_x' => 0,
+ 'camera_y' => 0,
+ 'camera_z' => 60,
+ 'camera_rot_x' => 50,
+ 'camera_rot_y' => 10,
+ 'camera_rot_z' => 0,
+ 'camera_zoom' => 1
+}
+
+class Params
+
+ @@reals = %w(
+world_width
+world_height
+world_depth
+boid_max_speed
+boid_bounds_limit_pull
+boid_bounds_limit_above_ground_level
+boid_wing_length
+boid_personal_space_dist
+boid_square_of_personal_space_dist
+cloud_min_speed
+cloud_max_speed
+cloud_max_bubble_radius
+cloud_min_altitude
+camera_x
+camera_y
+camera_z
+camera_rot_x
+camera_rot_y
+camera_rot_z
+camera_zoom
+)
+
+ def Params.readParamsFromFile(paramFileName)
+ File.open(paramFileName).each { | line |
+ line.chomp!
+ next if line.empty? || line =~ /^#/
+
+ key, value = line.split(/\s*=\s*/)
+ next unless value
+ key.downcase!()
+ key.gsub!(/\./, '_')
+
+ isReal = @@reals.include?(key)
+ value = value.to_f if isReal
+ value = value.to_i if !isReal
+ $PARAMS[key] = value
+ }
+ $PARAMS['boid_square_of_personal_space_dist'] =
+ $PARAMS['boid_personal_space_dist'] *
+ $PARAMS['boid_personal_space_dist']
+ end
+
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Point.rb b/qtruby/rubylib/examples/ruboids/ruboids/Point.rb
new file mode 100644
index 00000000..0331f795
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Point.rb
@@ -0,0 +1,153 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+class Point
+
+ attr_accessor :x, :y, :z
+
+ # Return a new Point that is the midpoint on the line between two
+ # points.
+ def Point.midpoint(a, b)
+ return Point.new((a.x + b.x) * 0.5, (a.y + b.y) * 0.5,
+ (a.z + b.z) * 0.5)
+ end
+
+ def initialize(x = 0, y = 0, z = 0)
+ if x.kind_of?(Point)
+ @x = x.x
+ @y = x.y
+ @z = x.z
+ else
+ @x = x
+ @y = y
+ @z = z
+ end
+ end
+
+ ORIGIN = Point.new(0, 0, 0)
+
+ def ==(point)
+ return point.kind_of?(Point) &&
+ @x == point.x && @y == point.y && @z == point.z
+ end
+
+ # Normalize this point.
+ def normalize!
+ mag = @x * @x + @y * @y + @z * @z
+ if mag != 1.0
+ mag = 1.0 / Math.sqrt(mag)
+ @x *= mag
+ @y *= mag
+ @z *= mag
+ end
+ return self
+ end
+
+ # Return a new point that is a normalized version of this point.
+ def normalize
+ return self.dup().normalize!()
+ end
+
+ # Return a new point that is the cross product of this point and another.
+ # The cross product of two unit vectors is another vector that's at
+ # right angles to the first two (for example, a surface normal).
+ def crossProduct(p)
+ return Point.new(@y * p.z - @z * p.y, @z * p.x - @x * p.z,
+ @x * p.y - @y * p.x)
+ end
+
+ # Return the (scalar) dot product of this vector and another.
+ # The dot product of two vectors produces the cosine of the angle
+ # between them, multiplied by the lengths of those vectors. (The dot
+ # product of two normalized vectors equals cosine of the angle.)
+ def dotProduct(p)
+ return @x * p.x + @y * p.y + @z * p.z
+ end
+
+ # Return square of distance between this point and another.
+ def squareOfDistanceTo(p)
+ dx = p.x - @x
+ dy = p.y - @y
+ dz = p.z - @z
+ return dx * dx + dy * dy + dz * dz
+ end
+
+ # Return distance between this point and another.
+ def distanceTo(p)
+ dx = p.x - @x
+ dy = p.y - @y
+ dz = p.z - @z
+ return Math.sqrt(dx * dx + dy * dy + dz * dz)
+ end
+
+ def add(d)
+ @x += d
+ @y += d
+ @z += d
+ return self
+ end
+
+ def addPoint(p)
+ @x += p.x
+ @y += p.y
+ @z += p.z
+ return self
+ end
+
+
+ def subtract(d)
+ @x -= d
+ @y -= d
+ @z -= d
+ return self
+ end
+
+ def subtractPoint(p)
+ @x -= p.x
+ @y -= p.y
+ @z -= p.z
+ return self
+ end
+
+
+ def multiplyBy(d)
+ @x *= d
+ @y *= d
+ @z *= d
+ return self
+ end
+
+ def multiplyByPoint(p)
+ @x *= p.x
+ @y *= p.y
+ @z *= p.z
+ return self
+ end
+
+ def divideBy(d)
+ @x = @x / d
+ @y = @y / d
+ @z = @z / d
+ return self
+ end
+
+ def divideByPoint(p)
+ @x = @x / p.x
+ @y = @y / p.y
+ @z = @z / p.z
+ return self
+ end
+
+ def to_a
+ return [@x, @y, @z]
+ end
+
+ def to_s
+ return "Point<#{@x}, #{@y}, #{@z}>"
+ end
+
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Thing.rb b/qtruby/rubylib/examples/ruboids/ruboids/Thing.rb
new file mode 100644
index 00000000..9b6bfe5b
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Thing.rb
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Point'
+
+class Thing
+
+ attr_accessor :position, :vector, :view
+
+ def initialize(pos = nil, vec = nil)
+ @position = pos ? pos : Point.new
+ @vector = vec ? vec : Point.new
+ end
+
+ def move
+ position.x += vector.x
+ position.y += vector.y
+ position.z += vector.z
+ end
+
+ def draw
+ view.draw() if view
+ end
+
+ def pixelsPerSecToPixelsPerMove(pixelsPerSecond)
+ pps = (pixelsPerSecond.to_f / (1000.0 / 75.0)).to_i
+ pps = 1 if pps == 0
+ return pps
+ end
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/Triangle.rb b/qtruby/rubylib/examples/ruboids/ruboids/Triangle.rb
new file mode 100644
index 00000000..eedf69f9
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/Triangle.rb
@@ -0,0 +1,21 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Point'
+
+class Triangle
+ attr_accessor :points
+
+ def initialize(p0 = Point::ORIGIN,
+ p1 = Point::ORIGIN,
+ p2 = Point::ORIGIN)
+ @points = []
+ @points << p0 ? p0 : Point::ORIGIN.dup()
+ @points << p1 ? p1 : Point::ORIGIN.dup()
+ @points << p2 ? p2 : Point::ORIGIN.dup()
+ end
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/View.rb b/qtruby/rubylib/examples/ruboids/ruboids/View.rb
new file mode 100644
index 00000000..a5323629
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/View.rb
@@ -0,0 +1,88 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+# A lightweight view
+class View
+
+ SHADOW_COLOR = [ 0.25, 0.25, 0.25 ]
+
+ attr_accessor :model, :color, :object, :shadow
+
+ def initialize(model, color = nil)
+ super()
+ @model = model
+ @color = color
+ @object = nil
+ @shadow = nil
+ end
+
+ def makeObject
+ raise "subclass should implement"
+ end
+
+ def makeShadow
+ # Don't raise error; some models may not have a shadow
+ end
+
+ def drawObject
+ CallList(@object)
+ end
+
+ def drawShadow
+ CallList(@shadow) if @shadow
+ end
+
+ def draw
+ # We don't always have enough information to make the 3D objects
+ # at initialize() time.
+ makeObject() unless @object
+ makeShadow() unless @shadow
+
+ rot = Graphics.rotations(model.vector)
+
+ PushMatrix()
+
+ # Translate and rotate shadow. Rotation around y axis only.
+ Translate(model.position.x, 0, model.position.z)
+ Rotate(rot.y, 0, 1, 0) if rot.y.nonzero?
+
+ # Draw shadow.
+ drawShadow() unless @shadow.nil?
+
+ # Translate and rotate object. Rotate object around x and z axes (y
+ # axis already done for shadow).
+ Translate(0, model.position.y, 0)
+ Rotate(rot.x, 1, 0, 0) if rot.x.nonzero?
+ Rotate(rot.z, 0, 0, 1) if rot.z.nonzero?
+
+ # Draw object.
+ drawObject()
+
+ PopMatrix()
+ end
+
+ # Given the height of an object, return a shadow color. The shadow color
+ # gets lighter as heigt increases.
+ def shadowColorForHeight(height)
+ wh = $PARAMS['world_height']
+ ratio = (height + wh / 2.0) / wh
+
+ shadowColor = []
+ SHADOW_COLOR.each_with_index { | c0, i |
+ min = c0
+ max = Canvas::GRASS_COLOR[i]
+ if min > max
+ tmp = min
+ min = max
+ max = tmp
+ end
+ shadowColor << min + ratio * (max - min)
+ }
+ return shadowColor
+ end
+
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/World.rb b/qtruby/rubylib/examples/ruboids/ruboids/World.rb
new file mode 100644
index 00000000..17608bca
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/World.rb
@@ -0,0 +1,82 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'singleton'
+require 'Qt'
+require 'Params'
+require 'Cloud'
+require 'Flock'
+require 'Boid'
+require 'Camera'
+require 'Canvas'
+
+class World < Qt::Object
+ slots 'slotMove()'
+
+ include Singleton
+
+ attr_accessor :canvas
+ attr_reader :width, :height, :depth, :camera, :clouds, :flock
+
+ def initialize
+ super
+ @width = $PARAMS['world_width']
+ @height = $PARAMS['world_height']
+ @depth = $PARAMS['world_depth']
+
+ @clouds = []
+ minAltitude = $PARAMS['cloud_min_altitude']
+ $PARAMS['cloud_count'].times {
+ c = Cloud.new
+ c.position =
+ Point.new(rand(@width) - @width / 2,
+ rand(@height) - @height / 2,
+ rand(@depth - minAltitude) - @depth / 2 + minAltitude)
+ @clouds << c
+ }
+ # Sort clouds by height so lower/darker shadows are drawn last
+ @clouds.sort { |a, b| a.position.y <=> b.position.y }
+
+ @flock = Flock.new
+ $PARAMS['flock_boids'].times {
+ b = Boid.new
+ b.position = Point.new(rand(@width) - @width / 2,
+ rand(@height) - @height / 2,
+ rand(@depth) - @depth / 2)
+ @flock.add(b) # flock will delete boid
+ }
+
+ @clock = Qt::Timer.new()
+ connect(@clock, SIGNAL('timeout()'), self, SLOT('slotMove()'))
+
+ @camera = Camera.new # Reads values from params
+ setupTranslation()
+ end
+
+ # Should be called whenever camera or screen changes.
+ def setupTranslation
+ @canvas.update() if @canvas
+ end
+
+ def start
+ @clock.start($PARAMS['world_sleep_millis'])
+ end
+
+ def slotMove
+ @clouds.each { | c | c.move() }
+ @flock.move()
+ @canvas.update() if @canvas
+
+ # Camera follow boid.
+# b = @flock.members.first
+# @camera.position = b.position
+# @camera.rotation = Graphics.rotations(b.vector)
+# @camera.zoom = 1.0
+
+ end
+end
+
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/WorldWindow.rb b/qtruby/rubylib/examples/ruboids/ruboids/WorldWindow.rb
new file mode 100644
index 00000000..56650ece
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/WorldWindow.rb
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Qt'
+require 'Canvas'
+require 'CameraDialog'
+
+class WorldWindow < Qt::MainWindow
+ slots 'slotMenuActivated(int)'
+
+ MENU_CAMERA_DIALOG = 1
+
+ attr_accessor :canvas
+
+ def initialize
+ super
+ setCaption("Boids")
+ setupMenubar()
+
+ @canvas = Canvas.new(self, "TheDamnCanvas")
+ setCentralWidget(@canvas)
+ setGeometry(0, 0, $PARAMS['window_width'],
+ $PARAMS['window_height'])
+ end
+
+ def setupMenubar
+
+ # Create and populate file menu
+ menu = Qt::PopupMenu.new(self)
+ menu.insertItem("Exit", $qApp, SLOT("quit()"), Qt::KeySequence.new(CTRL+Key_Q))
+
+ # Add file menu to menu bar
+ menuBar.insertItem("&File", menu)
+
+ # Create and populate options menu
+ menu = Qt::PopupMenu.new(self)
+ menu.insertItem("&Camera...", MENU_CAMERA_DIALOG, -1)
+
+ # Add options menu to menu bar and link it to method below
+ menuBar.insertItem("&Options", menu)
+ connect(menu, SIGNAL("activated(int)"), self, SLOT('slotMenuActivated(int)'))
+
+ end
+
+ def slotMenuActivated(id)
+ if id == MENU_CAMERA_DIALOG
+ CameraDialog.new(nil).exec()
+ end
+ end
+end
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/info.rb b/qtruby/rubylib/examples/ruboids/ruboids/info.rb
new file mode 100644
index 00000000..fcfc50f6
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/info.rb
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+VERSION_MAJOR = 0
+VERSION_MINOR = 0
+VERSION_TWEAK = 1
+Version = "#{VERSION_MAJOR}.#{VERSION_MINOR}.#{VERSION_TWEAK}"
+Copyright = 'Copyright (c) 2001 by Jim Menard <jimm@io.com>'
diff --git a/qtruby/rubylib/examples/ruboids/ruboids/ruboids.rb b/qtruby/rubylib/examples/ruboids/ruboids/ruboids.rb
new file mode 100755
index 00000000..b9bdecba
--- /dev/null
+++ b/qtruby/rubylib/examples/ruboids/ruboids/ruboids.rb
@@ -0,0 +1,29 @@
+#! /usr/bin/env ruby
+#
+# Copyright (c) 2001 by Jim Menard <jimm@io.com>
+#
+# Released under the same license as Ruby. See
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+
+require 'Qt'
+require 'World'
+require 'WorldWindow'
+require 'Canvas'
+require 'Params'
+
+app = Qt::Application.new(ARGV)
+if (!Qt::GLFormat::hasOpenGL())
+ warning("This system has no OpenGL support. Exiting.")
+ exit -1
+end
+
+Params.readParamsFromFile(ARGV[0] || 'boids.properties')
+world = World.instance
+win = WorldWindow.new
+app.mainWidget = win
+
+World.instance.canvas = win.canvas
+win.show
+World.instance.start
+app.exec
diff --git a/qtruby/rubylib/examples/testcases/bugs.rb b/qtruby/rubylib/examples/testcases/bugs.rb
new file mode 100644
index 00000000..6b5e3153
--- /dev/null
+++ b/qtruby/rubylib/examples/testcases/bugs.rb
@@ -0,0 +1,57 @@
+require 'Qt'
+
+
+#### TODO ###
+# dup of qobject crash
+def bug1
+ p1 = Qt::Point.new(5,5)
+ p1.setX 5
+ p p1
+ p3 = p1.dup
+ p3.setX 5
+ p p3
+end
+#bug1
+
+
+#### FIXED ###
+def bug3
+ a = Qt::Application.new(ARGV)
+ @file = Qt::PopupMenu.new
+ @file.insertSeparator
+ Qt::debug_level = Qt::DebugLevel::High
+ p $qApp
+ @file.insertItem("Quit", $qApp, SLOT('quit()'))
+ @file.exec
+end
+#bug3
+
+
+class CPUWaster < Qt::Widget
+ def initialize(*k)
+ super(*k)
+ end
+ def draw
+ painter = Qt::Painter.new(self)
+ 0.upto(1000) { |i|
+ cw, ch = width, height
+ c = Qt::Color.new(rand(255), rand(255), rand(255))
+ x = rand(cw - 8)
+ y = rand(cw - 8)
+ w = rand(cw - x)
+ h = rand(cw - y)
+ brush = Qt::Brush.new(c)
+ brush.setStyle(Qt::Dense6Pattern)
+ Qt::debug_level = Qt::DebugLevel::High
+ painter.fillRect(Qt::Rect.new(x, y, w, h), brush)
+ Qt::debug_level = Qt::DebugLevel::Off
+ }
+ end
+end
+def bug4
+ Qt::Application.new(ARGV)
+ w = CPUWaster.new
+ w.show
+ w.draw
+end
+bug4
diff --git a/qtruby/rubylib/examples/testcases/error_reporting.rb b/qtruby/rubylib/examples/testcases/error_reporting.rb
new file mode 100644
index 00000000..e2012447
--- /dev/null
+++ b/qtruby/rubylib/examples/testcases/error_reporting.rb
@@ -0,0 +1,85 @@
+require 'Qt'
+
+#### CRASH ###
+# param mismatch?
+class Bug1 < Qt::PushButton
+ def initialize(*k)
+ super(*k)
+ end
+ def Bug1.test
+ a = Qt::Application.new(ARGV)
+ w = Qt::VBox.new
+ hello = Bug1.new(a)
+ hello.resize(100, 30)
+ a.setMainWidget(w)
+ hello.show()
+ a.exec()
+ end
+end
+#Bug1.test
+
+
+#### MORE DEBUG INFO NEEDED ###
+# missing method
+class Bug2 < Qt::VBox
+ def initialize(*k)
+ super(*k)
+ end
+ def Bug2.test
+ a = Qt::Application.new(ARGV)
+ w = Bug2.new
+ a.setMainWidget(w)
+ w.show2()
+ a.exec()
+ end
+end
+#Bug2.test
+
+
+#### MORE DEBUG INFO NEEDED ###
+# missing prototype
+class Bug2a < Qt::VBox
+ def initialize(*k)
+ super(*k)
+ end
+ def Bug2a.test
+ a = Qt::Application.new(ARGV)
+ w = Bug2a.new
+ a.setMainWidget(w)
+ w.show(p)
+ a.exec()
+ end
+end
+Bug2a.test
+
+
+#### FIXED ###
+# no such constructor for PushButton
+class Bug3 < Qt::PushButton
+ def initialize
+ super
+ end
+ def Bug3.test
+ a = Qt::Application.new(ARGV)
+ hello = Bug3.new
+ hello.resize(100, 30)
+ a.setMainWidget(hello)
+ hello.show()
+ a.exec()
+ end
+end
+#Bug3.test
+
+
+#### FIXED ###
+# no *class* variable/method resize in PushButton
+class Bug4 < Qt::PushButton
+ def initialize
+ super
+ end
+ def Bug4.test
+ hello = Bug4
+ hello.resize(100, 30)
+ end
+end
+#Bug4.test
diff --git a/qtruby/rubylib/examples/testcases/opoverloading.rb b/qtruby/rubylib/examples/testcases/opoverloading.rb
new file mode 100644
index 00000000..1798a995
--- /dev/null
+++ b/qtruby/rubylib/examples/testcases/opoverloading.rb
@@ -0,0 +1,46 @@
+require 'Qt'
+
+class Qt::Point
+ def to_s
+ "(#{x}, #{y})"
+ end
+end
+
+$t = binding
+def test(str)
+ puts "#{str.ljust 25} => #{eval(str, $t)}"
+end
+
+test("p1 = Qt::Point.new(5,5)")
+test("p2 = Qt::Point.new(20,20)")
+test("p1 + p2")
+test("p1 - p2")
+test("-p1 + p2")
+test("p2 += p1")
+test("p2 -= p1")
+test("p2 * 3")
+
+class Qt::Region
+ def to_s
+ "(#{isNull})"
+ end
+end
+
+test("r1 = Qt::Region.new()")
+test("r2 = Qt::Region.new( 100,100,200,80, Qt::Region::Ellipse )")
+test("r1 + r2")
+
+class Qt::WMatrix
+ def to_s
+ "(#{m11}, #{m12}, #{m21}, #{m22}, #{dx}, #{dy})"
+ end
+end
+
+test("a = Math::PI/180 * 25") # convert 25 to radians
+test("sina = Math.sin(a)")
+test("cosa = Math.cos(a)")
+test("m1 = Qt::WMatrix.new(1, 0, 0, 1, 10, -20)") # translation matrix
+test("m2 = Qt::WMatrix.new( cosa, sina, -sina, cosa, 0, 0 )")
+test("m3 = Qt::WMatrix.new(1.2, 0, 0, 0.7, 0, 0)") # scaling matrix
+test("m = Qt::WMatrix.new")
+test("m = m3 * m2 * m1") # combine all transformations
diff --git a/qtruby/rubylib/examples/textedit/textedit.rb b/qtruby/rubylib/examples/textedit/textedit.rb
new file mode 100644
index 00000000..db905b4f
--- /dev/null
+++ b/qtruby/rubylib/examples/textedit/textedit.rb
@@ -0,0 +1,150 @@
+#!/usr/bin/ruby -w
+
+require 'Qt'
+require 'rexml/document'
+
+require '../base/rui.rb'
+
+class MyTextEditor < Qt::TextEdit
+ signals 'saved()'
+ slots 'insert_icon()', 'new()', 'open()', 'save_as()'
+ def initialize(w = nil)
+ @images = {}
+ @@next_image_id = 0
+ super(w)
+ self.setTextFormat(Qt::RichText)
+ end
+ def insert_richtext(richtext)
+ # todo, use a rand string
+ unique_string = '000___xxx123456789xxx___xxx123456789xxx___000'
+ insert(unique_string)
+ txt = self.text().gsub(unique_string, richtext)
+ self.setText(txt)
+ end
+ def next_image_id
+ @@next_image_id += 1
+ end
+ def load_image(fname, image_id)
+ pixmap = Qt::Pixmap.new(fname)
+ msfactory = Qt::MimeSourceFactory.defaultFactory
+ msfactory.setPixmap(image_id, pixmap)
+ @images[image_id] = fname
+ image_id
+ end
+ def insert_icon
+ fname = Qt::FileDialog.getOpenFileName
+ return if fname.nil?
+ image_id = "image_#{next_image_id}"
+ load_image(fname, image_id)
+ insert_richtext('<qt><img source="'+image_id+'"></qt>')
+ end
+ def createPopupMenu(pos) # virtual
+ pm = Qt::PopupMenu.new
+ pm.insertItem("Insert Image!", self, SLOT('insert_icon()'))
+ pm
+ end
+ def has_metadata
+ !@images.empty?
+ end
+ def metadata_fname(fname)
+ "#{fname}.metadata.xml"
+ end
+ def attempt_metadata_load(fname)
+ return unless File.exists?(metadata_fname(fname))
+ file = File.open(metadata_fname(fname))
+ @xmldoc = REXML::Document.new file
+ @xmldoc.root.elements.each("image") {
+ |image|
+ image_id = image.attributes["ident"]
+ img_fname = image.attributes["filename"]
+ load_image(img_fname, image_id)
+ }
+ end
+ def metadata_save_if_has(fname)
+ return if not has_metadata
+ metadata_doc = REXML::Document.new '<metadata/>'
+ @images.each {
+ |id, img_fname|
+ metadata_doc.root.add_element("image", {"filename"=>img_fname, "ident"=>id})
+ }
+ file = File.new(metadata_fname(fname), "w")
+ file.puts(metadata_doc)
+ file.close
+ end
+ def metadata_clear
+ @images = {}
+ end
+ def new(txt = "")
+ metadata_clear
+ self.setText(txt)
+ end
+ def open
+ fname = Qt::FileDialog.getOpenFileName
+ return if fname.nil?
+ unless File.exists?(fname)
+ Qt::MessageBox.critical(self, "File Does Not Exist", "Sorry, unable to find the requested file!")
+ return
+ end
+ return if fname.nil?
+ txt = File.open(fname).gets(nil)
+ metadata_clear
+ attempt_metadata_load(fname)
+ self.setText(txt)
+ end
+ def save_as
+ fname = Qt::FileDialog.getSaveFileName
+ return if fname.nil?
+ if File.exists?(fname)
+ Qt::MessageBox.critical(self, "File Already Exists", "Sorry, file already exists. Please choose a non-existing filename!")
+ return save_as
+ end
+ file = File.new(fname, "w")
+ file.puts(text())
+ file.close
+ metadata_save_if_has(fname)
+ emit saved()
+ end
+end
+
+class MyWidget < Qt::MainWindow
+ slots 'text_changed()', 'saved()'
+ def initialize()
+ super
+ @editor = MyTextEditor.new(self)
+ connect(@editor, SIGNAL('textChanged()'), self, SLOT('text_changed()'))
+ connect(@editor, SIGNAL('saved()'), self, SLOT('saved()'))
+
+ fileTools = Qt::ToolBar.new(self, "file operations")
+ fileMenu = Qt::PopupMenu.new(self)
+
+ actions = [
+ RAction.new("&New", Icons::FILE_NEW, @editor, SLOT('new()'), [fileTools, fileMenu]),
+ RAction.new("&Open...", Icons::FILE_OPEN, @editor, SLOT('open()'), [fileTools, fileMenu]),
+ @save = RAction.new("Save &As...", Icons::FILE_SAVE_AS, @editor, SLOT('save_as()'), [fileTools, fileMenu]),
+ RSeperator.new([fileMenu]),
+ RAction.new("E&xit", Icons::EXIT, $qApp, SLOT('quit()'), [fileMenu])
+ ]
+
+ build_actions(actions)
+
+ menubar = Qt::MenuBar.new(self)
+ menubar.insertItem("&File", fileMenu)
+
+ self.setCentralWidget(@editor)
+ end
+ def saved
+ @save.action.setEnabled(false)
+ end
+ def text_changed
+ @save.action.setEnabled(true)
+ end
+end
+
+a = Qt::Application.new(ARGV)
+
+w = MyWidget.new
+w.show
+
+a.setMainWidget(w)
+a.exec()
+exit
diff --git a/qtruby/rubylib/qtruby/Makefile.am b/qtruby/rubylib/qtruby/Makefile.am
new file mode 100644
index 00000000..1df273bf
--- /dev/null
+++ b/qtruby/rubylib/qtruby/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES = -I$(top_srcdir)/smoke $(all_includes) -I$(RUBY_ARCHDIR)
+
+noinst_HEADERS = qtruby.h marshall.h smokeruby.h extconf.rb
+
+noinst_LTLIBRARIES = libqtrubyinternal.la
+libqtrubyinternal_la_SOURCES = Qt.cpp handlers.cpp
+libqtrubyinternal_la_METASOURCES = AUTO
+
+rubylibdir = $(RUBY_SITEARCHDIR)
+rubylib_LTLIBRARIES = qtruby.la
+qtruby_la_SOURCES =
+qtruby_la_LDFLAGS = -module $(all_libraries) -version-info 0:0:0
+qtruby_la_LIBADD = libqtrubyinternal.la $(LIB_QT) $(top_builddir)/smoke/qt/libsmokeqt.la
+
+SUBDIRS = lib
diff --git a/qtruby/rubylib/qtruby/Qt.cpp b/qtruby/rubylib/qtruby/Qt.cpp
new file mode 100644
index 00000000..a8415512
--- /dev/null
+++ b/qtruby/rubylib/qtruby/Qt.cpp
@@ -0,0 +1,2967 @@
+/***************************************************************************
+ Qt.cpp - description
+ -------------------
+ begin : Fri Jul 4 2003
+ copyright : (C) 2003-2004 by Richard Dale
+ email : Richard_Dale@tipitina.demon.co.uk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <qglobal.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qptrdict.h>
+#include <qintdict.h>
+#include <qapplication.h>
+#include <qmetaobject.h>
+#include <private/qucomextra_p.h>
+#include <qvariant.h>
+#include <qcursor.h>
+#include <qobjectlist.h>
+#include <qsignalslotimp.h>
+#include <qcstring.h>
+
+#undef DEBUG
+#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#ifndef __USE_XOPEN
+#define __USE_XOPEN
+#endif
+#ifdef _BOOL
+#define HAS_BOOL
+#endif
+
+#include <ruby.h>
+
+#ifndef QT_VERSION_STR
+#define QT_VERSION_STR "Unknown"
+#endif
+
+#undef free
+#undef malloc
+
+#include "marshall.h"
+#include "qtruby.h"
+#include "smokeruby.h"
+#include "smoke.h"
+
+// #define DEBUG
+
+#define QTRUBY_VERSION "1.0.13"
+
+extern Smoke *qt_Smoke;
+extern void init_qt_Smoke();
+extern void smokeruby_mark(void * ptr);
+extern void smokeruby_free(void * ptr);
+extern VALUE qchar_to_s(VALUE self);
+
+#ifdef DEBUG
+int do_debug = qtdb_gc;
+#else
+int do_debug = qtdb_none;
+#endif
+
+QPtrDict<VALUE> pointer_map(2179);
+int object_count = 0;
+
+QAsciiDict<Smoke::Index> methcache(2179);
+QAsciiDict<Smoke::Index> classcache(2179);
+// Maps from a classname in the form Qt::Widget to an int id
+QIntDict<char> classname(2179);
+
+extern "C" {
+VALUE qt_module = Qnil;
+VALUE qext_scintilla_module = Qnil;
+VALUE kde_module = Qnil;
+VALUE kparts_module = Qnil;
+VALUE kio_module = Qnil;
+VALUE kns_module = Qnil;
+VALUE dom_module = Qnil;
+VALUE kontact_module = Qnil;
+VALUE kate_module = Qnil;
+VALUE ktexteditor_module = Qnil;
+VALUE koffice_module = Qnil;
+VALUE qt_internal_module = Qnil;
+VALUE qt_base_class = Qnil;
+VALUE qmetaobject_class = Qnil;
+VALUE qvariant_class = Qnil;
+VALUE kconfigskeleton_class = Qnil;
+VALUE kconfigskeleton_itemenum_class = Qnil;
+VALUE kconfigskeleton_itemenum_choice_class = Qnil;
+VALUE kio_udsatom_class = Qnil;
+VALUE kwin_class = Qnil;
+VALUE konsole_part_class = Qnil;
+bool application_terminated = false;
+};
+
+#define logger logger_backend
+void rb_str_catf(VALUE self, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+static VALUE (*_new_kde)(int, VALUE *, VALUE) = 0;
+static VALUE (*_kconfigskeletonitem_immutable)(VALUE) = 0;
+
+Smoke::Index _current_method = 0;
+
+extern TypeHandler Qt_handlers[];
+void install_handlers(TypeHandler *);
+
+smokeruby_object *value_obj_info(VALUE ruby_value) { // ptr on success, null on fail
+ if (TYPE(ruby_value) != T_DATA) {
+ return 0;
+ }
+
+ smokeruby_object * o = 0;
+ Data_Get_Struct(ruby_value, smokeruby_object, o);
+ return o;
+}
+
+void *value_to_ptr(VALUE ruby_value) { // ptr on success, null on fail
+ smokeruby_object *o = value_obj_info(ruby_value);
+ return o;
+}
+
+VALUE getPointerObject(void *ptr);
+
+bool isQObject(Smoke *smoke, Smoke::Index classId) {
+ if(qstrcmp(smoke->classes[classId].className, "QObject") == 0)
+ return true;
+ for(Smoke::Index *p = smoke->inheritanceList + smoke->classes[classId].parents;
+ *p;
+ p++) {
+ if(isQObject(smoke, *p))
+ return true;
+ }
+ return false;
+}
+
+bool isDerivedFrom(Smoke *smoke, Smoke::Index classId, Smoke::Index baseId) {
+ if(classId == 0 && baseId == 0)
+ return false;
+ if(classId == baseId)
+ return true;
+ for(Smoke::Index *p = smoke->inheritanceList + smoke->classes[classId].parents;
+ *p;
+ p++) {
+ if(isDerivedFrom(smoke, *p, baseId))
+ return true;
+ }
+ return false;
+}
+
+bool isDerivedFromByName(Smoke *smoke, const char *className, const char *baseClassName) {
+ if(!smoke || !className || !baseClassName)
+ return false;
+ Smoke::Index idClass = smoke->idClass(className);
+ Smoke::Index idBase = smoke->idClass(baseClassName);
+ return isDerivedFrom(smoke, idClass, idBase);
+}
+
+VALUE getPointerObject(void *ptr) {
+ if (pointer_map[ptr] == 0) {
+ return Qnil;
+ } else {
+ return *(pointer_map[ptr]);
+ }
+}
+
+void unmapPointer(smokeruby_object *o, Smoke::Index classId, void *lastptr) {
+ void *ptr = o->smoke->cast(o->ptr, o->classId, classId);
+ if(ptr != lastptr) {
+ lastptr = ptr;
+ if (pointer_map[ptr] != 0) {
+ VALUE * obj_ptr = pointer_map[ptr];
+
+ if (do_debug & qtdb_gc) {
+ const char *className = o->smoke->classes[o->classId].className;
+ qWarning("unmapPointer (%s*)%p -> %p", className, ptr, obj_ptr);
+ }
+
+ pointer_map.remove(ptr);
+ free((void*) obj_ptr);
+ }
+ }
+ for(Smoke::Index *i = o->smoke->inheritanceList + o->smoke->classes[classId].parents;
+ *i;
+ i++) {
+ unmapPointer(o, *i, lastptr);
+ }
+}
+
+// Store pointer in pointer_map hash : "pointer_to_Qt_object" => weak ref to associated Ruby object
+// Recurse to store it also as casted to its parent classes.
+
+void mapPointer(VALUE obj, smokeruby_object *o, Smoke::Index classId, void *lastptr) {
+ void *ptr = o->smoke->cast(o->ptr, o->classId, classId);
+
+ if (ptr != lastptr) {
+ lastptr = ptr;
+ VALUE * obj_ptr = (VALUE *) malloc(sizeof(VALUE));
+ memcpy(obj_ptr, &obj, sizeof(VALUE));
+
+ if (do_debug & qtdb_gc) {
+ const char *className = o->smoke->classes[o->classId].className;
+ qWarning("mapPointer (%s*)%p -> %p", className, ptr, (void*)obj);
+ }
+
+ pointer_map.insert(ptr, obj_ptr);
+ }
+
+ for(Smoke::Index *i = o->smoke->inheritanceList + o->smoke->classes[classId].parents;
+ *i;
+ i++) {
+ mapPointer(obj, o, *i, lastptr);
+ }
+
+ return;
+}
+
+Marshall::HandlerFn getMarshallFn(const SmokeType &type);
+
+class VirtualMethodReturnValue : public Marshall {
+ Smoke *_smoke;
+ Smoke::Index _method;
+ Smoke::Stack _stack;
+ SmokeType _st;
+ VALUE _retval;
+public:
+ const Smoke::Method &method() { return _smoke->methods[_method]; }
+ SmokeType type() { return _st; }
+ Marshall::Action action() { return Marshall::FromVALUE; }
+ Smoke::StackItem &item() { return _stack[0]; }
+ VALUE * var() { return &_retval; }
+
+ void unsupported() {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as return-type of virtual method %s::%s",
+ type().name(),
+ _smoke->className(method().classId),
+ _smoke->methodNames[method().name]);
+ }
+
+ Smoke *smoke() { return _smoke; }
+ void next() {}
+ bool cleanup() { return false; }
+
+ VirtualMethodReturnValue(Smoke *smoke, Smoke::Index meth, Smoke::Stack stack, VALUE retval) :
+ _smoke(smoke), _method(meth), _stack(stack), _retval(retval) {
+ _st.set(_smoke, method().ret);
+ Marshall::HandlerFn fn = getMarshallFn(type());
+ (*fn)(this);
+ }
+};
+
+class VirtualMethodCall : public Marshall {
+ Smoke *_smoke;
+ Smoke::Index _method;
+ Smoke::Stack _stack;
+ VALUE _obj;
+ int _cur;
+ Smoke::Index *_args;
+ VALUE *_sp;
+ bool _called;
+
+public:
+ SmokeType type() { return SmokeType(_smoke, _args[_cur]); }
+ Marshall::Action action() { return Marshall::ToVALUE; }
+ Smoke::StackItem &item() { return _stack[_cur + 1]; }
+ VALUE * var() { return _sp + _cur; }
+ const Smoke::Method &method() { return _smoke->methods[_method]; }
+ void unsupported() {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as argument of virtual method %s::%s",
+ type().name(),
+ _smoke->className(method().classId),
+ _smoke->methodNames[method().name]);
+ }
+ Smoke *smoke() { return _smoke; }
+ void callMethod() {
+ if(_called) return;
+ _called = true;
+
+ VALUE _retval = rb_funcall2(_obj,
+ rb_intern(_smoke->methodNames[method().name]),
+ method().numArgs,
+ _sp );
+ VirtualMethodReturnValue r(_smoke, _method, _stack, _retval);
+ }
+
+ void next() {
+ int oldcur = _cur;
+ _cur++;
+ while(!_called && _cur < method().numArgs) {
+ Marshall::HandlerFn fn = getMarshallFn(type());
+ (*fn)(this);
+ _cur++;
+ }
+ callMethod();
+ _cur = oldcur;
+ }
+
+ bool cleanup() { return false; } // is this right?
+
+ VirtualMethodCall(Smoke *smoke, Smoke::Index meth, Smoke::Stack stack, VALUE obj) :
+ _smoke(smoke), _method(meth), _stack(stack), _obj(obj), _cur(-1), _sp(0), _called(false) {
+ _sp = (VALUE *) calloc(method().numArgs, sizeof(VALUE));
+
+ _args = _smoke->argumentList + method().args;
+ }
+
+ ~VirtualMethodCall() {
+ free(_sp);
+ }
+};
+
+class MethodReturnValue : public Marshall {
+ Smoke *_smoke;
+ Smoke::Index _method;
+ VALUE * _retval;
+ Smoke::Stack _stack;
+public:
+ MethodReturnValue(Smoke *smoke, Smoke::Index method, Smoke::Stack stack, VALUE * retval) :
+ _smoke(smoke), _method(method), _retval(retval), _stack(stack) {
+ Marshall::HandlerFn fn = getMarshallFn(type());
+ (*fn)(this);
+ }
+
+ const Smoke::Method &method() { return _smoke->methods[_method]; }
+ SmokeType type() { return SmokeType(_smoke, method().ret); }
+ Marshall::Action action() { return Marshall::ToVALUE; }
+ Smoke::StackItem &item() { return _stack[0]; }
+ VALUE * var() {
+ return _retval;
+ }
+ void unsupported() {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as return-type of %s::%s",
+ type().name(),
+ qstrcmp(_smoke->className(method().classId), "QGlobalSpace") == 0 ? "" : _smoke->className(method().classId),
+ _smoke->methodNames[method().name]);
+ }
+ Smoke *smoke() { return _smoke; }
+ void next() {}
+ bool cleanup() { return false; }
+};
+
+class MethodCall : public Marshall {
+ int _cur;
+ Smoke *_smoke;
+ Smoke::Stack _stack;
+ Smoke::Index _method;
+ Smoke::Index *_args;
+ VALUE _target;
+ void *_current_object;
+ Smoke::Index _current_object_class;
+ VALUE *_sp;
+ int _items;
+ VALUE _retval;
+ bool _called;
+public:
+ MethodCall(Smoke *smoke, Smoke::Index method, VALUE target, VALUE *sp, int items) :
+ _cur(-1), _smoke(smoke), _method(method), _target(target), _current_object(0), _sp(sp), _items(items), _called(false)
+ {
+
+ if (_target != Qnil) {
+ smokeruby_object *o = value_obj_info(_target);
+ if (o && o->ptr) {
+ _current_object = o->ptr;
+ _current_object_class = o->classId;
+ }
+ }
+
+ _args = _smoke->argumentList + _smoke->methods[_method].args;
+ _items = _smoke->methods[_method].numArgs;
+ _stack = new Smoke::StackItem[items + 1];
+ _retval = Qnil;
+ }
+
+ ~MethodCall() {
+ delete[] _stack;
+ }
+
+ SmokeType type() {
+ return SmokeType(_smoke, _args[_cur]);
+ }
+
+ Marshall::Action action() {
+ return Marshall::FromVALUE;
+ }
+ Smoke::StackItem &item() {
+ return _stack[_cur + 1];
+ }
+
+ VALUE * var() {
+ if(_cur < 0) return &_retval;
+ return _sp + _cur;
+ }
+
+ inline const Smoke::Method &method() {
+ return _smoke->methods[_method];
+ }
+
+ void unsupported() {
+ if (qstrcmp(_smoke->className(method().classId), "QGlobalSpace") == 0) {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as argument to %s",
+ type().name(),
+ _smoke->methodNames[method().name]);
+ } else {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as argument to %s::%s",
+ type().name(),
+ _smoke->className(method().classId),
+ _smoke->methodNames[method().name]);
+ }
+ }
+
+ Smoke *smoke() {
+ return _smoke;
+ }
+
+ inline void callMethod() {
+ if(_called) return;
+ _called = true;
+
+ QString className(_smoke->className(method().classId));
+
+ if ( ! className.endsWith(_smoke->methodNames[method().name])
+ && TYPE(_target) != T_DATA
+ && _target != Qnil
+ && !(method().flags & Smoke::mf_static) )
+ {
+ rb_raise(rb_eArgError, "Instance is not initialized, cannot call %s",
+ _smoke->methodNames[method().name]);
+ }
+
+ if (_target == Qnil && !(method().flags & Smoke::mf_static)) {
+ rb_raise(rb_eArgError, "%s is not a class method\n", _smoke->methodNames[method().name]);
+ }
+
+ Smoke::ClassFn fn = _smoke->classes[method().classId].classFn;
+ void *ptr = _smoke->cast(_current_object, _current_object_class, method().classId);
+ _items = -1;
+ (*fn)(method().method, ptr, _stack);
+ MethodReturnValue r(_smoke, _method, _stack, &_retval);
+ }
+
+ void next() {
+ int oldcur = _cur;
+ _cur++;
+
+ while(!_called && _cur < _items) {
+ Marshall::HandlerFn fn = getMarshallFn(type());
+ (*fn)(this);
+ _cur++;
+ }
+ callMethod();
+ _cur = oldcur;
+ }
+
+ bool cleanup() {
+ return true;
+ }
+};
+
+class UnencapsulatedQObject : public QObject {
+public:
+ QConnectionList *public_receivers(int signal) const { return receivers(signal); }
+ void public_activate_signal(QConnectionList *clist, QUObject *o) { activate_signal(clist, o); }
+};
+
+class EmitSignal : public Marshall {
+ UnencapsulatedQObject *_qobj;
+ int _id;
+ MocArgument *_args;
+ VALUE *_sp;
+ int _items;
+ int _cur;
+ Smoke::Stack _stack;
+ bool _called;
+public:
+ EmitSignal(QObject *qobj, int id, int items, VALUE args, VALUE *sp) :
+ _qobj((UnencapsulatedQObject*)qobj), _id(id), _sp(sp), _items(items),
+ _cur(-1), _called(false)
+ {
+ _items = NUM2INT(rb_ary_entry(args, 0));
+ Data_Get_Struct(rb_ary_entry(args, 1), MocArgument, _args);
+ _stack = new Smoke::StackItem[_items];
+ }
+ ~EmitSignal() {
+ delete[] _stack;
+ }
+ const MocArgument &arg() { return _args[_cur]; }
+ SmokeType type() { return arg().st; }
+ Marshall::Action action() { return Marshall::FromVALUE; }
+ Smoke::StackItem &item() { return _stack[_cur]; }
+ VALUE * var() { return _sp + _cur; }
+ void unsupported() {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as signal argument", type().name());
+ }
+ Smoke *smoke() { return type().smoke(); }
+ void emitSignal() {
+ if(_called) return;
+ _called = true;
+
+ QConnectionList *clist = _qobj->public_receivers(_id);
+ if(!clist) return;
+
+ QUObject *o = new QUObject[_items + 1];
+ for(int i = 0; i < _items; i++) {
+ QUObject *po = o + i + 1;
+ Smoke::StackItem *si = _stack + i;
+ switch(_args[i].argType) {
+ case xmoc_bool:
+ static_QUType_bool.set(po, si->s_bool);
+ break;
+ case xmoc_int:
+ static_QUType_int.set(po, si->s_int);
+ break;
+ case xmoc_double:
+ static_QUType_double.set(po, si->s_double);
+ break;
+ case xmoc_charstar:
+ static_QUType_charstar.set(po, (char*)si->s_voidp);
+ break;
+ case xmoc_QString:
+ static_QUType_QString.set(po, *(QString*)si->s_voidp);
+ break;
+ default:
+ {
+ const SmokeType &t = _args[i].st;
+ void *p;
+ switch(t.elem()) {
+ case Smoke::t_bool:
+ p = &si->s_bool;
+ break;
+ case Smoke::t_char:
+ p = &si->s_char;
+ break;
+ case Smoke::t_uchar:
+ p = &si->s_uchar;
+ break;
+ case Smoke::t_short:
+ p = &si->s_short;
+ break;
+ case Smoke::t_ushort:
+ p = &si->s_ushort;
+ break;
+ case Smoke::t_int:
+ p = &si->s_int;
+ break;
+ case Smoke::t_uint:
+ p = &si->s_uint;
+ break;
+ case Smoke::t_long:
+ p = &si->s_long;
+ break;
+ case Smoke::t_ulong:
+ p = &si->s_ulong;
+ break;
+ case Smoke::t_float:
+ p = &si->s_float;
+ break;
+ case Smoke::t_double:
+ p = &si->s_double;
+ break;
+ case Smoke::t_enum:
+ {
+ // allocate a new enum value
+ Smoke::EnumFn fn = SmokeClass(t).enumFn();
+ if(!fn) {
+ rb_warning("Unknown enumeration %s\n", t.name());
+ p = new int((int)si->s_enum);
+ break;
+ }
+ Smoke::Index id = t.typeId();
+ (*fn)(Smoke::EnumNew, id, p, si->s_enum);
+ (*fn)(Smoke::EnumFromLong, id, p, si->s_enum);
+ // FIXME: MEMORY LEAK
+ }
+ break;
+ case Smoke::t_class:
+ case Smoke::t_voidp:
+ p = si->s_voidp;
+ break;
+ default:
+ p = 0;
+ break;
+ }
+ static_QUType_ptr.set(po, p);
+ }
+ }
+ }
+
+ _qobj->public_activate_signal(clist, o);
+ delete[] o;
+ }
+ void next() {
+ int oldcur = _cur;
+ _cur++;
+
+ while(!_called && _cur < _items) {
+ Marshall::HandlerFn fn = getMarshallFn(type());
+ (*fn)(this);
+ _cur++;
+ }
+
+ emitSignal();
+ _cur = oldcur;
+ }
+ bool cleanup() { return true; }
+};
+
+class InvokeSlot : public Marshall {
+ VALUE _obj;
+ ID _slotname;
+ int _items;
+ MocArgument *_args;
+ QUObject *_o;
+ int _cur;
+ bool _called;
+ VALUE *_sp;
+ Smoke::Stack _stack;
+public:
+ const MocArgument &arg() { return _args[_cur]; }
+ SmokeType type() { return arg().st; }
+ Marshall::Action action() { return Marshall::ToVALUE; }
+ Smoke::StackItem &item() { return _stack[_cur]; }
+ VALUE * var() { return _sp + _cur; }
+ Smoke *smoke() { return type().smoke(); }
+ bool cleanup() { return false; }
+ void unsupported() {
+ rb_raise(rb_eArgError, "Cannot handle '%s' as slot argument\n", type().name());
+ }
+ void copyArguments() {
+ for(int i = 0; i < _items; i++) {
+ QUObject *o = _o + i + 1;
+ switch(_args[i].argType) {
+ case xmoc_bool:
+ _stack[i].s_bool = static_QUType_bool.get(o);
+ break;
+ case xmoc_int:
+ _stack[i].s_int = static_QUType_int.get(o);
+ break;
+ case xmoc_double:
+ _stack[i].s_double = static_QUType_double.get(o);
+ break;
+ case xmoc_charstar:
+ _stack[i].s_voidp = static_QUType_charstar.get(o);
+ break;
+ case xmoc_QString:
+ _stack[i].s_voidp = &static_QUType_QString.get(o);
+ break;
+ default: // case xmoc_ptr:
+ {
+ const SmokeType &t = _args[i].st;
+ void *p = static_QUType_ptr.get(o);
+ switch(t.elem()) {
+ case Smoke::t_bool:
+ _stack[i].s_bool = *(bool*)p;
+ break;
+ case Smoke::t_char:
+ _stack[i].s_char = *(char*)p;
+ break;
+ case Smoke::t_uchar:
+ _stack[i].s_uchar = *(unsigned char*)p;
+ break;
+ case Smoke::t_short:
+ _stack[i].s_short = *(short*)p;
+ break;
+ case Smoke::t_ushort:
+ _stack[i].s_ushort = *(unsigned short*)p;
+ break;
+ case Smoke::t_int:
+ _stack[i].s_int = *(int*)p;
+ break;
+ case Smoke::t_uint:
+ _stack[i].s_uint = *(unsigned int*)p;
+ break;
+ case Smoke::t_long:
+ _stack[i].s_long = *(long*)p;
+ break;
+ case Smoke::t_ulong:
+ _stack[i].s_ulong = *(unsigned long*)p;
+ break;
+ case Smoke::t_float:
+ _stack[i].s_float = *(float*)p;
+ break;
+ case Smoke::t_double:
+ _stack[i].s_double = *(double*)p;
+ break;
+ case Smoke::t_enum:
+ {
+ Smoke::EnumFn fn = SmokeClass(t).enumFn();
+ if(!fn) {
+ rb_warning("Unknown enumeration %s\n", t.name());
+ _stack[i].s_enum = *(int*)p;
+ break;
+ }
+ Smoke::Index id = t.typeId();
+ (*fn)(Smoke::EnumToLong, id, p, _stack[i].s_enum);
+ }
+ break;
+ case Smoke::t_class:
+ case Smoke::t_voidp:
+ _stack[i].s_voidp = p;
+ break;
+ }
+ }
+ }
+ }
+ }
+ void invokeSlot() {
+ if(_called) return;
+ _called = true;
+
+ (void) rb_funcall2(_obj, _slotname, _items, _sp);
+ }
+
+ void next() {
+ int oldcur = _cur;
+ _cur++;
+
+ while(!_called && _cur < _items) {
+ Marshall::HandlerFn fn = getMarshallFn(type());
+ (*fn)(this);
+ _cur++;
+ }
+
+ invokeSlot();
+ _cur = oldcur;
+ }
+
+ InvokeSlot(VALUE obj, ID slotname, VALUE args, QUObject *o) :
+ _obj(obj), _slotname(slotname), _o(o), _cur(-1), _called(false)
+ {
+ _items = NUM2INT(rb_ary_entry(args, 0));
+ Data_Get_Struct(rb_ary_entry(args, 1), MocArgument, _args);
+ _sp = (VALUE *) calloc(_items, sizeof(VALUE));
+ _stack = new Smoke::StackItem[_items];
+ copyArguments();
+ }
+
+ ~InvokeSlot() {
+ delete[] _stack;
+ free(_sp);
+ }
+};
+
+class QtRubySmokeBinding : public SmokeBinding {
+public:
+ QtRubySmokeBinding(Smoke *s) : SmokeBinding(s) {}
+
+ void deleted(Smoke::Index classId, void *ptr) {
+ VALUE obj = getPointerObject(ptr);
+ smokeruby_object *o = value_obj_info(obj);
+ if(do_debug & qtdb_gc) {
+ qWarning("%p->~%s()", ptr, smoke->className(classId));
+ }
+ if(!o || !o->ptr) {
+ return;
+ }
+ unmapPointer(o, o->classId, 0);
+ o->ptr = 0;
+ }
+
+ bool callMethod(Smoke::Index method, void *ptr, Smoke::Stack args, bool /*isAbstract*/) {
+ VALUE obj = getPointerObject(ptr);
+ smokeruby_object *o = value_obj_info(obj);
+
+ if (do_debug & qtdb_virtual) {
+ Smoke::Method & meth = smoke->methods[method];
+ QCString signature(smoke->methodNames[meth.name]);
+ signature += "(";
+
+ for (int i = 0; i < meth.numArgs; i++) {
+ if (i != 0) signature += ", ";
+ signature += smoke->types[smoke->argumentList[meth.args + i]].name;
+ }
+
+ signature += ")";
+ if (meth.flags & Smoke::mf_const) {
+ signature += " const";
+ }
+
+ qWarning( "virtual %p->%s::%s called",
+ ptr,
+ smoke->classes[smoke->methods[method].classId].className,
+ (const char *) signature );
+ }
+
+ if(!o) {
+ if( do_debug & qtdb_virtual ) // if not in global destruction
+ qWarning("Cannot find object for virtual method %p -> %p", ptr, &obj);
+ return false;
+ }
+
+ const char *methodName = smoke->methodNames[smoke->methods[method].name];
+
+ // If the virtual method hasn't been overriden, just call the C++ one.
+ if (rb_respond_to(obj, rb_intern(methodName)) == 0) {
+ return false;
+ }
+
+ VirtualMethodCall c(smoke, method, args, obj);
+ c.next();
+ return true;
+ }
+
+ char *className(Smoke::Index classId) {
+ return classname.find((int) classId);
+ }
+};
+
+void rb_str_catf(VALUE self, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ char *p = 0;
+ int len;
+ if (len = vasprintf(&p, format, ap), len != -1) {
+ rb_str_cat(self, p, len);
+ free(p);
+ }
+ va_end(ap);
+}
+
+extern "C" {
+
+static VALUE
+qdebug(VALUE klass, VALUE msg)
+{
+ qDebug("%s", StringValuePtr(msg));
+ return klass;
+}
+
+static VALUE
+qfatal(VALUE klass, VALUE msg)
+{
+ qFatal("%s", StringValuePtr(msg));
+ return klass;
+}
+
+static VALUE
+qwarning(VALUE klass, VALUE msg)
+{
+ qWarning("%s", StringValuePtr(msg));
+ return klass;
+}
+
+// ---------------- Helpers -------------------
+
+//---------- All functions except fully qualified statics & enums ---------
+
+static VALUE qobject_metaobject(VALUE self);
+static VALUE kde_package_to_class(const char * package, VALUE base_class);
+
+VALUE
+set_obj_info(const char * className, smokeruby_object * o)
+{
+ VALUE klass = rb_funcall(qt_internal_module,
+ rb_intern("find_class"),
+ 1,
+ rb_str_new2(className) );
+
+ Smoke::Index *r = classcache.find(className);
+ if (r != 0) {
+ o->classId = (int)*r;
+ }
+
+ // If the instance is a subclass of QObject, then check to see if the
+ // className from its QMetaObject is in the Smoke library. If not then
+ // create a Ruby class for it dynamically. Remove the first letter from
+ // any class names beginning with 'Q' or 'K' and put them under the Qt::
+ // or KDE:: modules respectively.
+ if (isDerivedFrom(o->smoke, o->classId, o->smoke->idClass("QObject"))) {
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+ QMetaObject * meta = qobject->metaObject();
+ int classId = o->smoke->idClass(meta->className());
+ // The class isn't in the Smoke lib..
+ if (classId == 0) {
+ VALUE new_klass = Qnil;
+ QString className(meta->className());
+ // The konsolePart class is in kdebase, and so it can't be in the Smoke library.
+ // This hack instantiates a Ruby KDE::KonsolePart instance
+ if (className == "konsolePart") {
+ new_klass = konsole_part_class;
+ } else if (className.startsWith("Q")) {
+ className.replace("Q", "");
+ className = className.mid(0, 1).upper() + className.mid(1);
+ new_klass = rb_define_class_under(qt_module, className.latin1(), klass);
+ } else if (kde_module == Qnil) {
+ new_klass = rb_define_class(className.latin1(), klass);
+ } else {
+ new_klass = kde_package_to_class(className.latin1(), klass);
+ }
+
+ if (new_klass != Qnil) {
+ klass = new_klass;
+ }
+
+ // Add a Qt::Object.metaObject method which will do dynamic despatch on the
+ // metaObject() virtual method so that the true QMetaObject of the class
+ // is returned, rather than for the one for the parent class that is in
+ // the Smoke library.
+ rb_define_method(klass, "metaObject", (VALUE (*) (...)) qobject_metaobject, 0);
+ }
+ }
+
+ VALUE obj = Data_Wrap_Struct(klass, smokeruby_mark, smokeruby_free, (void *) o);
+ return obj;
+}
+
+static VALUE mapObject(VALUE self, VALUE obj);
+
+VALUE
+cast_object_to(VALUE /*self*/, VALUE object, VALUE new_klass)
+{
+ smokeruby_object *o = value_obj_info(object);
+
+ VALUE new_klassname = rb_funcall(new_klass, rb_intern("name"), 0);
+
+ Smoke::Index * cast_to_id = classcache.find(StringValuePtr(new_klassname));
+ if (cast_to_id == 0) {
+ rb_raise(rb_eArgError, "unable to find class \"%s\" to cast to\n", StringValuePtr(new_klassname));
+ }
+
+ smokeruby_object *o_cast = (smokeruby_object *) malloc(sizeof(smokeruby_object));
+ memcpy(o_cast, o, sizeof(smokeruby_object));
+
+ o_cast->allocated = o->allocated;
+ o->allocated = false;
+
+ o_cast->classId = (int) *cast_to_id;
+ o_cast->ptr = o->smoke->cast(o->ptr, o->classId, o_cast->classId);
+
+ VALUE obj = Data_Wrap_Struct(new_klass, smokeruby_mark, smokeruby_free, (void *) o_cast);
+ mapPointer(obj, o_cast, o_cast->classId, 0);
+ return obj;
+}
+
+const char *
+get_VALUEtype(VALUE ruby_value)
+{
+ char * classname = rb_obj_classname(ruby_value);
+ const char *r = "";
+ if(ruby_value == Qnil)
+ r = "u";
+ else if(TYPE(ruby_value) == T_FIXNUM || TYPE(ruby_value) == T_BIGNUM || qstrcmp(classname, "Qt::Integer") == 0)
+ r = "i";
+ else if(TYPE(ruby_value) == T_FLOAT)
+ r = "n";
+ else if(TYPE(ruby_value) == T_STRING)
+ r = "s";
+ else if(ruby_value == Qtrue || ruby_value == Qfalse || qstrcmp(classname, "Qt::Boolean") == 0)
+ r = "B";
+ else if(qstrcmp(classname, "Qt::Enum") == 0) {
+ VALUE temp = rb_funcall(qt_internal_module, rb_intern("get_qenum_type"), 1, ruby_value);
+ r = StringValuePtr(temp);
+ } else if(TYPE(ruby_value) == T_DATA) {
+ smokeruby_object *o = value_obj_info(ruby_value);
+ if(!o) {
+ r = "a";
+ } else {
+ r = o->smoke->classes[o->classId].className;
+ }
+ }
+ else {
+ r = "U";
+ }
+
+ return r;
+}
+
+VALUE prettyPrintMethod(Smoke::Index id)
+{
+ VALUE r = rb_str_new2("");
+ Smoke::Method &meth = qt_Smoke->methods[id];
+ const char *tname = qt_Smoke->types[meth.ret].name;
+ if(meth.flags & Smoke::mf_static) rb_str_catf(r, "static ");
+ rb_str_catf(r, "%s ", (tname ? tname:"void"));
+ rb_str_catf(r, "%s::%s(", qt_Smoke->classes[meth.classId].className, qt_Smoke->methodNames[meth.name]);
+ for(int i = 0; i < meth.numArgs; i++) {
+ if(i) rb_str_catf(r, ", ");
+ tname = qt_Smoke->types[qt_Smoke->argumentList[meth.args+i]].name;
+ rb_str_catf(r, "%s", (tname ? tname:"void"));
+ }
+ rb_str_catf(r, ")");
+ if(meth.flags & Smoke::mf_const) rb_str_catf(r, " const");
+ return r;
+}
+
+//---------- Ruby methods (for all functions except fully qualified statics & enums) ---------
+
+// Used to display debugging info about the signals a Qt::Object has connected.
+// Returns a Hash with keys of the signals names, and values of Arrays of
+// Qt::Connections for the target slots
+static VALUE
+receivers_qobject(VALUE self)
+{
+ if (TYPE(self) != T_DATA) {
+ return Qnil;
+ }
+
+ smokeruby_object * o = 0;
+ Data_Get_Struct(self, smokeruby_object, o);
+ UnencapsulatedQObject * qobject = (UnencapsulatedQObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+ VALUE result = rb_hash_new();
+ QStrList signalNames = qobject->metaObject()->signalNames(true);
+
+ for (int sig = 0; sig < qobject->metaObject()->numSignals(true); sig++) {
+ QConnectionList * clist = qobject->public_receivers(sig);
+ if (clist != 0) {
+ VALUE name = rb_str_new2(signalNames.at(sig));
+ VALUE members = rb_ary_new();
+
+ for ( QConnection * connection = clist->first();
+ connection != 0;
+ connection = clist->next() )
+ {
+ VALUE obj = getPointerObject(connection);
+ if (obj == Qnil) {
+ smokeruby_object * c = ALLOC(smokeruby_object);
+ c->classId = o->smoke->idClass("QConnection");
+ c->smoke = o->smoke;
+ c->ptr = connection;
+ c->allocated = false;
+ obj = set_obj_info("Qt::Connection", c);
+ }
+
+ rb_ary_push(members, obj);
+ }
+
+ rb_hash_aset(result, name, members);
+ }
+ }
+
+ return result;
+}
+
+// Takes a variable name and a QProperty with QVariant value, and returns a '
+// variable=value' pair with the value in ruby inspect style
+static QCString
+inspectProperty(Smoke * smoke, const QMetaProperty * property, const char * name, QVariant & value)
+{
+ if (property->isEnumType()) {
+ QMetaObject * metaObject = *(property->meta);
+ return QCString().sprintf( " %s=%s::%s",
+ name,
+ smoke->binding->className(smoke->idClass(metaObject->className())),
+ property->valueToKey(value.toInt()) );
+ }
+
+ switch (value.type()) {
+ case QVariant::String:
+ case QVariant::CString:
+ {
+ if (value.toString().isNull()) {
+ return QCString().sprintf(" %s=nil", name);
+ } else {
+ return QCString().sprintf( " %s=\"%s\"",
+ name,
+ value.toString().latin1() );
+ }
+ }
+
+ case QVariant::Bool:
+ {
+ QString rubyName;
+ QRegExp name_re("^(is|has)(.)(.*)");
+
+ if (name_re.search(name) != -1) {
+ rubyName = name_re.cap(2).lower() + name_re.cap(3) + "?";
+ } else {
+ rubyName = name;
+ }
+
+ return QCString().sprintf(" %s=%s", rubyName.latin1(), value.toString().latin1());
+ }
+
+ case QVariant::Color:
+ {
+ QColor c = value.toColor();
+ return QCString().sprintf(" %s=#<Qt::Color:0x0 %s>", name, c.name().latin1());
+ }
+
+ case QVariant::Cursor:
+ {
+ QCursor c = value.toCursor();
+ return QCString().sprintf(" %s=#<Qt::Cursor:0x0 shape=%d>", name, c.shape());
+ }
+
+ case QVariant::Double:
+ {
+ return QCString().sprintf(" %s=%.4f", name, value.toDouble());
+ }
+
+ case QVariant::Font:
+ {
+ QFont f = value.toFont();
+ return QCString().sprintf( " %s=#<Qt::Font:0x0 family=%s, pointSize=%d, weight=%d, italic=%s, bold=%s, underline=%s, strikeOut=%s>",
+ name,
+ f.family().latin1(), f.pointSize(), f.weight(),
+ f.italic() ? "true" : "false", f.bold() ? "true" : "false",
+ f.underline() ? "true" : "false", f.strikeOut() ? "true" : "false" );
+ }
+
+ case QVariant::Point:
+ {
+ QPoint p = value.toPoint();
+ return QCString().sprintf( " %s=#<Qt::Point:0x0 x=%d, y=%d>",
+ name,
+ p.x(), p.y() );
+ }
+
+ case QVariant::Rect:
+ {
+ QRect r = value.toRect();
+ return QCString().sprintf( " %s=#<Qt::Rect:0x0 left=%d, right=%d, top=%d, bottom=%d>",
+ name,
+ r.left(), r.right(), r.top(), r.bottom() );
+ }
+
+ case QVariant::Size:
+ {
+ QSize s = value.toSize();
+ return QCString().sprintf( " %s=#<Qt::Size:0x0 width=%d, height=%d>",
+ name,
+ s.width(), s.height() );
+ }
+
+ case QVariant::SizePolicy:
+ {
+ QSizePolicy s = value.toSizePolicy();
+ return QCString().sprintf( " %s=#<Qt::SizePolicy:0x0 horData=%d, verData=%d>",
+ name,
+ s.horData(), s.verData() );
+ }
+
+ case QVariant::Brush:
+ case QVariant::ColorGroup:
+ case QVariant::Image:
+ case QVariant::Palette:
+ case QVariant::Pixmap:
+ case QVariant::Region:
+ {
+ return QCString().sprintf(" %s=#<Qt::%s:0x0>", name, value.typeName() + 1);
+ }
+
+ default:
+ return QCString().sprintf( " %s=%s",
+ name,
+ (value.isNull() || value.toString().isNull()) ? "nil" : value.toString().latin1() );
+ }
+}
+
+// Retrieves the properties for a QObject and returns them as 'name=value' pairs
+// in a ruby inspect string. For example:
+//
+// #<Qt::HBoxLayout:0x30139030 name=unnamed, margin=0, spacing=0, resizeMode=3>
+//
+static VALUE
+inspect_qobject(VALUE self)
+{
+ if (TYPE(self) != T_DATA) {
+ return Qnil;
+ }
+
+ // Start with #<Qt::HBoxLayout:0x30139030> from the original inspect() call
+ // Drop the closing '>'
+ VALUE inspect_str = rb_call_super(0, 0);
+ rb_str_resize(inspect_str, RSTRING(inspect_str)->len - 1);
+
+ smokeruby_object * o = 0;
+ Data_Get_Struct(self, smokeruby_object, o);
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+
+ QCString value_list;
+ value_list.append(QCString().sprintf(" name=\"%s\"", qobject->name()));
+
+ if (qobject->isWidgetType()) {
+ QWidget * w = (QWidget *) qobject;
+ value_list.append(QCString().sprintf( ", x=%d, y=%d, width=%d, height=%d",
+ w->x(),
+ w->y(),
+ w->width(),
+ w->height() ) );
+ }
+
+ value_list.append(">");
+ rb_str_cat(inspect_str, value_list.data(), strlen(value_list.data()));
+
+ return inspect_str;
+}
+
+// Retrieves the properties for a QObject and pretty_prints them as 'name=value' pairs
+// For example:
+//
+// #<Qt::HBoxLayout:0x30139030
+// name=unnamed,
+// margin=0,
+// spacing=0,
+// resizeMode=3>
+//
+static VALUE
+pretty_print_qobject(VALUE self, VALUE pp)
+{
+ if (TYPE(self) != T_DATA) {
+ return Qnil;
+ }
+
+ // Start with #<Qt::HBoxLayout:0x30139030>
+ // Drop the closing '>'
+ VALUE inspect_str = rb_funcall(self, rb_intern("to_s"), 0, 0);
+ rb_str_resize(inspect_str, RSTRING(inspect_str)->len - 1);
+ rb_funcall(pp, rb_intern("text"), 1, inspect_str);
+ rb_funcall(pp, rb_intern("breakable"), 0);
+
+ smokeruby_object * o = 0;
+ Data_Get_Struct(self, smokeruby_object, o);
+ UnencapsulatedQObject * qobject = (UnencapsulatedQObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+ QStrList names = qobject->metaObject()->propertyNames(true);
+
+ QCString value_list;
+
+ if (qobject->parent() != 0) {
+ QCString parentInspectString;
+ VALUE obj = getPointerObject(qobject->parent());
+ if (obj != Qnil) {
+ VALUE parent_inspect_str = rb_funcall(obj, rb_intern("to_s"), 0, 0);
+ rb_str_resize(parent_inspect_str, RSTRING(parent_inspect_str)->len - 1);
+ parentInspectString = StringValuePtr(parent_inspect_str);
+ } else {
+ parentInspectString.sprintf("#<%s:0x0", qobject->parent()->className());
+ }
+
+ if (qobject->parent()->isWidgetType()) {
+ QWidget * w = (QWidget *) qobject->parent();
+ value_list = QCString().sprintf( " parent=%s name=\"%s\", x=%d, y=%d, width=%d, height=%d>,\n",
+ parentInspectString.data(),
+ w->name(),
+ w->x(),
+ w->y(),
+ w->width(),
+ w->height() );
+ } else {
+ value_list = QCString().sprintf( " parent=%s name=\"%s\">,\n",
+ parentInspectString.data(),
+ qobject->parent()->name() );
+ }
+
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(value_list.data()));
+ }
+
+ if (qobject->children() != 0) {
+ value_list = QCString().sprintf(" children=Array (%d element(s)),\n", qobject->children()->count());
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(value_list.data()));
+ }
+
+ value_list = QCString(" metaObject=#<Qt::MetaObject:0x0");
+ value_list.append(QCString().sprintf(" className=%s", qobject->metaObject()->className()));
+
+ if (qobject->metaObject()->superClass() != 0) {
+ value_list.append(QCString().sprintf(", superClass=#<Qt::MetaObject:0x0>", qobject->metaObject()->superClass()));
+ }
+
+ if (qobject->metaObject()->numSignals() > 0) {
+ value_list.append(QCString().sprintf(", signalNames=Array (%d element(s))", qobject->metaObject()->numSignals()));
+ }
+
+ if (qobject->metaObject()->numSlots() > 0) {
+ value_list.append(QCString().sprintf(", slotNames=Array (%d element(s))", qobject->metaObject()->numSlots()));
+ }
+
+ value_list.append(">,\n");
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(value_list.data()));
+
+ int signalCount = 0;
+ for (int sig = 0; sig < qobject->metaObject()->numSignals(true); sig++) {
+ QConnectionList * clist = qobject->public_receivers(sig);
+ if (clist != 0) {
+ signalCount++;
+ }
+ }
+
+ if (signalCount > 0) {
+ value_list = QCString().sprintf(" receivers=Hash (%d element(s)),\n", signalCount);
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(value_list.data()));
+ }
+
+ int index = 0;
+ const char * name = names.first();
+
+ if (name != 0) {
+ QVariant value = qobject->property(name);
+ const QMetaProperty * property = qobject->metaObject()->property(index, true);
+ value_list = " " + inspectProperty(o->smoke, property, name, value);
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(value_list.data()));
+ index++;
+
+ for ( name = names.next();
+ name != 0;
+ name = names.next(), index++ )
+ {
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(",\n"));
+
+ value = qobject->property(name);
+ property = qobject->metaObject()->property(index, true);
+ value_list = " " + inspectProperty(o->smoke, property, name, value);
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(value_list.data()));
+ }
+ }
+
+ rb_funcall(pp, rb_intern("text"), 1, rb_str_new2(">"));
+
+ return self;
+}
+
+static VALUE
+metaObject(VALUE self)
+{
+ VALUE metaObject = rb_funcall(qt_internal_module, rb_intern("getMetaObject"), 1, self);
+ return metaObject;
+}
+
+static VALUE
+qobject_metaobject(VALUE self)
+{
+ smokeruby_object * o = value_obj_info(self);
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+ QMetaObject * meta = qobject->metaObject();
+ VALUE obj = getPointerObject(meta);
+ if (obj != Qnil) {
+ return obj;
+ }
+
+ smokeruby_object * m = (smokeruby_object *) malloc(sizeof(smokeruby_object));
+ m->smoke = o->smoke;
+ m->classId = m->smoke->idClass("QMetaObject");
+ m->ptr = meta;
+ m->allocated = false;
+ obj = set_obj_info("Qt::MetaObject", m);
+ return obj;
+}
+
+static VALUE
+new_qvariant(int argc, VALUE * argv, VALUE self)
+{
+static Smoke::Index new_qvariant_qlist = 0;
+static Smoke::Index new_qvariant_qmap = 0;
+
+ if (new_qvariant_qlist == 0) {
+ Smoke::Index nameId = qt_Smoke->idMethodName("QVariant?");
+ Smoke::Index meth = qt_Smoke->findMethod(qt_Smoke->idClass("QVariant"), nameId);
+ Smoke::Index i = qt_Smoke->methodMaps[meth].method;
+ i = -i; // turn into ambiguousMethodList index
+ while (qt_Smoke->ambiguousMethodList[i] != 0) {
+ const char * argType = qt_Smoke->types[qt_Smoke->argumentList[qt_Smoke->methods[qt_Smoke->ambiguousMethodList[i]].args]].name;
+
+ if (qstrcmp(argType, "const QValueList<QVariant>&" ) == 0) {
+ new_qvariant_qlist = qt_Smoke->ambiguousMethodList[i];
+ } else if (qstrcmp(argType, "const QMap<QString,QVariant>&" ) == 0) {
+ new_qvariant_qmap = qt_Smoke->ambiguousMethodList[i];
+ }
+
+ i++;
+ }
+ }
+
+ if (argc == 1 && TYPE(argv[0]) == T_HASH) {
+ _current_method = new_qvariant_qmap;
+ MethodCall c(qt_Smoke, _current_method, self, argv, argc-1);
+ c.next();
+ return *(c.var());
+ } else if ( argc == 1
+ && TYPE(argv[0]) == T_ARRAY
+ && RARRAY(argv[0])->len > 0
+ && TYPE(rb_ary_entry(argv[0], 0)) != T_STRING )
+ {
+ _current_method = new_qvariant_qlist;
+ MethodCall c(qt_Smoke, _current_method, self, argv, argc-1);
+ c.next();
+ return *(c.var());
+ }
+
+ return rb_call_super(argc, argv);
+}
+
+static QCString *
+find_cached_selector(int argc, VALUE * argv, VALUE klass, char * methodName)
+{
+ // Look in the cache
+static QCString * mcid = 0;
+ if (mcid == 0) {
+ mcid = new QCString();
+ }
+ *mcid = rb_class2name(klass);
+ *mcid += ';';
+ *mcid += methodName;
+ for(int i=3; i<argc ; i++)
+ {
+ *mcid += ';';
+ *mcid += get_VALUEtype(argv[i]);
+ }
+
+ Smoke::Index *rcid = methcache.find((const char *)*mcid);
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("method_missing mcid: %s", (const char *) *mcid);
+#endif
+
+ if (rcid) {
+ // Got a hit
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("method_missing cache hit, mcid: %s", (const char *) *mcid);
+#endif
+ _current_method = *rcid;
+ } else {
+ _current_method = -1;
+ }
+
+ return mcid;
+}
+
+static VALUE
+method_missing(int argc, VALUE * argv, VALUE self)
+{
+ char * methodName = rb_id2name(SYM2ID(argv[0]));
+ VALUE klass = rb_funcall(self, rb_intern("class"), 0);
+
+ // Look for 'thing?' methods, and try to match isThing() or hasThing() in the Smoke runtime
+static QString * pred = 0;
+ if (pred == 0) {
+ pred = new QString();
+ }
+
+ *pred = methodName;
+ if (pred->endsWith("?")) {
+ smokeruby_object *o = value_obj_info(self);
+ if(!o || !o->ptr) {
+ rb_call_super(argc, argv);
+ }
+
+ // Drop the trailing '?'
+ pred->replace(pred->length() - 1, 1, "");
+
+ pred->replace(0, 1, pred->at(0).upper());
+ pred->replace(0, 0, QString("is"));
+ Smoke::Index meth = o->smoke->findMethod(o->smoke->classes[o->classId].className, pred->latin1());
+
+ if (meth == 0) {
+ pred->replace(0, 2, QString("has"));
+ meth = o->smoke->findMethod(o->smoke->classes[o->classId].className, pred->latin1());
+ }
+
+ if (meth > 0) {
+ methodName = (char *) pred->latin1();
+ }
+ }
+
+ VALUE * temp_stack = (VALUE *) calloc(argc+3, sizeof(VALUE));
+ temp_stack[0] = rb_str_new2("Qt");
+ temp_stack[1] = rb_str_new2(methodName);
+ temp_stack[2] = klass;
+ temp_stack[3] = self;
+ for (int count = 1; count < argc; count++) {
+ temp_stack[count+3] = argv[count];
+ }
+
+ {
+ QCString * mcid = find_cached_selector(argc+3, temp_stack, klass, methodName);
+
+ if (_current_method == -1) {
+ // Find the C++ method to call. Do that from Ruby for now
+
+ VALUE retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+3, temp_stack);
+ if (_current_method == -1) {
+ char * op = rb_id2name(SYM2ID(argv[0]));
+ if ( qstrcmp(op, "-") == 0
+ || qstrcmp(op, "+") == 0
+ || qstrcmp(op, "/") == 0
+ || qstrcmp(op, "%") == 0
+ || qstrcmp(op, "|") == 0 )
+ {
+ // Look for operator methods of the form 'operator+=', 'operator-=' and so on..
+ char op1[3];
+ op1[0] = op[0];
+ op1[1] = '=';
+ op1[2] = '\0';
+ temp_stack[1] = rb_str_new2(op1);
+ retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+3, temp_stack);
+ }
+
+ if (_current_method == -1) {
+ free(temp_stack);
+
+ // Check for property getter/setter calls
+ smokeruby_object *o = value_obj_info(self);
+ if ( o != 0
+ && o->ptr != 0
+ && isDerivedFrom(o->smoke, o->classId, o->smoke->idClass("QObject")) )
+ {
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+static QString * prop = 0;
+ if (prop == 0) {
+ prop = new QString();
+ }
+
+ *prop = rb_id2name(SYM2ID(argv[0]));
+ QMetaObject * meta = qobject->metaObject();
+ if (argc == 1) {
+ if (prop->endsWith("?")) {
+ prop->replace(0, 1, pred->at(0).upper());
+ prop->replace(0, 0, QString("is"));
+ if (meta->findProperty(prop->latin1(), true) == -1) {
+ prop->replace(0, 2, QString("has"));
+ }
+ }
+
+ if (meta->findProperty(prop->latin1(), true) != -1) {
+ VALUE qvariant = rb_funcall(self, rb_intern("property"), 1, rb_str_new2(prop->latin1()));
+ return rb_funcall(qvariant, rb_intern("to_ruby"), 0);
+ }
+ } else if (argc == 2 && prop->endsWith("=")) {
+ prop->replace("=", "");
+ if (meta->findProperty(prop->latin1(), true) != -1) {
+ VALUE qvariant = rb_funcall(qvariant_class, rb_intern("new"), 1, argv[1]);
+ return rb_funcall(self, rb_intern("setProperty"), 2, rb_str_new2(prop->latin1()), qvariant);
+ }
+ }
+ }
+
+ rb_call_super(argc, argv);
+ }
+ }
+ // Success. Cache result.
+ methcache.insert((const char *)*mcid, new Smoke::Index(_current_method));
+ }
+ }
+
+ MethodCall c(qt_Smoke, _current_method, self, temp_stack+4, argc-1);
+ c.next();
+ VALUE result = *(c.var());
+ free(temp_stack);
+
+ return result;
+}
+
+static VALUE
+class_method_missing(int argc, VALUE * argv, VALUE klass)
+{
+ VALUE result = Qnil;
+ char * methodName = rb_id2name(SYM2ID(argv[0]));
+ VALUE * temp_stack = (VALUE *) calloc(argc+3, sizeof(VALUE));
+ temp_stack[0] = rb_str_new2("Qt");
+ temp_stack[1] = rb_str_new2(methodName);
+ temp_stack[2] = klass;
+ temp_stack[3] = Qnil;
+ for (int count = 1; count < argc; count++) {
+ temp_stack[count+3] = argv[count];
+ }
+
+ {
+ QCString * mcid = find_cached_selector(argc+3, temp_stack, klass, methodName);
+
+ if (_current_method == -1) {
+ VALUE retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+3, temp_stack);
+ Q_UNUSED(retval);
+ if (_current_method != -1) {
+ // Success. Cache result.
+ methcache.insert((const char *)*mcid, new Smoke::Index(_current_method));
+ }
+ }
+ }
+
+ if (_current_method == -1) {
+static QRegExp * rx = 0;
+ if (rx == 0) {
+ rx = new QRegExp("[a-zA-Z]+");
+ }
+
+ if (rx->search(methodName) == -1) {
+ // If an operator method hasn't been found as an instance method,
+ // then look for a class method - after 'op(self,a)' try 'self.op(a)'
+ VALUE * method_stack = (VALUE *) calloc(argc - 1, sizeof(VALUE));
+ method_stack[0] = argv[0];
+ for (int count = 1; count < argc - 1; count++) {
+ method_stack[count] = argv[count+1];
+ }
+ result = method_missing(argc-1, method_stack, argv[1]);
+ free(method_stack);
+ free(temp_stack);
+ return result;
+ } else {
+ rb_call_super(argc, argv);
+ }
+ }
+
+ MethodCall c(qt_Smoke, _current_method, Qnil, temp_stack+4, argc-1);
+ c.next();
+ result = *(c.var());
+ free(temp_stack);
+ return result;
+}
+
+static VALUE module_method_missing(int argc, VALUE * argv, VALUE /*klass*/)
+{
+ return class_method_missing(argc, argv, qt_module);
+}
+
+static VALUE kde_module_method_missing(int argc, VALUE * argv, VALUE klass)
+{
+ return class_method_missing(argc, argv, klass);
+}
+
+/*
+
+class LCDRange < Qt::Widget
+
+ def initialize(s, parent, name)
+ super(parent, name)
+ init()
+ ...
+
+For a case such as the above, the QWidget can't be instantiated until
+the initializer has been run up to the point where 'super(parent, name)'
+is called. Only then, can the number and type of arguments passed to the
+constructor be known. However, the rest of the intializer
+can't be run until 'self' is a proper T_DATA object with a wrapped C++
+instance.
+
+The solution is to run the initialize code twice. First, only up to the
+'super(parent, name)' call, where the QWidget would get instantiated in
+initialize_qt(). And then rb_throw() jumps out of the
+initializer returning the wrapped object as a result.
+
+The second time round 'self' will be the wrapped instance of type T_DATA,
+so initialize() can be allowed to proceed to the end.
+*/
+static VALUE
+initialize_qt(int argc, VALUE * argv, VALUE self)
+{
+ VALUE retval;
+ VALUE temp_obj;
+
+ if (TYPE(self) == T_DATA) {
+ // If a ruby block was passed then run that now
+ if (rb_block_given_p()) {
+ rb_funcall(qt_internal_module, rb_intern("run_initializer_block"), 2, self, rb_block_proc());
+ }
+
+ return self;
+ }
+
+ VALUE klass = rb_funcall(self, rb_intern("class"), 0);
+ VALUE constructor_name = rb_str_new2("new");
+
+ VALUE * temp_stack = (VALUE *) calloc(argc+4, sizeof(VALUE));
+ temp_stack[0] = rb_str_new2("Qt");
+ temp_stack[1] = constructor_name;
+ temp_stack[2] = klass;
+ temp_stack[3] = self;
+ for (int count = 0; count < argc; count++) {
+ temp_stack[count+4] = argv[count];
+ }
+
+ {
+ // Put this in a C block so that the mcid will be de-allocated at the end of the block,
+ // rather than on f'n exit, to avoid the longjmp problem described below
+ QCString * mcid = find_cached_selector(argc+4, temp_stack, klass, rb_class2name(klass));
+
+ if (_current_method == -1) {
+ retval = rb_funcall2(qt_internal_module, rb_intern("do_method_missing"), argc+4, temp_stack);
+ if (_current_method != -1) {
+ // Success. Cache result.
+ methcache.insert((const char *)*mcid, new Smoke::Index(_current_method));
+ }
+ }
+ }
+
+ if (_current_method == -1) {
+ free(temp_stack);
+ // Another longjmp here..
+ rb_raise(rb_eArgError, "unresolved constructor call %s\n", rb_class2name(klass));
+ }
+
+ {
+ // Allocate the MethodCall within a C block. Otherwise, because the continue_new_instance()
+ // call below will longjmp out, it wouldn't give C++ an opportunity to clean up
+ MethodCall c(qt_Smoke, _current_method, self, temp_stack+4, argc);
+ c.next();
+ temp_obj = *(c.var());
+ }
+
+ smokeruby_object * p = 0;
+ Data_Get_Struct(temp_obj, smokeruby_object, p);
+ smokeruby_object * o = (smokeruby_object *) malloc(sizeof(smokeruby_object));
+ memcpy(o, p, sizeof(smokeruby_object));
+ p->ptr = 0;
+ p->allocated = false;
+ o->allocated = true;
+ VALUE result = Data_Wrap_Struct(klass, smokeruby_mark, smokeruby_free, o);
+ mapObject(result, result);
+ free(temp_stack);
+ // Off with a longjmp, never to return..
+ rb_throw("newqt", result);
+ /*NOTREACHED*/
+ return self;
+}
+
+VALUE
+new_qt(int argc, VALUE * argv, VALUE klass)
+{
+ VALUE * temp_stack = (VALUE *) calloc(argc + 1, sizeof(VALUE));
+ temp_stack[0] = rb_obj_alloc(klass);
+ for (int count = 0; count < argc; count++) {
+ temp_stack[count+1] = argv[count];
+ }
+
+ VALUE result = rb_funcall2(qt_internal_module, rb_intern("try_initialize"), argc+1, temp_stack);
+ rb_obj_call_init(result, argc, argv);
+
+ free(temp_stack);
+ return result;
+}
+
+static VALUE
+new_qapplication(int argc, VALUE * argv, VALUE klass)
+{
+ VALUE result = Qnil;
+
+ if (argc == 1 && TYPE(argv[0]) == T_ARRAY) {
+ // Convert '(ARGV)' to '(NUM, [$0]+ARGV)'
+ VALUE * local_argv = (VALUE *) calloc(argc + 1, sizeof(VALUE));
+ VALUE temp = rb_ary_dup(argv[0]);
+ rb_ary_unshift(temp, rb_gv_get("$0"));
+ local_argv[0] = INT2NUM(RARRAY(temp)->len);
+ local_argv[1] = temp;
+ result = new_qt(2, local_argv, klass);
+ free(local_argv);
+ } else {
+ result = new_qt(argc, argv, klass);
+ }
+
+ rb_gv_set("$qApp", result);
+ return result;
+}
+
+// Returns $qApp.ARGV() - the original ARGV array with Qt command line options removed
+static VALUE
+qapplication_argv(VALUE /*self*/)
+{
+ VALUE result = rb_ary_new();
+ // Drop argv[0], as it isn't included in the ruby global ARGV
+ for (int index = 1; index < qApp->argc(); index++) {
+ rb_ary_push(result, rb_str_new2(qApp->argv()[index]));
+ }
+
+ return result;
+}
+
+//----------------- Sig/Slot ------------------
+
+
+VALUE
+getmetainfo(VALUE self, int &offset, int &index)
+{
+ char * signalname = rb_id2name(rb_frame_last_func());
+ VALUE metaObject_value = rb_funcall(qt_internal_module, rb_intern("getMetaObject"), 1, self);
+
+ smokeruby_object *ometa = value_obj_info(metaObject_value);
+ if(!ometa) return 0;
+ QMetaObject *metaobject = (QMetaObject*)ometa->ptr;
+
+ offset = metaobject->signalOffset();
+
+ VALUE signalInfo = rb_funcall(qt_internal_module, rb_intern("signalInfo"), 2, self, rb_str_new2(signalname));
+ VALUE member = rb_ary_entry(signalInfo, 0);
+ index = NUM2INT(rb_ary_entry(signalInfo, 1));
+ return rb_funcall(qt_internal_module, rb_intern("getMocArguments"), 1, member);
+}
+
+VALUE
+getslotinfo(VALUE self, int id, char *&slotname, int &index, bool isSignal = false)
+{
+ VALUE member;
+
+ VALUE metaObject_value = rb_funcall(qt_internal_module, rb_intern("getMetaObject"), 1, self);
+ smokeruby_object *ometa = value_obj_info(metaObject_value);
+ if(!ometa) return Qnil;
+
+ QMetaObject *metaobject = (QMetaObject*)ometa->ptr;
+
+ int offset = isSignal ? metaobject->signalOffset() : metaobject->slotOffset();
+
+ index = id - offset; // where we at
+ if(index < 0) return Qnil;
+
+ if (isSignal) {
+ member = rb_funcall(qt_internal_module, rb_intern("signalAt"), 2, self, INT2NUM(index));
+ } else {
+ member = rb_funcall(qt_internal_module, rb_intern("slotAt"), 2, self, INT2NUM(index));
+ }
+
+ VALUE mocArgs = rb_funcall(qt_internal_module, rb_intern("getMocArguments"), 1, member);
+ slotname = StringValuePtr(member);
+
+ return mocArgs;
+}
+
+static VALUE
+qt_signal(int argc, VALUE * argv, VALUE self)
+{
+ smokeruby_object *o = value_obj_info(self);
+ QObject *qobj = (QObject*)o->smoke->cast(
+ o->ptr,
+ o->classId,
+ o->smoke->idClass("QObject")
+ );
+ if(qobj->signalsBlocked()) return Qfalse;
+
+ int offset;
+ int index;
+
+ VALUE args = getmetainfo(self, offset, index);
+
+ if(args == Qnil) return Qfalse;
+
+ // Okay, we have the signal info. *whew*
+ EmitSignal signal(qobj, offset + index, argc, args, argv);
+ signal.next();
+
+ return Qtrue;
+}
+
+static VALUE
+qt_invoke(int /*argc*/, VALUE * argv, VALUE self)
+{
+ // Arguments: int id, QUObject *o
+ int id = NUM2INT(argv[0]);
+ QUObject *_o = 0;
+
+ Data_Get_Struct(rb_ary_entry(argv[1], 0), QUObject, _o);
+ if(_o == 0) {
+ rb_raise(rb_eRuntimeError, "Cannot create QUObject\n");
+ }
+
+ smokeruby_object *o = value_obj_info(self);
+ (void) (QObject*)o->smoke->cast(
+ o->ptr,
+ o->classId,
+ o->smoke->idClass("QObject")
+ );
+
+ // Now, I need to find out if this means me
+ int index;
+ char *slotname;
+ bool isSignal = qstrcmp(rb_id2name(rb_frame_last_func()), "qt_emit") == 0;
+ VALUE mocArgs = getslotinfo(self, id, slotname, index, isSignal);
+ if(mocArgs == Qnil) {
+ // No ruby slot/signal found, assume the target is a C++ one
+ Smoke::Index nameId = o->smoke->idMethodName(isSignal ? "qt_emit$?" : "qt_invoke$?");
+ Smoke::Index meth = o->smoke->findMethod(o->classId, nameId);
+ if(meth > 0) {
+ Smoke::Method &m = o->smoke->methods[o->smoke->methodMaps[meth].method];
+ Smoke::ClassFn fn = o->smoke->classes[m.classId].classFn;
+ Smoke::StackItem i[3];
+ i[1].s_int = id;
+ i[2].s_class = _o;
+ (*fn)(m.method, o->ptr, i);
+ return i[0].s_bool == 1 ? Qtrue : Qfalse;
+ }
+
+ // Should never happen..
+ rb_raise(rb_eRuntimeError, "Cannot find %s::qt_invoke() method\n",
+ o->smoke->classes[o->classId].className );
+ }
+
+ QString name(slotname);
+static QRegExp * rx = 0;
+ if (rx == 0) {
+ rx = new QRegExp("\\(.*");
+ }
+ name.replace(*rx, "");
+
+ InvokeSlot slot(self, rb_intern(name.latin1()), mocArgs, _o);
+ slot.next();
+
+ return Qtrue;
+}
+
+static VALUE
+qobject_connect(int argc, VALUE * argv, VALUE self)
+{
+ if (rb_block_given_p()) {
+ if (argc == 1) {
+ return rb_funcall(qt_internal_module, rb_intern("signal_connect"), 3, self, argv[0], rb_block_proc());
+ } else if (argc == 2) {
+ return rb_funcall(qt_internal_module, rb_intern("connect"), 4, argv[0], argv[1], self, rb_block_proc());
+ } else if (argc == 3) {
+ return rb_funcall(qt_internal_module, rb_intern("connect"), 4, argv[0], argv[1], argv[2], rb_block_proc());
+ } else {
+ rb_raise(rb_eArgError, "Invalid argument list");
+ }
+ } else {
+ return rb_call_super(argc, argv);
+ }
+}
+
+// --------------- Ruby C functions for Qt::_internal.* helpers ----------------
+
+
+static VALUE
+getMethStat(VALUE /*self*/)
+{
+ VALUE result_list = rb_ary_new();
+ rb_ary_push(result_list, INT2NUM((int)methcache.size()));
+ rb_ary_push(result_list, INT2NUM((int)methcache.count()));
+ return result_list;
+}
+
+static VALUE
+getClassStat(VALUE /*self*/)
+{
+ VALUE result_list = rb_ary_new();
+ rb_ary_push(result_list, INT2NUM((int)classcache.size()));
+ rb_ary_push(result_list, INT2NUM((int)classcache.count()));
+ return result_list;
+}
+
+static VALUE
+getIsa(VALUE /*self*/, VALUE classId)
+{
+ VALUE parents_list = rb_ary_new();
+
+ Smoke::Index *parents =
+ qt_Smoke->inheritanceList +
+ qt_Smoke->classes[NUM2INT(classId)].parents;
+
+ while(*parents) {
+ //qWarning("\tparent: %s", qt_Smoke->classes[*parents].className);
+ rb_ary_push(parents_list, rb_str_new2(qt_Smoke->classes[*parents++].className));
+ }
+ return parents_list;
+}
+
+// Return the class name of a QObject. Note that the name will be in the
+// form of Qt::Widget rather than QWidget. Is this a bug or a feature?
+static VALUE
+class_name(VALUE self)
+{
+ VALUE klass = rb_funcall(self, rb_intern("class"), 0);
+ return rb_funcall(klass, rb_intern("name"), 0);
+}
+
+// Allow classnames in both 'Qt::Widget' and 'QWidget' formats to be
+// used as an argument to Qt::Object.inherits()
+static VALUE
+inherits_qobject(int argc, VALUE * argv, VALUE /*self*/)
+{
+ if (argc != 1) {
+ return rb_call_super(argc, argv);
+ }
+
+ Smoke::Index * classId = classcache.find(StringValuePtr(argv[0]));
+
+ if (classId == 0) {
+ return rb_call_super(argc, argv);
+ } else {
+ VALUE super_class = rb_str_new2(qt_Smoke->classes[*classId].className);
+ return rb_call_super(argc, &super_class);
+ }
+}
+
+static VALUE
+qbytearray_data(VALUE self)
+{
+ smokeruby_object *o = value_obj_info(self);
+ if (o == 0 || o->ptr == 0) {
+ return Qnil;
+ }
+ QByteArray * dataArray = (QByteArray*) o->ptr;
+ return rb_str_new(dataArray->data(), (long) dataArray->size());
+}
+
+static VALUE
+qbytearray_size(VALUE self)
+{
+ smokeruby_object *o = value_obj_info(self);
+ if (o == 0 || o->ptr == 0) {
+ return Qnil;
+ }
+ QByteArray * dataArray = (QByteArray*) o->ptr;
+ return UINT2NUM(dataArray->size());
+}
+
+static VALUE
+qbytearray_setRawData(VALUE self, VALUE data)
+{
+ smokeruby_object *o = value_obj_info(self);
+ if (o == 0 || o->ptr == 0) {
+ return Qnil;
+ }
+ QByteArray * dataArray = (QByteArray*) o->ptr;
+ dataArray->setRawData(StringValuePtr(data), RSTRING(data)->len);
+ return self;
+}
+
+static void
+mocargs_free(void * ptr)
+{
+ MocArgument * mocArgs = (MocArgument *) ptr;
+ delete[] mocArgs;
+ return;
+}
+
+static VALUE
+allocateMocArguments(VALUE /*self*/, VALUE count_value)
+{
+ int count = NUM2INT(count_value);
+ MocArgument * ptr = new MocArgument[count + 1];
+ return Data_Wrap_Struct(rb_cObject, 0, mocargs_free, ptr);
+}
+
+static VALUE
+setMocType(VALUE /*self*/, VALUE ptr, VALUE idx_value, VALUE name_value, VALUE static_type_value)
+{
+ int idx = NUM2INT(idx_value);
+ char *name = StringValuePtr(name_value);
+ char *static_type = StringValuePtr(static_type_value);
+ Smoke::Index typeId = qt_Smoke->idType(name);
+ if(!typeId) return Qfalse;
+ MocArgument *arg = 0;
+ Data_Get_Struct(ptr, MocArgument, arg);
+ arg[idx].st.set(qt_Smoke, typeId);
+ if(qstrcmp(static_type, "ptr") == 0)
+ arg[idx].argType = xmoc_ptr;
+ else if(qstrcmp(static_type, "bool") == 0)
+ arg[idx].argType = xmoc_bool;
+ else if(qstrcmp(static_type, "int") == 0)
+ arg[idx].argType = xmoc_int;
+ else if(qstrcmp(static_type, "double") == 0)
+ arg[idx].argType = xmoc_double;
+ else if(qstrcmp(static_type, "char*") == 0)
+ arg[idx].argType = xmoc_charstar;
+ else if(qstrcmp(static_type, "QString") == 0)
+ arg[idx].argType = xmoc_QString;
+ return Qtrue;
+}
+
+static VALUE
+setDebug(VALUE self, VALUE on_value)
+{
+ int on = NUM2INT(on_value);
+ do_debug = on;
+ return self;
+}
+
+static VALUE
+debugging(VALUE /*self*/)
+{
+ return INT2NUM(do_debug);
+}
+
+static VALUE
+getTypeNameOfArg(VALUE /*self*/, VALUE method_value, VALUE idx_value)
+{
+ int method = NUM2INT(method_value);
+ int idx = NUM2INT(idx_value);
+ Smoke::Method &m = qt_Smoke->methods[method];
+ Smoke::Index *args = qt_Smoke->argumentList + m.args;
+ return rb_str_new2((char*)qt_Smoke->types[args[idx]].name);
+}
+
+static VALUE
+classIsa(VALUE /*self*/, VALUE className_value, VALUE base_value)
+{
+ char *className = StringValuePtr(className_value);
+ char *base = StringValuePtr(base_value);
+ return isDerivedFromByName(qt_Smoke, className, base) ? Qtrue : Qfalse;
+}
+
+static VALUE
+isEnum(VALUE /*self*/, VALUE enumName_value)
+{
+ char *enumName = StringValuePtr(enumName_value);
+ Smoke::Index typeId = qt_Smoke->idType(enumName);
+ return typeId > 0
+ && ( (qt_Smoke->types[typeId].flags & Smoke::tf_elem) == Smoke::t_enum
+ || (qt_Smoke->types[typeId].flags & Smoke::tf_elem) == Smoke::t_ulong
+ || (qt_Smoke->types[typeId].flags & Smoke::tf_elem) == Smoke::t_long
+ || (qt_Smoke->types[typeId].flags & Smoke::tf_elem) == Smoke::t_uint
+ || (qt_Smoke->types[typeId].flags & Smoke::tf_elem) == Smoke::t_int ) ? Qtrue : Qfalse;
+}
+
+static VALUE
+insert_pclassid(VALUE self, VALUE p_value, VALUE ix_value)
+{
+ char *p = StringValuePtr(p_value);
+ int ix = NUM2INT(ix_value);
+ classcache.insert(p, new Smoke::Index((Smoke::Index)ix));
+ classname.insert(ix, strdup(p));
+ return self;
+}
+
+static VALUE
+find_pclassid(VALUE /*self*/, VALUE p_value)
+{
+ char *p = StringValuePtr(p_value);
+ Smoke::Index *r = classcache.find(p);
+ if(r)
+ return INT2NUM((int)*r);
+ else
+ return INT2NUM(0);
+}
+
+static VALUE
+insert_mcid(VALUE self, VALUE mcid_value, VALUE ix_value)
+{
+ char *mcid = StringValuePtr(mcid_value);
+ int ix = NUM2INT(ix_value);
+ methcache.insert(mcid, new Smoke::Index((Smoke::Index)ix));
+ return self;
+}
+
+static VALUE
+find_mcid(VALUE /*self*/, VALUE mcid_value)
+{
+ char *mcid = StringValuePtr(mcid_value);
+ Smoke::Index *r = methcache.find(mcid);
+ if(r)
+ return INT2NUM((int)*r);
+ else
+ return INT2NUM(0);
+}
+
+static VALUE
+getVALUEtype(VALUE /*self*/, VALUE ruby_value)
+{
+ return rb_str_new2(get_VALUEtype(ruby_value));
+}
+
+static VALUE
+make_QUParameter(VALUE /*self*/, VALUE name_value, VALUE type_value, VALUE /*extra*/, VALUE inout_value)
+{
+ char *name = StringValuePtr(name_value);
+ char *type = StringValuePtr(type_value);
+ int inout = NUM2INT(inout_value);
+ QUParameter *p = new QUParameter;
+ p->name = new char[strlen(name) + 1];
+ strcpy((char*)p->name, name);
+ if(qstrcmp(type, "bool") == 0)
+ p->type = &static_QUType_bool;
+ else if(qstrcmp(type, "int") == 0)
+ p->type = &static_QUType_int;
+ else if(qstrcmp(type, "double") == 0)
+ p->type = &static_QUType_double;
+ else if(qstrcmp(type, "char*") == 0 || qstrcmp(type, "const char*") == 0)
+ p->type = &static_QUType_charstar;
+ else if(qstrcmp(type, "QString") == 0 || qstrcmp(type, "QString&") == 0 ||
+ qstrcmp(type, "const QString") == 0 || qstrcmp(type, "const QString&") == 0)
+ p->type = &static_QUType_QString;
+ else
+ p->type = &static_QUType_ptr;
+ // Lacking support for several types. Evil.
+ p->inOut = inout;
+ p->typeExtra = 0;
+ return Data_Wrap_Struct(rb_cObject, 0, 0, p);
+}
+
+static VALUE
+make_QMetaData(VALUE /*self*/, VALUE name_value, VALUE method)
+{
+ char *name = StringValuePtr(name_value);
+ QMetaData *m = new QMetaData; // will be deleted
+ m->name = new char[strlen(name) + 1];
+ strcpy((char*)m->name, name);
+ Data_Get_Struct(method, QUMethod, m->method);
+ m->access = QMetaData::Public;
+ return Data_Wrap_Struct(rb_cObject, 0, 0, m);
+}
+
+static VALUE
+make_QUMethod(VALUE /*self*/, VALUE name_value, VALUE params)
+{
+ char *name = StringValuePtr(name_value);
+ QUMethod *m = new QUMethod; // permanent memory allocation
+ m->name = new char[strlen(name) + 1]; // this too
+ strcpy((char*)m->name, name);
+ m->parameters = 0;
+ m->count = RARRAY(params)->len;
+
+ if (m->count > 0) {
+ m->parameters = new QUParameter[m->count];
+ for (long i = 0; i < m->count; i++) {
+ VALUE param = rb_ary_entry(params, i);
+ QUParameter *p = 0;
+ Data_Get_Struct(param, QUParameter, p);
+ ((QUParameter *) m->parameters)[i] = *p;
+ delete p;
+ }
+ }
+ return Data_Wrap_Struct(rb_cObject, 0, 0, m);
+}
+
+static VALUE
+make_QMetaData_tbl(VALUE /*self*/, VALUE list)
+{
+ long count = RARRAY(list)->len;
+ QMetaData *m = new QMetaData[count];
+
+ for (long i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+
+ QMetaData *old = 0;
+ Data_Get_Struct(item, QMetaData, old);
+ m[i] = *old;
+ delete old;
+ }
+
+ return Data_Wrap_Struct(rb_cObject, 0, 0, m);
+}
+
+static VALUE
+make_metaObject(VALUE /*self*/, VALUE className_value, VALUE parent, VALUE slot_tbl_value, VALUE slot_count_value, VALUE signal_tbl_value, VALUE signal_count_value)
+{
+ char *className = strdup(StringValuePtr(className_value));
+
+ QMetaData * slot_tbl = 0;
+ int slot_count = 0;
+ if (slot_tbl_value != Qnil) {
+ Data_Get_Struct(slot_tbl_value, QMetaData, slot_tbl);
+ slot_count = NUM2INT(slot_count_value);
+ }
+
+ QMetaData * signal_tbl = 0;
+ int signal_count = 0;
+ if (signal_tbl_value != Qnil) {
+ Data_Get_Struct(signal_tbl_value, QMetaData, signal_tbl);
+ signal_count = NUM2INT(signal_count_value);
+ }
+
+ smokeruby_object *po = value_obj_info(parent);
+ if(!po || !po->ptr) {
+ rb_raise(rb_eRuntimeError, "Cannot create metaObject\n");
+ }
+
+ QMetaObject *meta = QMetaObject::new_metaobject(
+ className, (QMetaObject*)po->ptr,
+ (const QMetaData*)slot_tbl, slot_count, // slots
+ (const QMetaData*)signal_tbl, signal_count, // signals
+ 0, 0, // properties
+ 0, 0, // enums
+ 0, 0);
+
+ smokeruby_object * o = (smokeruby_object *) malloc(sizeof(smokeruby_object));
+ o->smoke = qt_Smoke;
+ o->classId = qt_Smoke->idClass("QMetaObject");
+ o->ptr = meta;
+ o->allocated = true;
+
+ return Data_Wrap_Struct(qmetaobject_class, smokeruby_mark, smokeruby_free, o);
+}
+
+static VALUE
+add_metaobject_methods(VALUE self, VALUE klass)
+{
+ rb_define_method(klass, "qt_invoke", (VALUE (*) (...)) qt_invoke, -1);
+ rb_define_method(klass, "qt_emit", (VALUE (*) (...)) qt_invoke, -1);
+ rb_define_method(klass, "metaObject", (VALUE (*) (...)) metaObject, 0);
+ return self;
+}
+
+static VALUE
+add_signal_methods(VALUE self, VALUE klass, VALUE signalNames)
+{
+ for (long index = 0; index < RARRAY(signalNames)->len; index++) {
+ VALUE signal = rb_ary_entry(signalNames, index);
+ rb_define_method(klass, StringValuePtr(signal), (VALUE (*) (...)) qt_signal, -1);
+ }
+ return self;
+}
+
+static VALUE
+dispose(VALUE self)
+{
+ smokeruby_object *o = value_obj_info(self);
+ if(!o || !o->ptr) { return Qnil; }
+
+ const char *className = o->smoke->classes[o->classId].className;
+ if(do_debug & qtdb_gc) printf("Deleting (%s*)%p\n", className, o->ptr);
+
+ unmapPointer(o, o->classId, 0);
+ object_count--;
+
+ char *methodName = new char[strlen(className) + 2];
+ methodName[0] = '~';
+ strcpy(methodName + 1, className);
+ Smoke::Index nameId = o->smoke->idMethodName(methodName);
+ Smoke::Index meth = o->smoke->findMethod(o->classId, nameId);
+ if(meth > 0) {
+ Smoke::Method &m = o->smoke->methods[o->smoke->methodMaps[meth].method];
+ Smoke::ClassFn fn = o->smoke->classes[m.classId].classFn;
+ Smoke::StackItem i[1];
+ (*fn)(m.method, o->ptr, i);
+ }
+ delete[] methodName;
+ o->ptr = 0;
+ o->allocated = false;
+
+ return self;
+}
+
+static VALUE
+is_disposed(VALUE self)
+{
+ smokeruby_object *o = value_obj_info(self);
+ if(!o || !o->ptr) { return Qtrue; }
+ return Qfalse;
+}
+
+static VALUE
+mapObject(VALUE self, VALUE obj)
+{
+ smokeruby_object *o = value_obj_info(obj);
+ if(!o)
+ return Qnil;
+ mapPointer(obj, o, o->classId, 0);
+ return self;
+}
+
+static VALUE
+isaQObject(VALUE /*self*/, VALUE classid)
+{
+ int classid_value = NUM2INT(classid);
+ return isQObject(qt_Smoke, classid_value) ? Qtrue : Qfalse;
+}
+
+// Returns the Smoke classId of a ruby instance
+static VALUE
+idInstance(VALUE /*self*/, VALUE instance)
+{
+ smokeruby_object *o = value_obj_info(instance);
+ if(!o)
+ return Qnil;
+
+ return INT2NUM(o->classId);
+}
+
+static VALUE
+idClass(VALUE /*self*/, VALUE name_value)
+{
+ char *name = StringValuePtr(name_value);
+ return INT2NUM(qt_Smoke->idClass(name));
+}
+
+static VALUE
+idMethodName(VALUE /*self*/, VALUE name_value)
+{
+ char *name = StringValuePtr(name_value);
+ return INT2NUM(qt_Smoke->idMethodName(name));
+}
+
+static VALUE
+idMethod(VALUE /*self*/, VALUE idclass_value, VALUE idmethodname_value)
+{
+ int idclass = NUM2INT(idclass_value);
+ int idmethodname = NUM2INT(idmethodname_value);
+ return INT2NUM(qt_Smoke->idMethod(idclass, idmethodname));
+}
+
+static VALUE
+findMethod(VALUE /*self*/, VALUE c_value, VALUE name_value)
+{
+ char *c = StringValuePtr(c_value);
+ char *name = StringValuePtr(name_value);
+ VALUE result = rb_ary_new();
+ Smoke::Index meth = qt_Smoke->findMethod(c, name);
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("DAMNIT on %s::%s => %d", c, name, meth);
+#endif
+ if(!meth) {
+ meth = qt_Smoke->findMethod("QGlobalSpace", name);
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("DAMNIT on QGlobalSpace::%s => %d", name, meth);
+#endif
+ }
+
+ if(!meth) {
+ return result;
+ // empty list
+ } else if(meth > 0) {
+ Smoke::Index i = qt_Smoke->methodMaps[meth].method;
+ if(!i) { // shouldn't happen
+ rb_raise(rb_eArgError, "Corrupt method %s::%s", c, name);
+ } else if(i > 0) { // single match
+ Smoke::Method &methodRef = qt_Smoke->methods[i];
+ if ((methodRef.flags & Smoke::mf_internal) == 0) {
+ rb_ary_push(result, INT2NUM(i));
+ }
+ } else { // multiple match
+ i = -i; // turn into ambiguousMethodList index
+ while(qt_Smoke->ambiguousMethodList[i]) {
+ Smoke::Method &methodRef = qt_Smoke->methods[qt_Smoke->ambiguousMethodList[i]];
+ if ((methodRef.flags & Smoke::mf_internal) == 0) {
+ rb_ary_push(result, INT2NUM(qt_Smoke->ambiguousMethodList[i]));
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("Ambiguous Method %s::%s => %d", c, name, qt_Smoke->ambiguousMethodList[i]);
+#endif
+
+ }
+ i++;
+ }
+ }
+ }
+ return result;
+}
+
+// findAllMethods(classid [, startingWith]) : returns { "mungedName" => [index in methods, ...], ... }
+
+static VALUE
+findAllMethods(int argc, VALUE * argv, VALUE /*self*/)
+{
+ VALUE classid = argv[0];
+ VALUE result = rb_hash_new();
+ if(classid != Qnil) {
+ Smoke::Index c = (Smoke::Index) NUM2INT(classid);
+ if (c > qt_Smoke->numClasses) {
+ return Qnil;
+ }
+ char * pat = 0L;
+ if(argc > 1 && TYPE(argv[1]) == T_STRING)
+ pat = StringValuePtr(argv[1]);
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("findAllMethods called with classid = %d, pat == %s", c, pat);
+#endif
+ Smoke::Index imax = qt_Smoke->numMethodMaps;
+ Smoke::Index imin = 0, icur = -1, methmin, methmax;
+ methmin = -1; methmax = -1; // kill warnings
+ int icmp = -1;
+ while(imax >= imin) {
+ icur = (imin + imax) / 2;
+ icmp = qt_Smoke->leg(qt_Smoke->methodMaps[icur].classId, c);
+ if(!icmp) {
+ Smoke::Index pos = icur;
+ while(icur && qt_Smoke->methodMaps[icur-1].classId == c)
+ icur --;
+ methmin = icur;
+ icur = pos;
+ while(icur < imax && qt_Smoke->methodMaps[icur+1].classId == c)
+ icur ++;
+ methmax = icur;
+ break;
+ }
+ if (icmp > 0)
+ imax = icur - 1;
+ else
+ imin = icur + 1;
+ }
+ if(!icmp) {
+ for(Smoke::Index i=methmin ; i <= methmax ; i++) {
+ Smoke::Index m = qt_Smoke->methodMaps[i].name;
+ if(!pat || !qstrncmp(qt_Smoke->methodNames[m], pat, strlen(pat))) {
+ Smoke::Index ix= qt_Smoke->methodMaps[i].method;
+ VALUE meths = rb_ary_new();
+ if(ix >= 0) { // single match
+ Smoke::Method &methodRef = qt_Smoke->methods[ix];
+ if ((methodRef.flags & Smoke::mf_internal) == 0) {
+ rb_ary_push(meths, INT2NUM((int)ix));
+ }
+ } else { // multiple match
+ ix = -ix; // turn into ambiguousMethodList index
+ while(qt_Smoke->ambiguousMethodList[ix]) {
+ Smoke::Method &methodRef = qt_Smoke->methods[qt_Smoke->ambiguousMethodList[ix]];
+ if ((methodRef.flags & Smoke::mf_internal) == 0) {
+ rb_ary_push(meths, INT2NUM((int)qt_Smoke->ambiguousMethodList[ix]));
+ }
+ ix++;
+ }
+ }
+ rb_hash_aset(result, rb_str_new2(qt_Smoke->methodNames[m]), meths);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*
+ Flags values
+ 0 All methods, except enum values and protected non-static methods
+ mf_static Static methods only
+ mf_enum Enums only
+ mf_protected Protected non-static methods only
+*/
+
+#define PUSH_QTRUBY_METHOD \
+ if ( (methodRef.flags & (Smoke::mf_internal|Smoke::mf_ctor|Smoke::mf_dtor)) == 0 \
+ && qstrcmp(qt_Smoke->methodNames[methodRef.name], "operator=") != 0 \
+ && qstrcmp(qt_Smoke->methodNames[methodRef.name], "operator!=") != 0 \
+ && qstrcmp(qt_Smoke->methodNames[methodRef.name], "operator--") != 0 \
+ && qstrcmp(qt_Smoke->methodNames[methodRef.name], "operator++") != 0 \
+ && qstrncmp(qt_Smoke->methodNames[methodRef.name], "operator ", strlen("operator ")) != 0 \
+ && ( (flags == 0 && (methodRef.flags & (Smoke::mf_static|Smoke::mf_enum|Smoke::mf_protected)) == 0) \
+ || ( flags == Smoke::mf_static \
+ && (methodRef.flags & Smoke::mf_enum) == 0 \
+ && (methodRef.flags & Smoke::mf_static) == Smoke::mf_static ) \
+ || (flags == Smoke::mf_enum && (methodRef.flags & Smoke::mf_enum) == Smoke::mf_enum) \
+ || ( flags == Smoke::mf_protected \
+ && (methodRef.flags & Smoke::mf_static) == 0 \
+ && (methodRef.flags & Smoke::mf_protected) == Smoke::mf_protected ) ) ) { \
+ if (qstrncmp(qt_Smoke->methodNames[methodRef.name], "operator", strlen("operator")) == 0) { \
+ if (op_re.search(qt_Smoke->methodNames[methodRef.name]) != -1) { \
+ rb_ary_push(result, rb_str_new2(op_re.cap(1) + op_re.cap(2))); \
+ } else { \
+ rb_ary_push(result, rb_str_new2(qt_Smoke->methodNames[methodRef.name] + strlen("operator"))); \
+ } \
+ } else if (predicate_re.search(qt_Smoke->methodNames[methodRef.name]) != -1 && methodRef.numArgs == 0) { \
+ rb_ary_push(result, rb_str_new2(predicate_re.cap(2).lower() + predicate_re.cap(3) + "?")); \
+ } else if (set_re.search(qt_Smoke->methodNames[methodRef.name]) != -1 && methodRef.numArgs == 1) { \
+ rb_ary_push(result, rb_str_new2(set_re.cap(2).lower() + set_re.cap(3) + "=")); \
+ } else { \
+ rb_ary_push(result, rb_str_new2(qt_Smoke->methodNames[methodRef.name])); \
+ } \
+ }
+
+static VALUE
+findAllMethodNames(VALUE /*self*/, VALUE result, VALUE classid, VALUE flags_value)
+{
+ QRegExp predicate_re("^(is|has)(.)(.*)");
+ QRegExp set_re("^(set)([A-Z])(.*)");
+ QRegExp op_re("operator(.*)(([-%~/+|&*])|(>>)|(<<)|(&&)|(\\|\\|)|(\\*\\*))=$");
+
+ unsigned short flags = (unsigned short) NUM2UINT(flags_value);
+ if (classid != Qnil) {
+ Smoke::Index c = (Smoke::Index) NUM2INT(classid);
+ if (c > qt_Smoke->numClasses) {
+ return Qnil;
+ }
+#ifdef DEBUG
+ if (do_debug & qtdb_calls) qWarning("findAllMethodNames called with classid = %d", c);
+#endif
+ Smoke::Index imax = qt_Smoke->numMethodMaps;
+ Smoke::Index imin = 0, icur = -1, methmin, methmax;
+ methmin = -1; methmax = -1; // kill warnings
+ int icmp = -1;
+
+ while (imax >= imin) {
+ icur = (imin + imax) / 2;
+ icmp = qt_Smoke->leg(qt_Smoke->methodMaps[icur].classId, c);
+ if (icmp == 0) {
+ Smoke::Index pos = icur;
+ while(icur && qt_Smoke->methodMaps[icur-1].classId == c)
+ icur --;
+ methmin = icur;
+ icur = pos;
+ while(icur < imax && qt_Smoke->methodMaps[icur+1].classId == c)
+ icur ++;
+ methmax = icur;
+ break;
+ }
+ if (icmp > 0)
+ imax = icur - 1;
+ else
+ imin = icur + 1;
+ }
+
+ if (icmp == 0) {
+ for (Smoke::Index i=methmin ; i <= methmax ; i++) {
+ Smoke::Index ix= qt_Smoke->methodMaps[i].method;
+ if (ix >= 0) { // single match
+ Smoke::Method &methodRef = qt_Smoke->methods[ix];
+ PUSH_QTRUBY_METHOD
+ } else { // multiple match
+ ix = -ix; // turn into ambiguousMethodList index
+ while (qt_Smoke->ambiguousMethodList[ix]) {
+ Smoke::Method &methodRef = qt_Smoke->methods[qt_Smoke->ambiguousMethodList[ix]];
+ PUSH_QTRUBY_METHOD
+ ix++;
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+static VALUE
+dumpCandidates(VALUE /*self*/, VALUE rmeths)
+{
+ VALUE errmsg = rb_str_new2("");
+ if(rmeths != Qnil) {
+ int count = RARRAY(rmeths)->len;
+ for(int i = 0; i < count; i++) {
+ rb_str_catf(errmsg, "\t");
+ int id = NUM2INT(rb_ary_entry(rmeths, i));
+ Smoke::Method &meth = qt_Smoke->methods[id];
+ const char *tname = qt_Smoke->types[meth.ret].name;
+ if(meth.flags & Smoke::mf_enum) {
+ rb_str_catf(errmsg, "enum ");
+ rb_str_catf(errmsg, "%s::%s", qt_Smoke->classes[meth.classId].className, qt_Smoke->methodNames[meth.name]);
+ rb_str_catf(errmsg, "\n");
+ } else {
+ if(meth.flags & Smoke::mf_static) rb_str_catf(errmsg, "static ");
+ rb_str_catf(errmsg, "%s ", (tname ? tname:"void"));
+ rb_str_catf(errmsg, "%s::%s(", qt_Smoke->classes[meth.classId].className, qt_Smoke->methodNames[meth.name]);
+ for(int i = 0; i < meth.numArgs; i++) {
+ if(i) rb_str_catf(errmsg, ", ");
+ tname = qt_Smoke->types[qt_Smoke->argumentList[meth.args+i]].name;
+ rb_str_catf(errmsg, "%s", (tname ? tname:"void"));
+ }
+ rb_str_catf(errmsg, ")");
+ if(meth.flags & Smoke::mf_const) rb_str_catf(errmsg, " const");
+ rb_str_catf(errmsg, "\n");
+ }
+ }
+ }
+ return errmsg;
+}
+
+static VALUE
+isObject(VALUE /*self*/, VALUE obj)
+{
+ void * ptr = 0;
+ ptr = value_to_ptr(obj);
+ return (ptr > 0 ? Qtrue : Qfalse);
+}
+
+static VALUE
+setCurrentMethod(VALUE self, VALUE meth_value)
+{
+ int meth = NUM2INT(meth_value);
+ // FIXME: damn, this is lame, and it doesn't handle ambiguous methods
+ _current_method = meth; //qt_Smoke->methodMaps[meth].method;
+ return self;
+}
+
+static VALUE
+getClassList(VALUE /*self*/)
+{
+ VALUE class_list = rb_ary_new();
+
+ for(int i = 1; i <= qt_Smoke->numClasses; i++) {
+ rb_ary_push(class_list, rb_str_new2(qt_Smoke->classes[i].className));
+ }
+
+ return class_list;
+}
+
+static VALUE
+kde_package_to_class(const char * package, VALUE base_class)
+{
+ VALUE klass = Qnil;
+ QString packageName(package);
+static QRegExp * scope_op = 0;
+ if (scope_op == 0) {
+ scope_op = new QRegExp("^([^:]+)::([^:]+)$");
+ }
+
+ if (packageName.startsWith("KDE::ConfigSkeleton::ItemEnum::")) {
+ klass = rb_define_class_under(kconfigskeleton_itemenum_class, package+strlen("KDE::ConfigSkeleton::EnumItem::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ kconfigskeleton_itemenum_choice_class = klass;
+ } else if (packageName.startsWith("KDE::ConfigSkeleton::")) {
+ klass = rb_define_class_under(kconfigskeleton_class, package+strlen("KDE::ConfigSkeleton::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ rb_define_method(klass, "immutable?", (VALUE (*) (...)) _kconfigskeletonitem_immutable, 0);
+ rb_define_method(klass, "isImmutable", (VALUE (*) (...)) _kconfigskeletonitem_immutable, 0);
+ } else if (packageName.startsWith("KDE::Win::")) {
+ klass = rb_define_class_under(kwin_class, package+strlen("KDE::Win::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("KDE::")) {
+ klass = rb_define_class_under(kde_module, package+strlen("KDE::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("KParts::")) {
+ klass = rb_define_class_under(kparts_module, package+strlen("KParts::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ if (packageName == "KParts::ReadOnlyPart") {
+ konsole_part_class = rb_define_class_under(kde_module, "KonsolePart", klass);
+ }
+ } else if (packageName.startsWith("KNS::")) {
+ klass = rb_define_class_under(kns_module, package+strlen("KNS::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("KIO::")) {
+ klass = rb_define_class_under(kio_module, package+strlen("KIO::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ if (packageName == "KIO::UDSAtom") {
+ kio_udsatom_class = klass;
+ }
+ } else if (packageName.startsWith("DOM::")) {
+ klass = rb_define_class_under(dom_module, package+strlen("DOM::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("Kontact::")) {
+ klass = rb_define_class_under(kontact_module, package+strlen("Kontact::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("Ko") && scope_op->search(packageName) == -1) {
+ klass = rb_define_class_under(koffice_module, package+strlen("Ko"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("Kate::")) {
+ klass = rb_define_class_under(kate_module, package+strlen("Kate::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("Kate")) {
+ klass = rb_define_class_under(kate_module, package+strlen("Kate"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (packageName.startsWith("KTextEditor::")) {
+ klass = rb_define_class_under(ktexteditor_module, package+strlen("KTextEditor::"), base_class);
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) _new_kde, -1);
+ } else if (scope_op->search(packageName) != -1) {
+ // If an unrecognised classname of the form 'XXXXXX::YYYYYY' is found,
+ // then create a module XXXXXX to put the class YYYYYY under
+ VALUE module = rb_define_module(scope_op->cap(1).latin1());
+ klass = rb_define_class_under(module, scope_op->cap(2).latin1(), base_class);
+ } else if ( packageName.startsWith("K")
+ && packageName.mid(1, 1).contains(QRegExp("[A-Z]")) == 1 )
+ {
+ klass = rb_define_class_under(kde_module, package+strlen("K"), base_class);
+ } else {
+ packageName = packageName.mid(0, 1).upper() + packageName.mid(1);
+ klass = rb_define_class_under(kde_module, packageName.latin1(), base_class);
+ }
+
+ return klass;
+}
+
+static VALUE
+create_qobject_class(VALUE /*self*/, VALUE package_value)
+{
+ const char *package = StringValuePtr(package_value);
+ VALUE klass;
+
+ if (QString(package).startsWith("Qt::")) {
+ klass = rb_define_class_under(qt_module, package+strlen("Qt::"), qt_base_class);
+ if (qstrcmp(package, "Qt::Application") == 0) {
+ rb_define_singleton_method(klass, "new", (VALUE (*) (...)) new_qapplication, -1);
+ rb_define_method(klass, "ARGV", (VALUE (*) (...)) qapplication_argv, 0);
+ }
+ } else if (QString(package).startsWith("Qext::")) {
+ if (qext_scintilla_module == Qnil) {
+ qext_scintilla_module = rb_define_module("Qext");
+ }
+ klass = rb_define_class_under(qext_scintilla_module, package+strlen("Qext::"), qt_base_class);
+ } else {
+ klass = kde_package_to_class(package, qt_base_class);
+ }
+
+ rb_define_method(klass, "inspect", (VALUE (*) (...)) inspect_qobject, 0);
+ rb_define_method(klass, "pretty_print", (VALUE (*) (...)) pretty_print_qobject, 1);
+ rb_define_method(klass, "receivers", (VALUE (*) (...)) receivers_qobject, 0);
+ rb_define_method(klass, "className", (VALUE (*) (...)) class_name, 0);
+ rb_define_method(klass, "inherits", (VALUE (*) (...)) inherits_qobject, -1);
+ rb_define_method(klass, "connect", (VALUE (*) (...)) qobject_connect, -1);
+ rb_define_singleton_method(klass, "connect", (VALUE (*) (...)) qobject_connect, -1);
+
+ return klass;
+}
+
+static VALUE
+create_qt_class(VALUE /*self*/, VALUE package_value)
+{
+ const char *package = StringValuePtr(package_value);
+ VALUE klass;
+
+ if (QString(package).startsWith("Qt::")) {
+ klass = rb_define_class_under(qt_module, package+strlen("Qt::"), qt_base_class);
+ } else if (QString(package).startsWith("Qext::")) {
+ if (qext_scintilla_module == Qnil) {
+ qext_scintilla_module = rb_define_module("Qext");
+ }
+ klass = rb_define_class_under(qext_scintilla_module, package+strlen("Qext::"), qt_base_class);
+ } else {
+ klass = kde_package_to_class(package, qt_base_class);
+ }
+
+ if (qstrcmp(package, "Qt::MetaObject") == 0) {
+ qmetaobject_class = klass;
+ } else if (qstrcmp(package, "Qt::Variant") == 0) {
+ qvariant_class = klass;
+ rb_define_singleton_method(qvariant_class, "new", (VALUE (*) (...)) new_qvariant, -1);
+ } else if (qstrcmp(package, "Qt::ByteArray") == 0) {
+ rb_define_method(klass, "data", (VALUE (*) (...)) qbytearray_data, 0);
+ rb_define_method(klass, "size", (VALUE (*) (...)) qbytearray_size, 0);
+ rb_define_method(klass, "setRawData", (VALUE (*) (...)) qbytearray_setRawData, 1);
+ } else if (qstrcmp(package, "Qt::Char") == 0) {
+ rb_define_method(klass, "to_s", (VALUE (*) (...)) qchar_to_s, 0);
+ }
+
+ return klass;
+}
+
+static VALUE
+version(VALUE /*self*/)
+{
+ return rb_str_new2(QT_VERSION_STR);
+}
+
+static VALUE
+qtruby_version(VALUE /*self*/)
+{
+ return rb_str_new2(QTRUBY_VERSION);
+}
+
+void
+set_new_kde(VALUE (*new_kde) (int, VALUE *, VALUE))
+{
+ _new_kde = new_kde;
+
+ if (qt_module == Qnil) {
+ qt_module = rb_define_module("Qt");
+ qt_internal_module = rb_define_module_under(qt_module, "Internal");
+ qt_base_class = rb_define_class_under(qt_module, "Base", rb_cObject);
+ }
+
+ kde_module = rb_define_module("KDE");
+ rb_define_singleton_method(kde_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(kde_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ kparts_module = rb_define_module("KParts");
+ rb_define_singleton_method(kparts_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(kparts_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ kns_module = rb_define_module("KNS");
+ rb_define_singleton_method(kns_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(kns_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ kio_module = rb_define_module("KIO");
+ rb_define_singleton_method(kio_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(kio_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ dom_module = rb_define_module("DOM");
+ rb_define_singleton_method(dom_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(dom_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ kontact_module = rb_define_module("Kontact");
+ rb_define_singleton_method(kontact_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(kontact_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ ktexteditor_module = rb_define_module("KTextEditor");
+ rb_define_singleton_method(ktexteditor_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(ktexteditor_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ kwin_class = rb_define_class_under(kde_module, "Win", qt_base_class);
+
+ kate_module = rb_define_module("Kate");
+ rb_define_singleton_method(kate_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(kate_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+
+ koffice_module = rb_define_module("Ko");
+ rb_define_singleton_method(koffice_module, "method_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+ rb_define_singleton_method(koffice_module, "const_missing", (VALUE (*) (...)) kde_module_method_missing, -1);
+}
+
+void
+set_kconfigskeletonitem_immutable(VALUE (*kconfigskeletonitem_immutable) (VALUE))
+{
+ _kconfigskeletonitem_immutable = kconfigskeletonitem_immutable;
+
+ kconfigskeleton_class = rb_define_class_under(kde_module, "ConfigSkeleton", qt_base_class);
+ kconfigskeleton_itemenum_class = rb_define_class_under(kconfigskeleton_class, "ItemEnum", qt_base_class);
+}
+
+static VALUE
+set_application_terminated(VALUE /*self*/, VALUE yn)
+{
+ application_terminated = (yn == Qtrue ? true : false);
+ return Qnil;
+}
+
+void
+Init_qtruby()
+{
+ if (qt_Smoke != 0L) {
+ // This function must have been called twice because both
+ // 'require Qt' and 'require Korundum' statements have
+ // been included in a ruby program
+ rb_fatal("require 'Qt' must not follow require 'Korundum'\n");
+ return;
+ }
+
+ init_qt_Smoke();
+ qt_Smoke->binding = new QtRubySmokeBinding(qt_Smoke);
+ install_handlers(Qt_handlers);
+
+ methcache.setAutoDelete(true);
+ classcache.setAutoDelete(true);
+
+ if (qt_module == Qnil) {
+ qt_module = rb_define_module("Qt");
+ qt_internal_module = rb_define_module_under(qt_module, "Internal");
+ qt_base_class = rb_define_class_under(qt_module, "Base", rb_cObject);
+ }
+
+ rb_define_singleton_method(qt_base_class, "new", (VALUE (*) (...)) new_qt, -1);
+ rb_define_method(qt_base_class, "initialize", (VALUE (*) (...)) initialize_qt, -1);
+ rb_define_singleton_method(qt_base_class, "method_missing", (VALUE (*) (...)) class_method_missing, -1);
+ rb_define_singleton_method(qt_module, "method_missing", (VALUE (*) (...)) module_method_missing, -1);
+ rb_define_method(qt_base_class, "method_missing", (VALUE (*) (...)) method_missing, -1);
+
+ rb_define_singleton_method(qt_base_class, "const_missing", (VALUE (*) (...)) class_method_missing, -1);
+ rb_define_singleton_method(qt_module, "const_missing", (VALUE (*) (...)) module_method_missing, -1);
+ rb_define_method(qt_base_class, "const_missing", (VALUE (*) (...)) method_missing, -1);
+
+ rb_define_method(qt_base_class, "dispose", (VALUE (*) (...)) dispose, 0);
+ rb_define_method(qt_base_class, "isDisposed", (VALUE (*) (...)) is_disposed, 0);
+ rb_define_method(qt_base_class, "disposed?", (VALUE (*) (...)) is_disposed, 0);
+
+ rb_define_method(rb_cObject, "qDebug", (VALUE (*) (...)) qdebug, 1);
+ rb_define_method(rb_cObject, "qFatal", (VALUE (*) (...)) qfatal, 1);
+ rb_define_method(rb_cObject, "qWarning", (VALUE (*) (...)) qwarning, 1);
+
+ rb_define_module_function(qt_internal_module, "getMethStat", (VALUE (*) (...)) getMethStat, 0);
+ rb_define_module_function(qt_internal_module, "getClassStat", (VALUE (*) (...)) getClassStat, 0);
+ rb_define_module_function(qt_internal_module, "getIsa", (VALUE (*) (...)) getIsa, 1);
+ rb_define_module_function(qt_internal_module, "allocateMocArguments", (VALUE (*) (...)) allocateMocArguments, 1);
+ rb_define_module_function(qt_internal_module, "setMocType", (VALUE (*) (...)) setMocType, 4);
+ rb_define_module_function(qt_internal_module, "setDebug", (VALUE (*) (...)) setDebug, 1);
+ rb_define_module_function(qt_internal_module, "debug", (VALUE (*) (...)) debugging, 0);
+ rb_define_module_function(qt_internal_module, "getTypeNameOfArg", (VALUE (*) (...)) getTypeNameOfArg, 2);
+ rb_define_module_function(qt_internal_module, "classIsa", (VALUE (*) (...)) classIsa, 2);
+ rb_define_module_function(qt_internal_module, "isEnum", (VALUE (*) (...)) isEnum, 1);
+ rb_define_module_function(qt_internal_module, "insert_pclassid", (VALUE (*) (...)) insert_pclassid, 2);
+ rb_define_module_function(qt_internal_module, "find_pclassid", (VALUE (*) (...)) find_pclassid, 1);
+ rb_define_module_function(qt_internal_module, "insert_mcid", (VALUE (*) (...)) insert_mcid, 2);
+ rb_define_module_function(qt_internal_module, "find_mcid", (VALUE (*) (...)) find_mcid, 1);
+ rb_define_module_function(qt_internal_module, "getVALUEtype", (VALUE (*) (...)) getVALUEtype, 1);
+ rb_define_module_function(qt_internal_module, "make_QUParameter", (VALUE (*) (...)) make_QUParameter, 4);
+ rb_define_module_function(qt_internal_module, "make_QMetaData", (VALUE (*) (...)) make_QMetaData, 2);
+ rb_define_module_function(qt_internal_module, "make_QUMethod", (VALUE (*) (...)) make_QUMethod, 2);
+ rb_define_module_function(qt_internal_module, "make_QMetaData_tbl", (VALUE (*) (...)) make_QMetaData_tbl, 1);
+ rb_define_module_function(qt_internal_module, "make_metaObject", (VALUE (*) (...)) make_metaObject, 6);
+ rb_define_module_function(qt_internal_module, "addMetaObjectMethods", (VALUE (*) (...)) add_metaobject_methods, 1);
+ rb_define_module_function(qt_internal_module, "addSignalMethods", (VALUE (*) (...)) add_signal_methods, 2);
+ rb_define_module_function(qt_internal_module, "mapObject", (VALUE (*) (...)) mapObject, 1);
+ // isQOjbect => isaQObject
+ rb_define_module_function(qt_internal_module, "isQObject", (VALUE (*) (...)) isaQObject, 1);
+ rb_define_module_function(qt_internal_module, "idInstance", (VALUE (*) (...)) idInstance, 1);
+ rb_define_module_function(qt_internal_module, "idClass", (VALUE (*) (...)) idClass, 1);
+ rb_define_module_function(qt_internal_module, "idMethodName", (VALUE (*) (...)) idMethodName, 1);
+ rb_define_module_function(qt_internal_module, "idMethod", (VALUE (*) (...)) idMethod, 2);
+ rb_define_module_function(qt_internal_module, "findMethod", (VALUE (*) (...)) findMethod, 2);
+ rb_define_module_function(qt_internal_module, "findAllMethods", (VALUE (*) (...)) findAllMethods, -1);
+ rb_define_module_function(qt_internal_module, "findAllMethodNames", (VALUE (*) (...)) findAllMethodNames, 3);
+ rb_define_module_function(qt_internal_module, "dumpCandidates", (VALUE (*) (...)) dumpCandidates, 1);
+ rb_define_module_function(qt_internal_module, "isObject", (VALUE (*) (...)) isObject, 1);
+ rb_define_module_function(qt_internal_module, "setCurrentMethod", (VALUE (*) (...)) setCurrentMethod, 1);
+ rb_define_module_function(qt_internal_module, "getClassList", (VALUE (*) (...)) getClassList, 0);
+ rb_define_module_function(qt_internal_module, "create_qt_class", (VALUE (*) (...)) create_qt_class, 1);
+ rb_define_module_function(qt_internal_module, "create_qobject_class", (VALUE (*) (...)) create_qobject_class, 1);
+ rb_define_module_function(qt_internal_module, "cast_object_to", (VALUE (*) (...)) cast_object_to, 2);
+ rb_define_module_function(qt_internal_module, "application_terminated=", (VALUE (*) (...)) set_application_terminated, 1);
+
+ rb_define_module_function(qt_module, "version", (VALUE (*) (...)) version, 0);
+ rb_define_module_function(qt_module, "qtruby_version", (VALUE (*) (...)) qtruby_version, 0);
+
+ rb_require("Qt/qtruby.rb");
+
+ // Do package initialization
+ rb_funcall(qt_internal_module, rb_intern("init_all_classes"), 0);
+}
+
+};
diff --git a/qtruby/rubylib/qtruby/configure.in.in b/qtruby/rubylib/qtruby/configure.in.in
new file mode 100644
index 00000000..41654f5e
--- /dev/null
+++ b/qtruby/rubylib/qtruby/configure.in.in
@@ -0,0 +1,19 @@
+AC_CHECK_PROG(RUBY, ruby, ruby)
+
+if test -z "$RUBY"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE qtruby"
+else
+ AC_MSG_CHECKING(for ruby dirs)
+ RUBY_ARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"archdir"@:>@)'`
+ RUBY_SITEARCHDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitearchdir"@:>@)'`
+ RUBY_SITEDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"sitelibdir"@:>@)'`
+ RUBY_LIBDIR=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"libdir"@:>@)'`
+ RUBY_LIBRUBYARG=`$RUBY -r rbconfig -e 'printf("%s",Config::CONFIG@<:@"LIBRUBYARG_SHARED"@:>@)'`
+ AC_MSG_RESULT([archdir $RUBY_ARCHDIR, sitearchdir $RUBY_SITEARCHDIR, sitedir $RUBY_SITEDIR, libdir $RUBY_LIBDIR, librubyarg $RUBY_LIBRUBYARG])
+ AC_SUBST(RUBY_ARCHDIR)
+ AC_SUBST(RUBY_SITEARCHDIR)
+ AC_SUBST(RUBY_SITEDIR)
+ AC_SUBST(RUBY_LIBDIR)
+ AC_SUBST(RUBY_LIBRUBYARG)
+fi
+
diff --git a/qtruby/rubylib/qtruby/extconf.rb b/qtruby/rubylib/qtruby/extconf.rb
new file mode 100644
index 00000000..0ffd2382
--- /dev/null
+++ b/qtruby/rubylib/qtruby/extconf.rb
@@ -0,0 +1,5 @@
+require 'mkmf'
+dir_config('smoke')
+dir_config('qt')
+$LOCAL_LIBS += '-lsmokeqt -lqt-mt -lstdc++'
+create_makefile("qtruby")
diff --git a/qtruby/rubylib/qtruby/handlers.cpp b/qtruby/rubylib/qtruby/handlers.cpp
new file mode 100644
index 00000000..6bddf50c
--- /dev/null
+++ b/qtruby/rubylib/qtruby/handlers.cpp
@@ -0,0 +1,1978 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qstring.h>
+#include <qregexp.h>
+#include <qapplication.h>
+#include <qcanvas.h>
+#include <qlistview.h>
+#include <qiconview.h>
+#include <qtable.h>
+#include <qpopupmenu.h>
+#include <qlayout.h>
+#include <qmetaobject.h>
+#include <qvaluelist.h>
+#include <qobjectlist.h>
+#include <qtextcodec.h>
+#include <qhostaddress.h>
+#include <qpair.h>
+
+#include <private/qucomextra_p.h>
+
+#include "smoke.h"
+
+#undef DEBUG
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#ifndef __USE_XOPEN
+#define __USE_XOPEN
+#endif
+#include <ruby.h>
+
+#include "marshall.h"
+#include "qtruby.h"
+#include "smokeruby.h"
+
+#ifndef HINT_BYTES
+#define HINT_BYTES HINT_BYTE
+#endif
+
+extern "C" {
+extern VALUE set_obj_info(const char * className, smokeruby_object * o);
+extern VALUE qt_internal_module;
+extern VALUE qvariant_class;
+extern bool application_terminated;
+};
+
+extern bool isDerivedFromByName(Smoke *smoke, const char *className, const char *baseClassName);
+extern void mapPointer(VALUE obj, smokeruby_object *o, Smoke::Index classId, void *lastptr);
+
+static const char * (*_kde_resolve_classname)(Smoke*, int, void*) = 0;
+
+extern "C" {
+
+void
+set_kde_resolve_classname(const char * (*kde_resolve_classname) (Smoke*, int, void *))
+{
+ _kde_resolve_classname = kde_resolve_classname;
+}
+
+};
+
+void
+mark_qobject_children(QObject * qobject)
+{
+ VALUE obj;
+
+ const QObjectList *l = qobject->children();
+ if (l == 0) {
+ return;
+ }
+ QObjectListIt it( *l ); // iterate over the children
+ QObject *child;
+
+ while ( (child = it.current()) != 0 ) {
+ ++it;
+ obj = getPointerObject(child);
+ if (obj != Qnil) {
+ if(do_debug & qtdb_gc) qWarning("Marking (%s*)%p -> %p\n", child->className(), child, (void*)obj);
+ rb_gc_mark(obj);
+ }
+
+ mark_qobject_children(child);
+ }
+}
+
+void
+smokeruby_mark(void * p)
+{
+ VALUE obj;
+ smokeruby_object * o = (smokeruby_object *) p;
+ const char *className = o->smoke->classes[o->classId].className;
+
+ if(do_debug & qtdb_gc) qWarning("Checking for mark (%s*)%p\n", className, o->ptr);
+
+ if(o->ptr && o->allocated) {
+ if (isDerivedFromByName(o->smoke, className, "QListView")) {
+ QListView * listview = (QListView *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QListView"));
+ QListViewItemIterator it(listview);
+ QListViewItem *item;
+
+ while ( (item = it.current()) != 0 ) {
+ ++it;
+ obj = getPointerObject(item);
+ if (obj != Qnil) {
+ if(do_debug & qtdb_gc) qWarning("Marking (%s*)%p -> %p\n", className, item, (void*)obj);
+ rb_gc_mark(obj);
+ }
+ }
+ return;
+ }
+
+ if (isDerivedFromByName(o->smoke, className, "QTable")) {
+ QTable * table = (QTable *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QTable"));
+ QTableItem *item;
+
+ for ( int row = 0; row < table->numRows(); row++ ) {
+ for ( int col = 0; col < table->numCols(); col++ ) {
+ item = table->item(row, col);
+ obj = getPointerObject(item);
+ if (obj != Qnil) {
+ if(do_debug & qtdb_gc) qWarning("Marking (%s*)%p -> %p\n", className, item, (void*)obj);
+ rb_gc_mark(obj);
+ }
+ }
+ }
+ return;
+ }
+
+ if (isDerivedFromByName(o->smoke, className, "QCanvas")) {
+ QCanvas * canvas = (QCanvas *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QCanvas"));
+ QCanvasItemList list = canvas->allItems();
+ for ( QCanvasItemList::iterator it = list.begin(); it != list.end(); ++it ) {
+ obj = getPointerObject(*it);
+ if (obj != Qnil) {
+ if(do_debug & qtdb_gc) qWarning("Marking (%s*)%p -> %p\n", className, *it, (void*)obj);
+ rb_gc_mark(obj);
+ }
+ }
+ return;
+ }
+
+ if (isDerivedFromByName(o->smoke, className, "QCanvasItem")) {
+ QCanvasItem * item = (QCanvasItem *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QCanvasItem"));
+ QCanvas * canvas = item->canvas();
+ obj = getPointerObject(canvas);
+ if (obj != Qnil) {
+ if(do_debug & qtdb_gc) qWarning("Marking (%s*)%p -> %p\n", "QCanvas", canvas, (void*)obj);
+ rb_gc_mark(obj);
+ }
+ return;
+ }
+
+ if (isDerivedFromByName(o->smoke, className, "QObject")) {
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+ mark_qobject_children(qobject);
+ return;
+ }
+ }
+}
+
+void
+smokeruby_free(void * p)
+{
+ smokeruby_object *o = (smokeruby_object*)p;
+ const char *className = o->smoke->classes[o->classId].className;
+
+ if(do_debug & qtdb_gc) qWarning("Checking for delete (%s*)%p allocated: %s\n", className, o->ptr, o->allocated ? "true" : "false");
+
+ if(application_terminated || !o->allocated || o->ptr == 0) {
+ free(o);
+ return;
+ }
+
+ unmapPointer(o, o->classId, 0);
+ object_count --;
+
+ if ( qstrcmp(className, "QObject") == 0
+ || qstrcmp(className, "QListBoxItem") == 0
+ || qstrcmp(className, "QStyleSheetItem") == 0
+ || qstrcmp(className, "KCommand") == 0
+ || qstrcmp(className, "KNamedCommand") == 0
+ || qstrcmp(className, "KMacroCommand") == 0
+ || qstrcmp(className, "KAboutData") == 0
+ || qstrcmp(className, "KCmdLineArgs") == 0
+ || qstrcmp(className, "QSqlCursor") == 0 )
+ {
+ // Don't delete instances of these classes for now
+ free(o);
+ return;
+ } else if (isDerivedFromByName(o->smoke, className, "QLayoutItem")) {
+ QLayoutItem * item = (QLayoutItem *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QLayoutItem"));
+ if (item->layout() != 0 || item->widget() != 0 || item->spacerItem() != 0) {
+ free(o);
+ return;
+ }
+ } else if (qstrcmp(className, "QIconViewItem") == 0) {
+ QIconViewItem * item = (QIconViewItem *) o->ptr;
+ if (item->iconView() != 0) {
+ free(o);
+ return;
+ }
+ } else if (qstrcmp(className, "QCheckListItem") == 0) {
+ QCheckListItem * item = (QCheckListItem *) o->ptr;
+ if (item->parent() != 0 || item->listView() != 0) {
+ free(o);
+ return;
+ }
+ } else if (qstrcmp(className, "QListViewItem") == 0) {
+ QListViewItem * item = (QListViewItem *) o->ptr;
+ if (item->parent() != 0 || item->listView() != 0) {
+ free(o);
+ return;
+ }
+ } else if (isDerivedFromByName(o->smoke, className, "QTableItem")) {
+ QTableItem * item = (QTableItem *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QTableItem"));
+ if (item->table() != 0) {
+ free(o);
+ return;
+ }
+ } else if (qstrcmp(className, "QPopupMenu") == 0) {
+ QPopupMenu * item = (QPopupMenu *) o->ptr;
+ if (item->parentWidget(false) != 0) {
+ free(o);
+ return;
+ }
+ } else if (isDerivedFromByName(o->smoke, className, "QWidget")) {
+ QWidget * qwidget = (QWidget *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QWidget"));
+ if (qwidget->parentWidget(true) != 0) {
+ free(o);
+ return;
+ }
+ } else if (isDerivedFromByName(o->smoke, className, "QObject")) {
+ QObject * qobject = (QObject *) o->smoke->cast(o->ptr, o->classId, o->smoke->idClass("QObject"));
+ if (qobject->parent() != 0) {
+ free(o);
+ return;
+ }
+ }
+
+ if(do_debug & qtdb_gc) qWarning("Deleting (%s*)%p\n", className, o->ptr);
+
+ char *methodName = new char[strlen(className) + 2];
+ methodName[0] = '~';
+ strcpy(methodName + 1, className);
+ Smoke::Index nameId = o->smoke->idMethodName(methodName);
+ Smoke::Index meth = o->smoke->findMethod(o->classId, nameId);
+ if(meth > 0) {
+ Smoke::Method &m = o->smoke->methods[o->smoke->methodMaps[meth].method];
+ Smoke::ClassFn fn = o->smoke->classes[m.classId].classFn;
+ Smoke::StackItem i[1];
+ (*fn)(m.method, o->ptr, i);
+ }
+ delete[] methodName;
+ free(o);
+
+ return;
+}
+
+/*
+ * Given an approximate classname and a qt instance, try to improve the resolution of the name
+ * by using the various Qt rtti mechanisms for QObjects, QEvents and QCanvasItems
+ */
+static const char *
+resolve_classname(Smoke* smoke, int classId, void * ptr)
+{
+ if (isDerivedFromByName(smoke, smoke->classes[classId].className, "QEvent")) {
+ QEvent * qevent = (QEvent *) smoke->cast(ptr, classId, smoke->idClass("QEvent"));
+ switch (qevent->type()) {
+ case QEvent::ChildInserted:
+ case QEvent::ChildRemoved:
+ return "Qt::ChildEvent";
+ case QEvent::Close:
+ return "Qt::CloseEvent";
+ case QEvent::ContextMenu:
+ return "Qt::ContextMenuEvent";
+// case QEvent::User:
+// return "Qt::CustomEvent";
+ case QEvent::DragEnter:
+ return "Qt::DragEnterEvent";
+ case QEvent::DragLeave:
+ return "Qt::DragLeaveEvent";
+ case QEvent::DragMove:
+ return "Qt::DragMoveEvent";
+ case QEvent::DragResponse:
+ return "Qt::DragResponseEvent";
+ case QEvent::Drop:
+ return "Qt::DropEvent";
+ case QEvent::FocusIn:
+ case QEvent::FocusOut:
+ return "Qt::FocusEvent";
+ case QEvent::Hide:
+ return "Qt::HideEvent";
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ return "Qt::KeyEvent";
+ case QEvent::IMStart:
+ case QEvent::IMCompose:
+ case QEvent::IMEnd:
+ return "Qt::IMEvent";
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ return "Qt::MouseEvent";
+ case QEvent::Move:
+ return "Qt::MoveEvent";
+ case QEvent::Paint:
+ return "Qt::PaintEvent";
+ case QEvent::Resize:
+ return "Qt::ResizeEvent";
+ case QEvent::Show:
+ return "Qt::ShowEvent";
+ // case QEvent::Tablet:
+ // return "Qt::TabletEvent";
+ case QEvent::Timer:
+ return "Qt::TimerEvent";
+ case QEvent::Wheel:
+ return "Qt::WheelEvent";
+ default:
+ break;
+ }
+ } else if (isDerivedFromByName(smoke, smoke->classes[classId].className, "QObject")) {
+ QObject * qobject = (QObject *) smoke->cast(ptr, classId, smoke->idClass("QObject"));
+ QMetaObject * meta = qobject->metaObject();
+
+ while (meta != 0) {
+ Smoke::Index classId = smoke->idClass(meta->className());
+ if (classId != 0) {
+ return smoke->binding->className(classId);
+ }
+
+ meta = meta->superClass();
+ }
+ } else if (isDerivedFromByName(smoke, smoke->classes[classId].className, "QCanvasItem")) {
+ QCanvasItem * qcanvasitem = (QCanvasItem *) smoke->cast(ptr, classId, smoke->idClass("QCanvasItem"));
+ switch (qcanvasitem->rtti()) {
+ case QCanvasItem::Rtti_Sprite:
+ return "Qt::CanvasSprite";
+ case QCanvasItem::Rtti_PolygonalItem:
+ return "Qt::CanvasPolygonalItem";
+ case QCanvasItem::Rtti_Text:
+ return "Qt::CanvasText";
+ case QCanvasItem::Rtti_Polygon:
+ return "Qt::CanvasPolygon";
+ case QCanvasItem::Rtti_Rectangle:
+ return "Qt::CanvasRectangle";
+ case QCanvasItem::Rtti_Ellipse:
+ return "Qt::CanvasEllipse";
+ case QCanvasItem::Rtti_Line:
+ return "Qt::CanvasLine";
+ case QCanvasItem::Rtti_Spline:
+ return "Qt::CanvasSpline";
+ default:
+ break;
+ }
+ } else if (isDerivedFromByName(smoke, smoke->classes[classId].className, "QListViewItem")) {
+ QListViewItem * item = (QListViewItem *) smoke->cast(ptr, classId, smoke->idClass("QListViewItem"));
+ switch (item->rtti()) {
+ case 0:
+ return "Qt::ListViewItem";
+ case 1:
+ return "Qt::CheckListItem";
+ default:
+ return "Qt::ListViewItem";
+ break;
+ }
+ } else if (isDerivedFromByName(smoke, smoke->classes[classId].className, "QTableItem")) {
+ QTableItem * item = (QTableItem *) smoke->cast(ptr, classId, smoke->idClass("QTableItem"));
+ switch (item->rtti()) {
+ case 0:
+ return "Qt::TableItem";
+ case 1:
+ return "Qt::ComboTableItem";
+ case 2:
+ return "Qt::CheckTableItem";
+ default:
+ return "Qt::TableItem";
+ break;
+ }
+ }
+
+ if (_kde_resolve_classname != 0) {
+ return (*_kde_resolve_classname)(smoke, classId, ptr);
+ }
+
+ return smoke->binding->className(classId);
+}
+
+bool
+matches_arg(Smoke *smoke, Smoke::Index meth, Smoke::Index argidx, const char *argtype)
+{
+ Smoke::Index *arg = smoke->argumentList + smoke->methods[meth].args + argidx;
+ SmokeType type = SmokeType(smoke, *arg);
+ return type.name() && qstrcmp(type.name(), argtype) == 0;
+}
+
+void *
+construct_copy(smokeruby_object *o)
+{
+ const char *className = o->smoke->className(o->classId);
+ int classNameLen = strlen(className);
+ char *ccSig = new char[classNameLen + 2]; // copy constructor signature
+ strcpy(ccSig, className);
+ strcat(ccSig, "#");
+ Smoke::Index ccId = o->smoke->idMethodName(ccSig);
+ delete[] ccSig;
+
+ char *ccArg = new char[classNameLen + 8];
+ sprintf(ccArg, "const %s&", className);
+
+ Smoke::Index ccMeth = o->smoke->findMethod(o->classId, ccId);
+
+ if(!ccMeth) {
+ delete[] ccArg;
+ return 0;
+ }
+ Smoke::Index method = o->smoke->methodMaps[ccMeth].method;
+ if(method > 0) {
+ // Make sure it's a copy constructor
+ if(!matches_arg(o->smoke, method, 0, ccArg)) {
+ delete[] ccArg;
+ return 0;
+ }
+ delete[] ccArg;
+ ccMeth = method;
+ } else {
+ // ambiguous method, pick the copy constructor
+ Smoke::Index i = -method;
+ while(o->smoke->ambiguousMethodList[i]) {
+ if(matches_arg(o->smoke, o->smoke->ambiguousMethodList[i], 0, ccArg))
+ break;
+ i++;
+ }
+ delete[] ccArg;
+ ccMeth = o->smoke->ambiguousMethodList[i];
+ if(!ccMeth)
+ return 0;
+ }
+
+ // Okay, ccMeth is the copy constructor. Time to call it.
+ Smoke::StackItem args[2];
+ args[0].s_voidp = 0;
+ args[1].s_voidp = o->ptr;
+ Smoke::ClassFn fn = o->smoke->classes[o->classId].classFn;
+ (*fn)(o->smoke->methods[ccMeth].method, 0, args);
+ return args[0].s_voidp;
+}
+
+void
+marshall_basetype(Marshall *m)
+{
+ switch(m->type().elem()) {
+ case Smoke::t_bool:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ if (TYPE(*(m->var())) == T_OBJECT) {
+ // A Qt::Boolean has been passed as a value
+ VALUE temp = rb_funcall(qt_internal_module, rb_intern("get_qboolean"), 1, *(m->var()));
+ m->item().s_bool = (temp == Qtrue ? true : false);
+ } else {
+ m->item().s_bool = (*(m->var()) == Qtrue ? true : false);
+ }
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = m->item().s_bool ? Qtrue : Qfalse;
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_char:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ m->item().s_char = NUM2CHR(*(m->var()));
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = CHR2FIX(m->item().s_char);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_uchar:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ m->item().s_uchar = NUM2CHR(*(m->var()));
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = CHR2FIX(m->item().s_uchar);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_short:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ m->item().s_short = (short) NUM2INT(*(m->var()));
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = INT2NUM(m->item().s_short);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_ushort:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ m->item().s_ushort = (unsigned short) NUM2UINT(*(m->var()));
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = UINT2NUM(m->item().s_ushort);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_int:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ if (TYPE(*(m->var())) == T_OBJECT) {
+ m->item().s_int = (int) NUM2INT(rb_funcall(qt_internal_module, rb_intern("get_qinteger"), 1, *(m->var())));
+ } else {
+ m->item().s_int = (int) NUM2INT(*(m->var()));
+ }
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = INT2NUM(m->item().s_int);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_uint:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ if (TYPE(*(m->var())) == T_OBJECT) {
+ m->item().s_int = (unsigned int) NUM2UINT(rb_funcall(qt_internal_module, rb_intern("get_qinteger"), 1, *(m->var())));
+ } else {
+ m->item().s_uint = (unsigned int) NUM2UINT(*(m->var()));
+ }
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = UINT2NUM(m->item().s_uint);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_long:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ if (TYPE(*(m->var())) == T_OBJECT) {
+ m->item().s_int = (long) NUM2LONG(rb_funcall(qt_internal_module, rb_intern("get_qinteger"), 1, *(m->var())));
+ } else {
+ m->item().s_long = (long) NUM2LONG(*(m->var()));
+ }
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = INT2NUM(m->item().s_long);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_ulong:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ if (TYPE(*(m->var())) == T_OBJECT) {
+ m->item().s_int = (unsigned long) NUM2ULONG(rb_funcall(qt_internal_module, rb_intern("get_qinteger"), 1, *(m->var())));
+ } else {
+ m->item().s_ulong = (unsigned long) NUM2ULONG(*(m->var()));
+ }
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = INT2NUM(m->item().s_ulong);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_float:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ m->item().s_float = (float) NUM2DBL(*(m->var()));
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = rb_float_new((double) m->item().s_float);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_double:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ m->item().s_double = (double) NUM2DBL(*(m->var()));
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = rb_float_new(m->item().s_double);
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_enum:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ if (TYPE(*(m->var())) == T_OBJECT) {
+ // A Qt::Enum is a subclass of Qt::Integer, so 'get_qinteger()' can be called ok
+ VALUE temp = rb_funcall(qt_internal_module, rb_intern("get_qinteger"), 1, *(m->var()));
+ m->item().s_enum = (long) NUM2LONG(temp);
+ } else {
+ m->item().s_enum = (long) NUM2LONG(*(m->var()));
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ *(m->var()) = rb_funcall( qt_internal_module,
+ rb_intern("create_qenum"),
+ 2, INT2NUM(m->item().s_enum), rb_str_new2(m->type().name()) );
+
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ case Smoke::t_class:
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ if(*(m->var()) == Qnil) {
+ m->item().s_class = 0;
+ break;
+ }
+ if(TYPE(*(m->var())) != T_DATA) {
+ rb_raise(rb_eArgError, "Invalid type, expecting %s\n", m->type().name());
+ break;
+ }
+
+ smokeruby_object *o = value_obj_info(*(m->var()));
+ if(!o || !o->ptr) {
+ if(m->type().isRef()) {
+ rb_warning("References can't be nil\n");
+ m->unsupported();
+ }
+ m->item().s_class = 0;
+ break;
+ }
+ void *ptr = o->ptr;
+ if(!m->cleanup() && m->type().isStack()) {
+ ptr = construct_copy(o);
+ }
+ const Smoke::Class &c = m->smoke()->classes[m->type().classId()];
+ ptr = o->smoke->cast(
+ ptr, // pointer
+ o->classId, // from
+ o->smoke->idClass(c.className) // to
+ );
+ m->item().s_class = ptr;
+ break;
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ if(m->item().s_voidp == 0) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ void *p = m->item().s_voidp;
+ VALUE obj = getPointerObject(p);
+ if(obj != Qnil) {
+ *(m->var()) = obj;
+ break;
+ }
+
+ smokeruby_object * o = (smokeruby_object *) malloc(sizeof(smokeruby_object));
+ o->smoke = m->smoke();
+ o->classId = m->type().classId();
+ o->ptr = p;
+ o->allocated = false;
+
+ const char * classname = resolve_classname(o->smoke, o->classId, o->ptr);
+
+ if(m->type().isConst() && m->type().isRef()) {
+ p = construct_copy( o );
+ if(p) {
+ o->ptr = p;
+ o->allocated = true;
+ }
+ }
+
+ obj = set_obj_info(classname, o);
+ if (do_debug & qtdb_calls) {
+ qWarning("allocating %s %p -> %p\n", classname, o->ptr, (void*)obj);
+ }
+
+ if(m->type().isStack()) {
+ o->allocated = true;
+ // Keep a mapping of the pointer so that it is only wrapped once as a ruby VALUE
+ mapPointer(obj, o, o->classId, 0);
+ }
+
+ *(m->var()) = obj;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static void marshall_void(Marshall * /*m*/) {}
+static void marshall_unknown(Marshall *m) {
+ m->unsupported();
+}
+
+static void marshall_charP(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE rv = *(m->var());
+ if (rv == Qnil) {
+ m->item().s_voidp = 0;
+ break;
+ }
+
+ int len = RSTRING(rv)->len;
+ char* mem = (char*) malloc(len+1);
+ memcpy(mem, StringValuePtr(rv), len);
+ mem[len] ='\0';
+ m->item().s_voidp = mem;
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ char *p = (char*)m->item().s_voidp;
+ if(p)
+ *(m->var()) = rb_str_new2(p);
+ else
+ *(m->var()) = Qnil;
+ if(m->cleanup())
+ delete[] p;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_ucharP(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE rv = *(m->var());
+ if (rv == Qnil) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int len = RSTRING(rv)->len;
+ char* mem = (char*) malloc(len+1);
+ memcpy(mem, StringValuePtr(rv), len);
+ mem[len] ='\0';
+ m->item().s_voidp = mem;
+ }
+ break;
+ case Marshall::ToVALUE:
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static const char * KCODE = 0;
+static QTextCodec *codec = 0;
+
+static void
+init_codec() {
+ VALUE temp = rb_gv_get("$KCODE");
+ KCODE = StringValuePtr(temp);
+ if (qstrcmp(KCODE, "EUC") == 0) {
+ codec = QTextCodec::codecForName("eucJP");
+ } else if (qstrcmp(KCODE, "SJIS") == 0) {
+ codec = QTextCodec::codecForName("Shift-JIS");
+ }
+}
+
+QString*
+qstringFromRString(VALUE rstring) {
+ if (KCODE == 0) {
+ init_codec();
+ }
+
+ QString * s;
+ if (qstrcmp(KCODE, "UTF8") == 0)
+ s = new QString(QString::fromUtf8(StringValuePtr(rstring), RSTRING(rstring)->len));
+ else if (qstrcmp(KCODE, "EUC") == 0)
+ s = new QString(codec->toUnicode(StringValuePtr(rstring)));
+ else if (qstrcmp(KCODE, "SJIS") == 0)
+ s = new QString(codec->toUnicode(StringValuePtr(rstring)));
+ else if(qstrcmp(KCODE, "NONE") == 0)
+ s = new QString(QString::fromLatin1(StringValuePtr(rstring)));
+ else
+ s = new QString(QString::fromLocal8Bit(StringValuePtr(rstring), RSTRING(rstring)->len));
+ return s;
+}
+
+VALUE
+rstringFromQString(QString * s) {
+ if (KCODE == 0) {
+ init_codec();
+ }
+
+ if (qstrcmp(KCODE, "UTF8") == 0)
+ return rb_str_new2(s->utf8());
+ else if (qstrcmp(KCODE, "EUC") == 0)
+ return rb_str_new2(codec->fromUnicode(*s));
+ else if (qstrcmp(KCODE, "SJIS") == 0)
+ return rb_str_new2(codec->fromUnicode(*s));
+ else if (qstrcmp(KCODE, "NONE") == 0)
+ return rb_str_new2(s->latin1());
+ else
+ return rb_str_new2(s->local8Bit());
+}
+
+static void marshall_QString(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ QString* s = 0;
+ if ( *(m->var()) != Qnil) {
+ s = qstringFromRString(*(m->var()));
+ } else {
+ s = new QString(QString::null);
+ }
+
+ m->item().s_voidp = s;
+ m->next();
+
+ if (!m->type().isConst() && *(m->var()) != Qnil && s != 0 && !s->isNull()) {
+ rb_str_resize(*(m->var()), 0);
+ VALUE temp = rstringFromQString(s);
+ rb_str_cat2(*(m->var()), StringValuePtr(temp));
+ }
+
+ if (s != 0 && m->cleanup()) {
+ delete s;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ QString *s = (QString*)m->item().s_voidp;
+ if (s != 0) {
+ if (s->isNull()) {
+ *(m->var()) = Qnil;
+ } else {
+ *(m->var()) = rstringFromQString(s);
+ }
+ if (m->cleanup() || m->type().isStack()) {
+ delete s;
+ }
+ } else {
+ *(m->var()) = Qnil;
+ }
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+// The only way to convert a QChar to a QString is to
+// pass a QChar to a QString constructor. However,
+// QStrings aren't in the QtRuby api, so add this
+// convenience method 'Qt::Char.to_s' to get a ruby
+// string from a Qt::Char.
+VALUE
+qchar_to_s(VALUE self)
+{
+ smokeruby_object *o = value_obj_info(self);
+ if (o == 0 || o->ptr == 0) {
+ return Qnil;
+ }
+
+ QChar * qchar = (QChar*) o->ptr;
+ QString s(*qchar);
+ return rstringFromQString(&s);
+}
+
+#if 0
+static const char *not_ascii(const char *s, uint &len)
+{
+ bool r = false;
+ for(; *s ; s++, len--)
+ if((uint)*s > 0x7F)
+ {
+ r = true;
+ break;
+ }
+ return r ? s : 0L;
+}
+#endif
+
+static void marshall_QCString(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ QCString *s = 0;
+ VALUE rv = *(m->var());
+ if (rv == Qnil) {
+ s = new QCString();
+ } else {
+ // Add 1 to the ruby string length to allow for a QCString '\0' terminator
+ s = new QCString(StringValuePtr(*(m->var())), RSTRING(*(m->var()))->len + 1);
+ }
+ m->item().s_voidp = s;
+
+ m->next();
+
+ if (!m->type().isConst() && rv != Qnil && s != 0) {
+ rb_str_resize(rv, 0);
+ rb_str_cat2(rv, (const char *)*s);
+ }
+ if(s && m->cleanup())
+ delete s;
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ QCString *s = (QCString*)m->item().s_voidp;
+ if(s && (const char *) *s != 0) {
+ *(m->var()) = rb_str_new2((const char *)*s);
+// const char * p = (const char *)*s;
+// uint len = s->length();
+// if(not_ascii(p,len))
+// {
+// #if PERL_VERSION == 6 && PERL_SUBVERSION == 0
+// QTextCodec* c = QTextCodec::codecForMib(106); // utf8
+// if(c->heuristicContentMatch(p,len) >= 0)
+// #else
+// if(is_utf8_string((U8 *)p,len))
+// #endif
+// SvUTF8_on(*(m->var()));
+// }
+ } else {
+ if (m->type().isConst()) {
+ *(m->var()) = Qnil;
+ } else {
+ *(m->var()) = rb_str_new2("");
+ }
+ }
+ m->next();
+
+ if (!m->type().isConst() && s != 0) {
+ *s = (const char *) StringValuePtr(*(m->var()));
+ }
+
+ if(s && m->cleanup())
+ delete s;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static void marshall_QCOORD_array(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE av = *(m->var());
+ if (TYPE(av) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int count = RARRAY(av)->len;
+ QCOORD *coord = new QCOORD[count + 2];
+ for(long i = 0; i < count; i++) {
+ VALUE svp = rb_ary_entry(av, i);
+ coord[i] = NUM2INT(svp);
+ }
+ m->item().s_voidp = coord;
+ m->next();
+ }
+ break;
+ default:
+ m->unsupported();
+ }
+}
+
+static void marshall_longlong(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ m->item().s_voidp = new long long;
+ *(long long *)m->item().s_voidp = rb_num2ll(*(m->var()));
+
+ m->next();
+
+ if(m->cleanup() && m->type().isConst()) {
+ delete (long long *) m->item().s_voidp;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ *(m->var()) = rb_ll2inum(*(long long *) m->item().s_voidp);
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static void marshall_ulonglong(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ m->item().s_voidp = new unsigned long long;
+ *(long long *)m->item().s_voidp = rb_num2ull(*(m->var()));
+
+ m->next();
+
+ if(m->cleanup() && m->type().isConst()) {
+ delete (unsigned long long *) m->item().s_voidp;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ *(m->var()) = rb_ull2inum(*(unsigned long long *) m->item().s_voidp);
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static void marshall_intR(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE rv = *(m->var());
+ int * i = new int;
+ if (TYPE(rv) == T_OBJECT) {
+ // A Qt::Integer has been passed as an integer value
+ VALUE temp = rb_funcall(qt_internal_module, rb_intern("get_qinteger"), 1, rv);
+ *i = NUM2INT(temp);
+ m->item().s_voidp = i;
+ m->next();
+ rb_funcall(qt_internal_module, rb_intern("set_qinteger"), 2, rv, INT2NUM(*i));
+ rv = temp;
+ } else {
+ *i = NUM2INT(rv);
+ m->item().s_voidp = i;
+ m->next();
+ }
+ if(m->cleanup() && m->type().isConst()) {
+ delete i;
+ } else {
+ m->item().s_voidp = new int((int)NUM2INT(rv));
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ int *ip = (int*)m->item().s_voidp;
+ VALUE rv = *(m->var());
+ if(!ip) {
+ rv = Qnil;
+ break;
+ }
+ *(m->var()) = INT2NUM(*ip);
+ m->next();
+ if(!m->type().isConst())
+ *ip = NUM2INT(*(m->var()));
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static void marshall_boolR(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE rv = *(m->var());
+ bool * b = new bool;
+ if (TYPE(rv) == T_OBJECT) {
+ // A Qt::Boolean has been passed as a value
+ VALUE temp = rb_funcall(qt_internal_module, rb_intern("get_qboolean"), 1, rv);
+ *b = (temp == Qtrue ? true : false);
+ m->item().s_voidp = b;
+ m->next();
+ rb_funcall(qt_internal_module, rb_intern("set_qboolean"), 2, rv, (*b ? Qtrue : Qfalse));
+ } else {
+ *b = (rv == Qtrue ? true : false);
+ m->item().s_voidp = b;
+ m->next();
+ }
+ if(m->cleanup() && m->type().isConst()) {
+ delete b;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ bool *ip = (bool*)m->item().s_voidp;
+ if(!ip) {
+ *(m->var()) = Qnil;
+ break;
+ }
+ *(m->var()) = (*ip?Qtrue:Qfalse);
+ m->next();
+ if(!m->type().isConst())
+ *ip = *(m->var()) == Qtrue ? true : false;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+static void marshall_charP_array(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE arglist = *(m->var());
+ if (arglist == Qnil
+ || TYPE(arglist) != T_ARRAY
+ || RARRAY(arglist)->len == 0 )
+ {
+ m->item().s_voidp = 0;
+ break;
+ }
+
+ char **argv = new char *[RARRAY(arglist)->len + 1];
+ long i;
+ for(i = 0; i < RARRAY(arglist)->len; i++) {
+ VALUE item = rb_ary_entry(arglist, i);
+ char *s = StringValuePtr(item);
+ argv[i] = new char[strlen(s) + 1];
+ strcpy(argv[i], s);
+ }
+ argv[i] = 0;
+ m->item().s_voidp = argv;
+ m->next();
+ if(m->cleanup()) {
+ rb_ary_clear(arglist);
+ for(i = 0; argv[i]; i++)
+ rb_ary_push(arglist, rb_str_new2(argv[i]));
+ }
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QStringList(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+
+ int count = RARRAY(list)->len;
+ QStringList *stringlist = new QStringList;
+
+ for(long i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+ if(TYPE(item) != T_STRING) {
+ stringlist->append(QString());
+ continue;
+ }
+ stringlist->append(*(qstringFromRString(item)));
+ }
+
+ m->item().s_voidp = stringlist;
+ m->next();
+
+
+ if (stringlist != 0 && !m->type().isConst()) {
+ rb_ary_clear(list);
+ for(QStringList::Iterator it = stringlist->begin(); it != stringlist->end(); ++it)
+ rb_ary_push(list, rstringFromQString(&(*it)));
+ }
+
+ if (m->cleanup())
+ delete stringlist;
+ break;
+ }
+ case Marshall::ToVALUE:
+ {
+ QStringList *stringlist = static_cast<QStringList *>(m->item().s_voidp);
+ if(!stringlist) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE av = rb_ary_new();
+ for(QStringList::Iterator it = stringlist->begin(); it != stringlist->end(); ++it) {
+ VALUE rv = rstringFromQString(&(*it));
+ rb_ary_push(av, rv);
+ }
+
+ if(m->cleanup())
+ delete stringlist;
+
+ *(m->var()) = av;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QStrList(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+
+ int count = RARRAY(list)->len;
+ QStrList *stringlist = new QStrList;
+
+ for(long i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+ if(TYPE(item) != T_STRING) {
+ stringlist->append(QString());
+ continue;
+ }
+ stringlist->append(QString::fromUtf8(StringValuePtr(item), RSTRING(item)->len));
+ }
+
+ m->item().s_voidp = stringlist;
+ m->next();
+
+ if (!m->type().isConst()) {
+ rb_ary_clear(list);
+ for(const char * it = stringlist->first(); it != 0; it = stringlist->next())
+ rb_ary_push(list, rb_str_new2(it));
+ }
+
+ if (m->cleanup()) {
+ delete stringlist;
+ }
+ break;
+ }
+ case Marshall::ToVALUE:
+ {
+ QStrList *stringlist = static_cast<QStrList *>(m->item().s_voidp);
+ if(!stringlist) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE av = rb_ary_new();
+ for(const char * it = stringlist->first(); it != 0; it = stringlist->next()) {
+ VALUE rv = rb_str_new2(it);
+ rb_ary_push(av, rv);
+ }
+
+ if(m->cleanup())
+ delete stringlist;
+
+ *(m->var()) = av;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+template <class Item, class ItemList, class ItemListIterator, const char *ItemSTR >
+void marshall_ItemList(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int count = RARRAY(list)->len;
+ ItemList *cpplist = new ItemList;
+ long i;
+ for(i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+ // TODO do type checking!
+ smokeruby_object *o = value_obj_info(item);
+ if(!o || !o->ptr)
+ continue;
+ void *ptr = o->ptr;
+ ptr = o->smoke->cast(
+ ptr, // pointer
+ o->classId, // from
+ o->smoke->idClass(ItemSTR) // to
+ );
+ cpplist->append((Item*)ptr);
+ }
+
+ m->item().s_voidp = cpplist;
+ m->next();
+
+ if (!m->type().isConst()) {
+ rb_ary_clear(list);
+ for(ItemListIterator it = cpplist->begin();
+ it != cpplist->end();
+ ++it )
+ {
+ VALUE obj = getPointerObject((void*)(*it));
+ rb_ary_push(list, obj);
+ }
+ }
+
+ if (m->cleanup()) {
+ delete cpplist;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ ItemList *valuelist = (ItemList*)m->item().s_voidp;
+ if(!valuelist) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE av = rb_ary_new();
+
+ for(ItemListIterator it = valuelist->begin();
+ it != valuelist->end();
+ ++it) {
+ void *p = *it;
+
+ if(m->item().s_voidp == 0) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE obj = getPointerObject(p);
+ if(obj == Qnil) {
+ smokeruby_object * o = ALLOC(smokeruby_object);
+ o->smoke = m->smoke();
+ o->classId = m->smoke()->idClass(ItemSTR);
+ o->ptr = p;
+ o->allocated = false;
+ obj = set_obj_info(resolve_classname(o->smoke, o->classId, o->ptr), o);
+ }
+ rb_ary_push(av, obj);
+ }
+
+ if(m->cleanup())
+ delete valuelist;
+ else
+ *(m->var()) = av;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QValueListInt(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int count = RARRAY(list)->len;
+ QValueList<int> *valuelist = new QValueList<int>;
+ long i;
+ for(i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+ if(TYPE(item) != T_FIXNUM && TYPE(item) != T_BIGNUM) {
+ valuelist->append(0);
+ continue;
+ }
+ valuelist->append(NUM2INT(item));
+ }
+
+ m->item().s_voidp = valuelist;
+ m->next();
+
+ if (!m->type().isConst()) {
+ rb_ary_clear(list);
+ for(QValueListIterator<int> it = valuelist->begin();
+ it != valuelist->end();
+ ++it)
+ rb_ary_push(list, INT2NUM((int)*it));
+ }
+
+ if (m->cleanup()) {
+ delete valuelist;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ QValueList<int> *valuelist = (QValueList<int>*)m->item().s_voidp;
+ if(!valuelist) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE av = rb_ary_new();
+
+ for(QValueListIterator<int> it = valuelist->begin();
+ it != valuelist->end();
+ ++it)
+ rb_ary_push(av, INT2NUM(*it));
+
+ *(m->var()) = av;
+
+ if(m->cleanup())
+ delete valuelist;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_voidP(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE rv = *(m->var());
+ if (rv != Qnil)
+ m->item().s_voidp = (void*)NUM2INT(*(m->var()));
+ else
+ m->item().s_voidp = 0;
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ *(m->var()) = Data_Wrap_Struct(rb_cObject, 0, 0, m->item().s_voidp);
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QMapQStringQString(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE hash = *(m->var());
+ if (TYPE(hash) != T_HASH) {
+ m->item().s_voidp = 0;
+ break;
+ }
+
+ QMap<QString,QString> * map = new QMap<QString,QString>;
+
+ // Convert the ruby hash to an array of key/value arrays
+ VALUE temp = rb_funcall(hash, rb_intern("to_a"), 0);
+
+ for (long i = 0; i < RARRAY(temp)->len; i++) {
+ VALUE key = rb_ary_entry(rb_ary_entry(temp, i), 0);
+ VALUE value = rb_ary_entry(rb_ary_entry(temp, i), 1);
+ (*map)[QString(StringValuePtr(key))] = QString(StringValuePtr(value));
+ }
+
+ m->item().s_voidp = map;
+ m->next();
+
+ if(m->cleanup())
+ delete map;
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ QMap<QString,QString> *map = (QMap<QString,QString>*)m->item().s_voidp;
+ if(!map) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE hv = rb_hash_new();
+
+ QMap<QString,QString>::Iterator it;
+ for (it = map->begin(); it != map->end(); ++it) {
+ rb_hash_aset(hv, rstringFromQString((QString*)&(it.key())), rstringFromQString((QString*) &(it.data())));
+ }
+
+ *(m->var()) = hv;
+ m->next();
+
+ if(m->cleanup())
+ delete map;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QMapQStringQVariant(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE hash = *(m->var());
+ if (TYPE(hash) != T_HASH) {
+ m->item().s_voidp = 0;
+ break;
+ }
+
+ QMap<QString,QVariant> * map = new QMap<QString,QVariant>;
+
+ // Convert the ruby hash to an array of key/value arrays
+ VALUE temp = rb_funcall(hash, rb_intern("to_a"), 0);
+
+ for (long i = 0; i < RARRAY(temp)->len; i++) {
+ VALUE key = rb_ary_entry(rb_ary_entry(temp, i), 0);
+ VALUE value = rb_ary_entry(rb_ary_entry(temp, i), 1);
+
+ smokeruby_object *o = value_obj_info(value);
+ if (!o || !o->ptr || o->classId != o->smoke->idClass("QVariant")) {
+ // If the value isn't a Qt::Variant, then try and construct
+ // a Qt::Variant from it
+ value = rb_funcall(qvariant_class, rb_intern("new"), 1, value);
+ if (value == Qnil) {
+ continue;
+ }
+ o = value_obj_info(value);
+ }
+
+ void * ptr = o->ptr;
+ ptr = o->smoke->cast(ptr, o->classId, o->smoke->idClass("QVariant"));
+
+ (*map)[QString(StringValuePtr(key))] = (QVariant)*(QVariant*)ptr;
+ }
+
+ m->item().s_voidp = map;
+ m->next();
+
+ if(m->cleanup())
+ delete map;
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ QMap<QString,QVariant> *map = (QMap<QString,QVariant>*)m->item().s_voidp;
+ if(!map) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE hv = rb_hash_new();
+
+ QMap<QString,QVariant>::Iterator it;
+ for (it = map->begin(); it != map->end(); ++it) {
+ void *p = new QVariant(it.data());
+ VALUE obj = getPointerObject(p);
+
+ if (obj == Qnil) {
+ smokeruby_object * o = ALLOC(smokeruby_object);
+ o->classId = m->smoke()->idClass("QVariant");
+ o->smoke = m->smoke();
+ o->ptr = p;
+ o->allocated = true;
+ obj = set_obj_info("Qt::Variant", o);
+ }
+
+ rb_hash_aset(hv, rstringFromQString((QString*)&(it.key())), obj);
+ }
+
+ *(m->var()) = hv;
+ m->next();
+
+ if(m->cleanup())
+ delete map;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QUObject(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE array = *(m->var());
+ if (array != Qnil && TYPE(array) == T_ARRAY) {
+ VALUE rv = rb_ary_entry(array, 0);
+ Data_Get_Struct(rv, QUObject, m->item().s_voidp);
+ } else {
+ m->item().s_voidp = 0;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ VALUE rv = Data_Wrap_Struct(rb_cObject, 0, 0, m->item().s_voidp);
+ VALUE array = rb_ary_new2(1);
+ rb_ary_push(array, rv);
+ *(m->var()) = array;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QRgb_array(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int count = RARRAY(list)->len;
+ QRgb *rgb = new QRgb[count + 2];
+ long i;
+ for(i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+ if(TYPE(item) != T_FIXNUM && TYPE(item) != T_BIGNUM) {
+ rgb[i] = 0;
+ continue;
+ }
+
+ rgb[i] = NUM2UINT(item);
+ }
+ m->item().s_voidp = rgb;
+ m->next();
+ }
+ break;
+ case Marshall::ToVALUE:
+ // Implement this with a tied array or something
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+void marshall_QPairintint(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY || RARRAY(list)->len != 2) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int int0;
+ int int1;
+ VALUE item = rb_ary_entry(list, 0);
+ if(TYPE(item) != T_FIXNUM && TYPE(item) != T_BIGNUM) {
+ int0 = 0;
+ } else {
+ int0 = NUM2INT(item);
+ }
+
+ item = rb_ary_entry(list, 1);
+ if(TYPE(item) != T_FIXNUM && TYPE(item) != T_BIGNUM) {
+ int1 = 0;
+ } else {
+ int1 = NUM2INT(item);
+ }
+
+ QPair<int,int> * qpair = new QPair<int,int>(int0,int1);
+ m->item().s_voidp = qpair;
+ m->next();
+ if(m->cleanup())
+ delete qpair;
+ }
+ break;
+ case Marshall::ToVALUE:
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+#define DEF_LIST_MARSHALLER(ListIdent,ItemList,Item,Itr) namespace { char ListIdent##STR[] = #Item; }; \
+ Marshall::HandlerFn marshall_##ListIdent = marshall_ItemList<Item,ItemList,Itr,ListIdent##STR>;
+
+#include <qcanvas.h>
+#include <qdir.h>
+#include <qobjectlist.h>
+#include <qwidgetlist.h>
+#include <qdockwindow.h>
+#include <qnetworkprotocol.h>
+#include <qtoolbar.h>
+#include <qtabbar.h>
+
+#if QT_VERSION >= 0x030200
+DEF_LIST_MARSHALLER( QPtrListQNetworkOperation, QPtrList<QNetworkOperation>, QNetworkOperation, QPtrListStdIterator<QNetworkOperation> )
+DEF_LIST_MARSHALLER( QPtrListQToolBar, QPtrList<QToolBar>, QToolBar, QPtrListStdIterator<QToolBar> )
+DEF_LIST_MARSHALLER( QPtrListQTab, QPtrList<QTab>, QTab, QPtrListStdIterator<QTab> )
+DEF_LIST_MARSHALLER( QPtrListQDockWindow, QPtrList<QDockWindow>, QDockWindow, QPtrListStdIterator<QDockWindow> )
+DEF_LIST_MARSHALLER( QFileInfoList, QFileInfoList, QFileInfo, QFileInfoList::Iterator )
+DEF_LIST_MARSHALLER( QObjectList, QObjectList, QObject, QPtrListStdIterator<QObject> )
+DEF_LIST_MARSHALLER( QWidgetList, QWidgetList, QWidget, QPtrListStdIterator<QWidget> )
+#endif
+
+DEF_LIST_MARSHALLER( QCanvasItemList, QCanvasItemList, QCanvasItem, QValueListIterator<QCanvasItem*> )
+
+template <class Item, class ItemList, class ItemListIterator, const char *ItemSTR >
+void marshall_ValueItemList(Marshall *m) {
+ switch(m->action()) {
+ case Marshall::FromVALUE:
+ {
+ VALUE list = *(m->var());
+ if (TYPE(list) != T_ARRAY) {
+ m->item().s_voidp = 0;
+ break;
+ }
+ int count = RARRAY(list)->len;
+ ItemList *cpplist = new ItemList;
+ long i;
+ for(i = 0; i < count; i++) {
+ VALUE item = rb_ary_entry(list, i);
+ // TODO do type checking!
+ smokeruby_object *o = value_obj_info(item);
+
+ // Special case for the QValueList<QVariant> type
+ if ( qstrcmp(ItemSTR, "QVariant") == 0
+ && (!o || !o->ptr || o->classId != o->smoke->idClass("QVariant")) )
+ {
+ // If the value isn't a Qt::Variant, then try and construct
+ // a Qt::Variant from it
+ item = rb_funcall(qvariant_class, rb_intern("new"), 1, item);
+ if (item == Qnil) {
+ continue;
+ }
+ o = value_obj_info(item);
+ }
+
+ if(!o || !o->ptr)
+ continue;
+ void *ptr = o->ptr;
+ ptr = o->smoke->cast(
+ ptr, // pointer
+ o->classId, // from
+ o->smoke->idClass(ItemSTR) // to
+ );
+ cpplist->append(*(Item*)ptr);
+ }
+
+ m->item().s_voidp = cpplist;
+ m->next();
+
+ if (!m->type().isConst()) {
+ rb_ary_clear(list);
+ for(ItemListIterator it = cpplist->begin();
+ it != cpplist->end();
+ ++it)
+ {
+ VALUE obj = getPointerObject((void*)&(*it));
+ rb_ary_push(list, obj);
+ }
+ }
+
+ if (m->cleanup()) {
+ delete cpplist;
+ }
+ }
+ break;
+ case Marshall::ToVALUE:
+ {
+ ItemList *valuelist = (ItemList*)m->item().s_voidp;
+ if(!valuelist) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE av = rb_ary_new();
+
+ int ix = m->smoke()->idClass(ItemSTR);
+ const char * className = m->smoke()->binding->className(ix);
+
+ for(ItemListIterator it = valuelist->begin();
+ it != valuelist->end();
+ ++it) {
+ void *p = &(*it);
+
+ if(m->item().s_voidp == 0) {
+ *(m->var()) = Qnil;
+ break;
+ }
+
+ VALUE obj = getPointerObject(p);
+ if(obj == Qnil) {
+ smokeruby_object * o = ALLOC(smokeruby_object);
+ o->smoke = m->smoke();
+ o->classId = o->smoke->idClass(ItemSTR);
+ o->ptr = p;
+ o->allocated = false;
+ obj = set_obj_info(className, o);
+ }
+ rb_ary_push(av, obj);
+ }
+
+ if(m->cleanup())
+ delete valuelist;
+ else
+ *(m->var()) = av;
+ }
+ break;
+ default:
+ m->unsupported();
+ break;
+ }
+}
+
+#define DEF_VALUELIST_MARSHALLER(ListIdent,ItemList,Item,Itr) namespace dummy { char ListIdent##STR[] = #Item; }; \
+ Marshall::HandlerFn marshall_##ListIdent = marshall_ValueItemList<Item,ItemList,Itr,dummy::ListIdent##STR>;
+
+DEF_VALUELIST_MARSHALLER( QVariantList, QValueList<QVariant>, QVariant, QValueList<QVariant>::Iterator )
+DEF_VALUELIST_MARSHALLER( QPixmapList, QValueList<QPixmap>, QPixmap, QValueList<QPixmap>::Iterator )
+DEF_VALUELIST_MARSHALLER( QIconDragItemList, QValueList<QIconDragItem>, QIconDragItem, QValueList<QIconDragItem>::Iterator )
+DEF_VALUELIST_MARSHALLER( QImageTextKeyLangList, QValueList<QImageTextKeyLang>, QImageTextKeyLang, QValueList<QImageTextKeyLang>::Iterator )
+DEF_VALUELIST_MARSHALLER( QUrlInfoList, QValueList<QUrlInfo>, QUrlInfo, QValueList<QUrlInfo>::Iterator )
+DEF_VALUELIST_MARSHALLER( QTranslatorMessageList, QValueList<QTranslatorMessage>, QTranslatorMessage, QValueList<QTranslatorMessage>::Iterator )
+DEF_VALUELIST_MARSHALLER( QHostAddressList, QValueList<QHostAddress>, QHostAddress, QValueList<QHostAddress>::Iterator )
+
+TypeHandler Qt_handlers[] = {
+ { "QString", marshall_QString },
+ { "QString&", marshall_QString },
+ { "QString*", marshall_QString },
+ { "QCString", marshall_QCString },
+ { "QCString&", marshall_QCString },
+ { "QCString*", marshall_QCString },
+ { "QStringList", marshall_QStringList },
+ { "QStringList&", marshall_QStringList },
+ { "QStringList*", marshall_QStringList },
+ { "QStrList", marshall_QStrList },
+ { "QStrList&", marshall_QStrList },
+ { "QStrList*", marshall_QStrList },
+ { "long long int", marshall_longlong },
+ { "long long int&", marshall_longlong },
+ { "Q_INT64", marshall_longlong },
+ { "Q_INT64&", marshall_longlong },
+ { "Q_LLONG", marshall_longlong },
+ { "Q_LLONG&", marshall_longlong },
+ { "KIO::filesize_t", marshall_longlong },
+ { "DOM::DOMTimeStamp", marshall_ulonglong },
+ { "unsigned long long int", marshall_ulonglong },
+ { "unsigned long long int&", marshall_ulonglong },
+ { "Q_UINT64", marshall_ulonglong },
+ { "Q_UINT64&", marshall_ulonglong },
+ { "Q_ULLONG", marshall_ulonglong },
+ { "Q_ULLONG&", marshall_ulonglong },
+ { "signed int&", marshall_intR },
+ { "int&", marshall_intR },
+ { "int*", marshall_intR },
+ { "bool&", marshall_boolR },
+ { "bool*", marshall_boolR },
+ { "char*", marshall_charP },
+ { "char**", marshall_charP_array },
+ { "uchar*", marshall_ucharP },
+ { "QRgb*", marshall_QRgb_array },
+ { "QPair<int,int>&", marshall_QPairintint },
+ { "QUObject*", marshall_QUObject },
+ { "const QCOORD*", marshall_QCOORD_array },
+ { "void", marshall_void },
+ { "QValueList<int>", marshall_QValueListInt },
+ { "QValueList<int>&", marshall_QValueListInt },
+ { "QValueList<QVariant>", marshall_QVariantList },
+ { "QValueList<QVariant>&", marshall_QVariantList },
+ { "QValueList<QPixmap>", marshall_QPixmapList },
+ { "QValueList<QIconDragItem>&", marshall_QIconDragItemList },
+ { "QValueList<QImageTextKeyLang>", marshall_QImageTextKeyLangList },
+ { "QValueList<QUrlInfo>&", marshall_QUrlInfoList },
+ { "QValueList<QTranslatorMessage>", marshall_QTranslatorMessageList },
+ { "QValueList<QHostAddress>", marshall_QHostAddressList },
+ { "QCanvasItemList", marshall_QCanvasItemList },
+ { "QMap<QString,QString>", marshall_QMapQStringQString },
+ { "QMap<QString,QString>&", marshall_QMapQStringQString },
+ { "QMap<QString,QVariant>", marshall_QMapQStringQVariant },
+ { "QMap<QString,QVariant>&", marshall_QMapQStringQVariant },
+#if QT_VERSION >= 0x030200
+ { "QWidgetList", marshall_QWidgetList },
+ { "QWidgetList*", marshall_QWidgetList },
+ { "QWidgetList&", marshall_QWidgetList },
+ { "QObjectList*", marshall_QObjectList },
+ { "QObjectList&", marshall_QObjectList },
+ { "QFileInfoList*", marshall_QFileInfoList },
+ { "QPtrList<QToolBar>", marshall_QPtrListQToolBar },
+ { "QPtrList<QTab>*", marshall_QPtrListQTab },
+ { "QPtrList<QDockWindow>", marshall_QPtrListQDockWindow },
+ { "QPtrList<QDockWindow>*", marshall_QPtrListQDockWindow },
+ { "QPtrList<QNetworkOperation>", marshall_QPtrListQNetworkOperation },
+ { "QPtrList<QNetworkOperation>&", marshall_QPtrListQNetworkOperation },
+#endif
+ { 0, 0 }
+};
+
+QAsciiDict<TypeHandler> type_handlers(199);
+
+void install_handlers(TypeHandler *h) {
+ while(h->name) {
+ type_handlers.insert(h->name, h);
+ h++;
+ }
+}
+
+Marshall::HandlerFn getMarshallFn(const SmokeType &type) {
+ if(type.elem())
+ return marshall_basetype;
+ if(!type.name())
+ return marshall_void;
+ TypeHandler *h = type_handlers[type.name()];
+ if(h == 0 && type.isConst() && strlen(type.name()) > strlen("const ")) {
+ h = type_handlers[type.name() + strlen("const ")];
+ }
+
+ if(h != 0) {
+ return h->fn;
+ }
+
+ return marshall_unknown;
+}
diff --git a/qtruby/rubylib/qtruby/lib/Makefile.am b/qtruby/rubylib/qtruby/lib/Makefile.am
new file mode 100644
index 00000000..e8f6457a
--- /dev/null
+++ b/qtruby/rubylib/qtruby/lib/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = Qt
+
+rubylibdir = $(RUBY_SITEDIR)
+rubylib_DATA = Qt.rb
diff --git a/qtruby/rubylib/qtruby/lib/Qt.rb b/qtruby/rubylib/qtruby/lib/Qt.rb
new file mode 100644
index 00000000..70e9c776
--- /dev/null
+++ b/qtruby/rubylib/qtruby/lib/Qt.rb
@@ -0,0 +1 @@
+require 'qtruby'
diff --git a/qtruby/rubylib/qtruby/lib/Qt/Makefile.am b/qtruby/rubylib/qtruby/lib/Qt/Makefile.am
new file mode 100644
index 00000000..267582ef
--- /dev/null
+++ b/qtruby/rubylib/qtruby/lib/Qt/Makefile.am
@@ -0,0 +1,2 @@
+qtrubylibdir = $(RUBY_SITEDIR)/Qt
+qtrubylib_DATA = qtruby.rb
diff --git a/qtruby/rubylib/qtruby/lib/Qt/qtruby.rb b/qtruby/rubylib/qtruby/lib/Qt/qtruby.rb
new file mode 100644
index 00000000..50f2eaef
--- /dev/null
+++ b/qtruby/rubylib/qtruby/lib/Qt/qtruby.rb
@@ -0,0 +1,1978 @@
+=begin
+/***************************************************************************
+ qtruby.rb - description
+ -------------------
+ begin : Fri Jul 4 2003
+ copyright : (C) 2003 by Richard Dale
+ email : Richard_Dale@tipitina.demon.co.uk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+=end
+
+module Qt
+ module DebugLevel
+ Off, Minimal, High, Extensive = 0, 1, 2, 3
+ end
+
+ module QtDebugChannel
+ QTDB_NONE = 0x00
+ QTDB_AMBIGUOUS = 0x01
+ QTDB_METHOD_MISSING = 0x02
+ QTDB_CALLS = 0x04
+ QTDB_GC = 0x08
+ QTDB_VIRTUAL = 0x10
+ QTDB_VERBOSE = 0x20
+ QTDB_ALL = QTDB_VERBOSE | QTDB_VIRTUAL | QTDB_GC | QTDB_CALLS | QTDB_METHOD_MISSING | QTDB_AMBIGUOUS
+ end
+
+ @@debug_level = DebugLevel::Off
+ def Qt.debug_level=(level)
+ @@debug_level = level
+ Internal::setDebug Qt::QtDebugChannel::QTDB_ALL if level >= DebugLevel::Extensive
+ end
+
+ def Qt.debug_level
+ @@debug_level
+ end
+
+ class Base
+ def self.signals(*signal_list)
+ meta = Qt::Meta[self.name] || Qt::MetaInfo.new(self)
+ meta.add_signals(signal_list)
+ meta.changed = true
+ end
+
+ def self.slots(*slot_list)
+ meta = Qt::Meta[self.name] || Qt::MetaInfo.new(self)
+ meta.add_slots(slot_list)
+ meta.changed = true
+ end
+
+ def **(a)
+ return Qt::**(self, a)
+ end
+ def +(a)
+ return Qt::+(self, a)
+ end
+ def ~(a)
+ return Qt::~(self, a)
+ end
+ def -@()
+ return Qt::-(self)
+ end
+ def -(a)
+ return Qt::-(self, a)
+ end
+ def *(a)
+ return Qt::*(self, a)
+ end
+ def /(a)
+ return Qt::/(self, a)
+ end
+ def %(a)
+ return Qt::%(self, a)
+ end
+ def >>(a)
+ return Qt::>>(self, a)
+ end
+ def <<(a)
+ return Qt::<<(self, a)
+ end
+ def &(a)
+ return Qt::&(self, a)
+ end
+ def ^(a)
+ return Qt::^(self, a)
+ end
+ def |(a)
+ return Qt::|(self, a)
+ end
+
+# Module has '<', '<=', '>' and '>=' operator instance methods, so pretend they
+# don't exist by calling method_missing() explicitely
+ def <(a)
+ begin
+ Qt::method_missing(:<, self, a)
+ rescue
+ super(a)
+ end
+ end
+
+ def <=(a)
+ begin
+ Qt::method_missing(:<=, self, a)
+ rescue
+ super(a)
+ end
+ end
+
+ def >(a)
+ begin
+ Qt::method_missing(:>, self, a)
+ rescue
+ super(a)
+ end
+ end
+
+ def >=(a)
+ begin
+ Qt::method_missing(:>=, self, a)
+ rescue
+ super(a)
+ end
+ end
+
+# Object has a '==' operator instance method, so pretend it
+# don't exist by calling method_missing() explicitely
+ def ==(a)
+ begin
+ Qt::method_missing(:==, self, a)
+ rescue
+ super(a)
+ end
+ end
+
+ def methods(regular=true)
+ if !regular
+ return singleton_methods
+ end
+
+ qt_methods(super, 0x0)
+ end
+
+ def protected_methods
+ # From smoke.h, Smoke::mf_protected 0x80
+ qt_methods(super, 0x80)
+ end
+
+ def public_methods
+ methods
+ end
+
+ def singleton_methods
+ # From smoke.h, Smoke::mf_static 0x01
+ qt_methods(super, 0x01)
+ end
+
+ private
+ def qt_methods(meths, flags)
+ ids = []
+ # These methods are all defined in Qt::Base, even if they aren't supported by a particular
+ # subclass, so remove them to avoid confusion
+ meths -= ["%", "&", "*", "**", "+", "-", "-@", "/", "<", "<<", "<=", ">", ">=", ">>", "|", "~", "^"]
+ classid = Qt::Internal::idInstance(self)
+ Qt::Internal::getAllParents(classid, ids)
+ ids << classid
+ ids.each { |c| Qt::Internal::findAllMethodNames(meths, c, flags) }
+ return meths.uniq
+ end
+ end # Qt::Base
+
+ # Delete the underlying C++ instance after exec returns
+ # Otherwise, rb_gc_call_finalizer_at_exit() can delete
+ # stuff that Qt::Application still needs for its cleanup.
+ class Application < Qt::Base
+ def exec
+ method_missing(:exec)
+ self.dispose
+ Qt::Internal.application_terminated = true
+ end
+
+ def exit(*args)
+ method_missing(:exit, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class BoxLayout < Qt::Base
+ include Enumerable
+
+ def each
+ it = iterator()
+ while it.current
+ yield it.current
+ it += 1
+ end
+ end
+ end
+
+ class Buffer < Qt::Base
+ def open(*args)
+ method_missing(:open, *args)
+ end
+ end
+
+ class ButtonGroup < Qt::Base
+ def id(*args)
+ method_missing(:id, *args)
+ end
+ end
+
+ class ByteArray < Qt::Base
+ def to_s
+ return data()
+ end
+
+ def length
+ return size()
+ end
+
+ def data=(data)
+ setRawData(data)
+ end
+ end
+
+ class CheckListItem < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class ChildEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class ClassInfo < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class CloseEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Color < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " %s>" % name)
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, " %s>" % name)
+ end
+
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Connection < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " memberName=%s, memberType=%s, object=%s>" %
+ [memberName.inspect, memberType == 1 ? "SLOT" : "SIGNAL", object.inspect] )
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, "\n memberName=%s,\n memberType=%s,\n object=%s>" %
+ [memberName.inspect, memberType == 1 ? "SLOT" : "SIGNAL", object.inspect] )
+ end
+ end
+
+ class ContextMenuEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Cursor < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " shape=%d>" % shape)
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, " shape=%d>" % shape)
+ end
+ end
+
+ class CustomEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Date < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " %s>" % toString)
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, " %s>" % toString)
+ end
+ end
+
+ class DateTime < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " %s>" % toString)
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, " %s>" % toString)
+ end
+ end
+
+ class Dialog < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+ end
+
+ class DomAttr < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class DomDocumentType < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class DragLeaveEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class DropEvent < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class EucJpCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class EucKrCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Event < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class EventLoop < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+
+ def exit(*args)
+ method_missing(:exit, *args)
+ end
+ end
+
+ class File < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+
+ def open(*args)
+ method_missing(:open, *args)
+ end
+ end
+
+ class FocusEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Font < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " family=%s, pointSize=%d, weight=%d, italic=%s, bold=%s, underline=%s, strikeOut=%s>" %
+ [family.inspect, pointSize, weight, italic, bold, underline, strikeOut])
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, "\n family=%s,\n pointSize=%d,\n weight=%d,\n italic=%s,\n bold=%s,\n underline=%s,\n strikeOut=%s>" %
+ [family.inspect, pointSize, weight, italic, bold, underline, strikeOut])
+ end
+ end
+
+ class Ftp < Qt::Base
+ def abort(*args)
+ method_missing(:abort, *args)
+ end
+ end
+
+ class GLContext < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class GLWidget < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class Gb18030Codec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Gb2312Codec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class GbkCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class GridLayout < Qt::Base
+ include Enumerable
+
+ def each
+ it = iterator()
+ while it.current
+ yield it.current
+ it += 1
+ end
+ end
+ end
+
+ class HBoxLayout < Qt::Base
+ include Enumerable
+
+ def each
+ it = iterator()
+ while it.current
+ yield it.current
+ it += 1
+ end
+ end
+ end
+
+ class HebrewCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class HideEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Http < Qt::Base
+ def abort(*args)
+ method_missing(:abort, *args)
+ end
+ end
+
+ class HttpRequestHeader < Qt::Base
+ def method(*args)
+ method_missing(:method, *args)
+ end
+ end
+
+ class IconDrag < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Image < Qt::Base
+ def load(*args)
+ method_missing(:load, *args)
+ end
+ end
+
+ class ImageDecoder < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class ImageDrag < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class ImageIO < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class IMEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class JisCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class KeyEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class LCDNumber < Qt::Base
+ def display(item)
+ method_missing(:display, item)
+ end
+ end
+
+ class Layout < Qt::Base
+ def freeze(*args)
+ method_missing(:freeze, *args)
+ end
+ end
+
+ class LayoutIterator < Qt::Base
+ def +(a)
+ for i in 1..a
+ send("operator++".to_sym)
+ end
+ return self
+ end
+ end
+
+ class Library < Qt::Base
+ def load(*args)
+ method_missing(:load, *args)
+ end
+ end
+
+ class ListView < Qt::Base
+ include Enumerable
+
+ def each
+ it = Qt::ListViewItemIterator.new(self)
+ while it.current
+ yield it.current
+ it += 1
+ end
+ end
+
+ def sort(*args)
+ method_missing(:sort, *args)
+ end
+ end
+
+ class ListViewItem < Qt::Base
+ include Enumerable
+
+ def each
+ it = Qt::ListViewItemIterator.new(self)
+ while it.current
+ yield it.current
+ it += 1
+ end
+ end
+
+ def sort(*args)
+ method_missing(:sort, *args)
+ end
+
+ def inspect
+ str = super
+ str.sub!(/>$/, "")
+ for i in 0..(listView.columns - 1)
+ str << " text%d=%s," % [i, self.text(i)]
+ end
+ str.sub!(/,?$/, ">")
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ str.sub!(/>$/, "")
+ for i in 0..(listView.columns - 1)
+ str << " text%d=%s," % [i, self.text(i)]
+ end
+ str.sub!(/,?$/, ">")
+ pp.text str
+ end
+ end
+
+ class Locale < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ def system(*args)
+ method_missing(:system, *args)
+ end
+ end
+
+ class MenuItem < Qt::Base
+ def id(*args)
+ method_missing(:id, *args)
+ end
+ end
+
+ class MetaData < Qt::Base
+ def method(*args)
+ method_missing(:method, *args)
+ end
+
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class MetaEnum < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class MetaProperty < Qt::Base
+ def id(*args)
+ method_missing(:id, *args)
+ end
+
+ def name(*args)
+ method_missing(:name, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class MouseEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class MoveEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Object < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class PaintEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Picture < Qt::Base
+ def load(*args)
+ method_missing(:load, *args)
+ end
+ end
+
+ class Pixmap < Qt::Base
+ def load(*args)
+ method_missing(:load, *args)
+ end
+ end
+
+ class Point < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " x=%d, y=%d>" % [x, y])
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, "\n x=%d,\n y=%d>" % [x, y])
+ end
+ end
+
+ class PolygonScanner < Qt::Base
+ def scan(*args)
+ method_missing(:scan, *args)
+ end
+ end
+
+ class PopupMenu < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+ end
+
+ class Printer < Qt::Base
+ def abort(*args)
+ method_missing(:abort, *args)
+ end
+ end
+
+ class MetaObject < Qt::Base
+ def inspect
+ str = super
+ str.sub!(/>$/, "")
+ str << " className=%s," % className
+ str << " propertyNames=Array (%d element(s))," % numProperties unless numProperties == 0
+ str << " signalNames=Array (%d element(s))," % numSignals unless numSignals == 0
+ str << " slotNames=Array (%d element(s))," % numSlots unless numSlots == 0
+ str << " superClass=%s," % superClass.inspect unless superClass == nil
+ str.chop!
+ str << ">"
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ str.sub!(/>$/, "")
+ str << "\n className=%s," % className
+ str << "\n propertyNames=Array (%d element(s))," % numProperties unless numProperties == 0
+ str << "\n signalNames=Array (%d element(s))," % numSignals unless numSignals == 0
+ str << "\n slotNames=Array (%d element(s))," % numSlots unless numSlots == 0
+ str << "\n superClass=%s," % superClass.inspect unless superClass == nil
+ str.chop!
+ str << ">"
+ pp.text str
+ end
+ end
+
+ class Rect < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " left=%d, right=%d, top=%d, bottom=%d>" % [left, right, top, bottom])
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, "\n left=%d,\n right=%d,\n top=%d,\n bottom=%d>" % [left, right, top, bottom])
+ end
+ end
+
+ class ResizeEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class ShowEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Size < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " width=%d, height=%d>" % [width, height])
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, "\n width=%d,\n height=%d>" % [width, height])
+ end
+ end
+
+ class SizePolicy < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " horData=%d, verData=%d>" % [horData, verData])
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, "\n horData=%d,\n verData=%d>" % [horData, verData])
+ end
+ end
+
+ class SjisCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Socket < Qt::Base
+ def open(*args)
+ method_missing(:open, *args)
+ end
+ end
+
+ class SocketDevice < Qt::Base
+ def open(*args)
+ method_missing(:open, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class SocketNotifier < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class SqlCursor < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+
+ def name(*args)
+ method_missing(:name, *args)
+ end
+
+ def select(*args)
+ method_missing(:select, *args)
+ end
+ end
+
+ class SqlDatabase < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+ def open(*args)
+ method_missing(:open, *args)
+ end
+ end
+
+ class SqlDriver < Qt::Base
+ def open(*args)
+ method_missing(:open, *args)
+ end
+ end
+
+ class SqlError < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class SqlField < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class SqlFieldInfo < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class SqlIndex < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class SqlQuery < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+ end
+
+ class SqlSelectCursor < Qt::Base
+ def exec(*args)
+ method_missing(:exec, *args)
+ end
+
+ def name(*args)
+ method_missing(:name, *args)
+ end
+
+ def select(*args)
+ method_missing(:select, *args)
+ end
+ end
+
+ class StoredDrag < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class StyleSheetItem < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class TextDrag < Qt::Base
+ def format(*args)
+ method_missing(:format, *args)
+ end
+ end
+
+ class TabletEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Time < Qt::Base
+ def inspect
+ str = super
+ str.sub(/>$/, " %s>" % toString)
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, " %s>" % toString)
+ end
+ end
+
+ class TimeEdit < Qt::Base
+ def display
+ method_missing(:display)
+ end
+ end
+
+ class TimerEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Translator < Qt::Base
+ def load(*args)
+ method_missing(:load, *args)
+ end
+ end
+
+ class TranslatorMessage < Qt::Base
+ def hash(*args)
+ method_missing(:hash, *args)
+ end
+ end
+
+ class TsciiCodec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class UrlInfo < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Utf16Codec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Utf8Codec < Qt::Base
+ def name(*args)
+ method_missing(:name, *args)
+ end
+ end
+
+ class Variant < Qt::Base
+ String = 3
+ Date = 26
+ Time = 27
+ DateTime = 28
+
+ def initialize(*args)
+ # In C++, the boolean constructor needs an ugly dummy int argument,
+ # so special case that here to avoid needing it in Ruby
+ if args[0] == true || args[0] == false
+ super(args[0], 0)
+ else
+ super
+ end
+ end
+
+ def to_a
+ return toStringList()
+ end
+
+ def to_f
+ return toDouble()
+ end
+
+ def to_i
+ return toInt()
+ end
+
+ def to_int
+ return toInt()
+ end
+
+ def to_ruby
+ case type()
+ when Qt::Variant::Bitmap
+ return toBitmap
+ when Qt::Variant::Bool
+ return toBool
+ when Qt::Variant::Brush
+ return toBrush
+ when Qt::Variant::ByteArray
+ return toByteArray
+ when Qt::Variant::Color
+ return toColor
+ when Qt::Variant::ColorGroup
+ return toColorGroup
+ when Qt::Variant::CString
+ return toCString
+ when Qt::Variant::Cursor
+ return toCursor
+ when Qt::Variant::Date
+ return toDate
+ when Qt::Variant::DateTime
+ return toDateTime
+ when Qt::Variant::Double
+ return toDouble
+ when Qt::Variant::Font
+ return toFont
+ when Qt::Variant::IconSet
+ return toIconSet
+ when Qt::Variant::Image
+ return toImage
+ when Qt::Variant::Int
+ return toInt
+ when Qt::Variant::KeySequence
+ return toKeySequence
+ when Qt::Variant::List
+ return toList
+ when Qt::Variant::LongLong
+ return toLongLong
+ when Qt::Variant::Map
+ return toMap
+ when Qt::Variant::Palette
+ return toPalette
+ when Qt::Variant::Pen
+ return toPen
+ when Qt::Variant::Pixmap
+ return toPixmap
+ when Qt::Variant::Point
+ return toPoint
+ when Qt::Variant::PointArray
+ return toPointArray
+ when Qt::Variant::Rect
+ return toRect
+ when Qt::Variant::Region
+ return toRegion
+ when Qt::Variant::Size
+ return toSize
+ when Qt::Variant::SizePolicy
+ return toSizePolicy
+ when Qt::Variant::String
+ return toString
+ when Qt::Variant::StringList
+ return toStringList
+ when Qt::Variant::Time
+ return toTime
+ when Qt::Variant::UInt
+ return toUint
+ when Qt::Variant::ULongLong
+ return toULongLong
+ end
+ end
+
+ def inspect
+ str = super
+ str.sub(/>$/, " typeName=%s>" % typeName)
+ end
+
+ def pretty_print(pp)
+ str = to_s
+ pp.text str.sub(/>$/, " typeName=%s>" % typeName)
+ end
+
+ def load(*args)
+ method_missing(:load, *args)
+ end
+
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class VBoxLayout < Qt::Base
+ include Enumerable
+
+ def each
+ it = iterator()
+ while it.current
+ yield it.current
+ it += 1
+ end
+ end
+ end
+
+ class WhatsThis < Qt::Base
+ def WhatsThis.display(*k)
+ method_missing(:display, *k)
+ end
+ end
+
+ class WheelEvent < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ class Widget < Qt::Base
+ def raise(*args)
+ method_missing(:raise, *args)
+ end
+ end
+
+ class WidgetStack < Qt::Base
+ def id(*args)
+ method_missing(:id, *args)
+ end
+ end
+
+ class XmlAttributes < Qt::Base
+ def type(*args)
+ method_missing(:type, *args)
+ end
+ end
+
+ # Provides a mutable numeric class for passing to methods with
+ # C++ 'int*' or 'int&' arg types
+ class Integer
+ attr_accessor :value
+ def initialize(n=0) @value = n end
+
+ def +(n)
+ return Integer.new(@value + n.to_i)
+ end
+ def -(n)
+ return Integer.new(@value - n.to_i)
+ end
+ def *(n)
+ return Integer.new(@value * n.to_i)
+ end
+ def /(n)
+ return Integer.new(@value / n.to_i)
+ end
+ def %(n)
+ return Integer.new(@value % n.to_i)
+ end
+ def **(n)
+ return Integer.new(@value ** n.to_i)
+ end
+
+ def |(n)
+ return Integer.new(@value | n.to_i)
+ end
+ def &(n)
+ return Integer.new(@value & n.to_i)
+ end
+ def ^(n)
+ return Integer.new(@value ^ n.to_i)
+ end
+ def <<(n)
+ return Integer.new(@value << n.to_i)
+ end
+ def >>(n)
+ return Integer.new(@value >> n.to_i)
+ end
+
+ def >(n)
+ return @value > n.to_i
+ end
+ def >=(n)
+ return @value >= n.to_i
+ end
+ def <(n)
+ return @value < n.to_i
+ end
+ def <=(n)
+ return @value <= n.to_i
+ end
+
+ def <=>(n)
+ if @value < n
+ return -1
+ elsif @value > n
+ return 1
+ else
+ return 0
+ end
+ end
+
+ def to_f() return @value.to_f end
+ def to_i() return @value.to_i end
+ def to_s() return @value.to_s end
+
+ def coerce(n)
+ [n, @value]
+ end
+ end
+
+ # If a C++ enum was converted to an ordinary ruby Integer, the
+ # name of the type is lost. The enum type name is needed for overloaded
+ # method resolution when two methods differ only by an enum type.
+ class Enum < Qt::Integer
+ attr_accessor :type
+ def initialize(n, type)
+ super(n)
+ @value = n
+ @type = type
+ end
+
+ def |(n)
+ return Enum.new(@value | n.to_i, @type)
+ end
+ def &(n)
+ return Enum.new(@value & n.to_i, @type)
+ end
+ def ^(n)
+ return Enum.new(@value ^ n.to_i, @type)
+ end
+ def <(n)
+ return @value < n.to_i
+ end
+ def <=(n)
+ return @value <= n.to_i
+ end
+ def >(n)
+ return @value > n.to_i
+ end
+ def >=(n)
+ return @value >= n.to_i
+ end
+ def <<(n)
+ return Enum.new(@value << n.to_i, @type)
+ end
+ def >>(n)
+ return Enum.new(@value >> n.to_i, @type)
+ end
+
+ def ==(n) return @value == n.to_i end
+ def to_i() return @value end
+
+ def inspect
+ to_s
+ end
+
+ def pretty_print(pp)
+ pp.text "#<%s:0x%8.8x @type=%s, @value=%d>" % [self.class.name, object_id, type, value]
+ end
+ end
+
+ # Provides a mutable boolean class for passing to methods with
+ # C++ 'bool*' or 'bool&' arg types
+ class Boolean
+ attr_accessor :value
+ def initialize(b=false) @value = b end
+ def nil?
+ return !@value
+ end
+ end
+
+ class SignalBlockInvocation < Qt::Object
+ def initialize(parent, block, args)
+ super(parent)
+ self.class.slots "invoke(#{args})"
+ @block = block
+ end
+
+ def invoke(*args)
+ @block.call(*args)
+ end
+ end
+
+ class BlockInvocation < Qt::Object
+ def initialize(target, block, args)
+ super(target)
+ self.class.slots "invoke(#{args})"
+ @target = target
+ @block = block
+ end
+
+ def invoke(*args)
+ @target.instance_exec(*args, &@block)
+ end
+ end
+
+ module Internal
+ @@classes = {}
+ @@cpp_names = {}
+ @@idclass = []
+
+ def Internal.normalize_classname(classname)
+ if classname =~ /^Qext/
+ now = classname.sub(/^Qext(?=[A-Z])/,'Qext::')
+ elsif classname =~ /^Q/
+ now = classname.sub(/^Q(?=[A-Z])/,'Qt::')
+ elsif classname =~ /^(KConfigSkeleton|KWin)::/
+ now = classname.sub(/^K?(?=[A-Z])/,'KDE::')
+ elsif classname !~ /::/
+ now = classname.sub(/^K?(?=[A-Z])/,'KDE::')
+ else
+ now = classname
+ end
+ # puts "normalize_classname = was::#{classname}, now::#{now}"
+ now
+ end
+
+ def Internal.init_class(c)
+ classname = Qt::Internal::normalize_classname(c)
+ classId = Qt::Internal.idClass(c)
+ insert_pclassid(classname, classId)
+ @@idclass[classId] = classname
+ @@cpp_names[classname] = c
+ klass = isQObject(classId) ? create_qobject_class(classname) \
+ : create_qt_class(classname)
+ @@classes[classname] = klass unless klass.nil?
+ end
+
+ def Internal.debug_level
+ Qt.debug_level
+ end
+
+ def Internal.checkarg(argtype, typename)
+ puts " #{typename} (#{argtype})" if debug_level >= DebugLevel::High
+ if argtype == 'i'
+ if typename =~ /^int&?$|^signed int&?$|^signed$|^Q_INT32&?$/
+ return 1
+ elsif typename =~ /^(?:short|ushort|unsigned short int|uchar|uint|long|ulong|unsigned long int|unsigned|float|double|Q_UINT32|Q_UINT16|Q_INT16)$/
+ return 0
+ else
+ t = typename.sub(/^const\s+/, '')
+ t.sub!(/[&*]$/, '')
+ if isEnum(t)
+ return 0
+ end
+ end
+ elsif argtype == 'n'
+ if typename =~ /^double$/
+ return 2
+ elsif typename =~ /^float$/
+ return 1
+ elsif typename =~ /^int&?$/
+ return 0
+ elsif typename =~ /^(?:short|ushort|uint|long|ulong|signed|unsigned|float|double)$/
+ return 0
+ else
+ t = typename.sub(/^const\s+/, '')
+ t.sub!(/[&*]$/, '')
+ if isEnum(t)
+ return 0
+ end
+ end
+ elsif argtype == 'B'
+ if typename =~ /^(?:bool)[*&]?$/
+ return 0
+ end
+ elsif argtype == 's'
+ if typename =~ /^(const )?((QChar)[*&]?)$/
+ return 1
+ elsif typename =~ /^(?:u?char\*|const u?char\*|(?:const )?(Q(C?)String)[*&]?)$/
+ qstring = !$1.nil?
+ c = ("C" == $2)
+ return c ? 2 : (qstring ? 3 : 0)
+ end
+ elsif argtype == 'a'
+ # FIXME: shouldn't be hardcoded. Installed handlers should tell what ruby type they expect.
+ if typename =~ /^(?:
+ const\ QCOORD\*|
+ (?:const\ )?
+ (?:
+ QStringList[\*&]?|
+ QValueList<int>[\*&]?|
+ QRgb\*|
+ char\*\*
+ )
+ )$/x
+ return 0
+ end
+ elsif argtype == 'u'
+ # Give nil matched against string types a higher score than anything else
+ if typename =~ /^(?:u?char\*|const u?char\*|(?:const )?((Q(C?)String))[*&]?)$/
+ return 1
+ # Numerics will give a runtime conversion error, so they fail the match
+ elsif typename =~ /^(?:short|ushort|uint|long|ulong|signed|unsigned|int)$/
+ return -99
+ else
+ return 0
+ end
+ elsif argtype == 'U'
+ if typename =~ /QStringList/
+ return 1
+ else
+ return 0
+ end
+ else
+ t = typename.sub(/^const\s+/, '')
+ t.sub!(/[&*]$/, '')
+ if argtype == t
+ return 1
+ elsif classIsa(argtype, t)
+ return 0
+ elsif isEnum(argtype) and
+ (t =~ /int|Q_INT32|uint|Q_UINT32|long|ulong/ or isEnum(t))
+ return 0
+ end
+ end
+ return -99
+ end
+
+ def Internal.find_class(classname)
+ # puts @@classes.keys.sort.join "\n"
+ @@classes[classname]
+ end
+
+ # Runs the initializer as far as allocating the Qt C++ instance.
+ # Then use a throw to jump back to here with the C++ instance
+ # wrapped in a new ruby variable of type T_DATA
+ def Internal.try_initialize(instance, *args)
+ initializer = instance.method(:initialize)
+ catch "newqt" do
+ initializer.call(*args)
+ end
+ end
+
+ # If a block was passed to the constructor, then
+ # run that now. Either run the context of the new instance
+ # if no args were passed to the block. Or otherwise,
+ # run the block in the context of the arg.
+ def Internal.run_initializer_block(instance, block)
+ if block.arity == -1
+ instance.instance_eval(&block)
+ elsif block.arity == 1
+ block.call(instance)
+ else
+ raise ArgumentError, "Wrong number of arguments to block(#{block.arity} for 1)"
+ end
+ end
+
+ def Internal.do_method_missing(package, method, klass, this, *args)
+ if klass.class == Module
+ classname = klass.name
+ else
+ classname = @@cpp_names[klass.name]
+ if classname.nil?
+ if klass != Object and klass != Qt
+ return do_method_missing(package, method, klass.superclass, this, *args)
+ else
+ return nil
+ end
+ end
+ end
+
+ if method == "new"
+ method = classname.dup
+ method.gsub!(/^(KParts|KIO|KNS|DOM|Kontact|Kate|KTextEditor|KConfigSkeleton::ItemEnum|KConfigSkeleton|KWin)::/,"")
+ end
+ method = "operator" + method.sub("@","") if method !~ /[a-zA-Z]+/
+ # Change foobar= to setFoobar()
+ method = 'set' + method[0,1].upcase + method[1,method.length].sub("=", "") if method =~ /.*[^-+%\/|=]=$/
+
+ methods = []
+ methods << method.dup
+ args.each do |arg|
+ if arg.nil?
+ # For each nil arg encountered, triple the number of munged method
+ # templates, in order to cover all possible types that can match nil
+ temp = []
+ methods.collect! do |meth|
+ temp << meth + '?'
+ temp << meth + '#'
+ meth << '$'
+ end
+ methods.concat(temp)
+ elsif isObject(arg)
+ methods.collect! { |meth| meth << '#' }
+ elsif arg.kind_of? Array or arg.kind_of? Hash
+ methods.collect! { |meth| meth << '?' }
+ else
+ methods.collect! { |meth| meth << '$' }
+ end
+ end
+
+ methodIds = []
+ methods.collect { |meth| methodIds.concat( findMethod(classname, meth) ) }
+
+ if method =~ /_/ && methodIds.length == 0
+ # If the method name contains underscores, convert to camel case
+ # form and try again
+ method.gsub!(/(.)_(.)/) {$1 + $2.upcase}
+ return do_method_missing(package, method, klass, this, *args)
+ end
+
+ if debug_level >= DebugLevel::High
+ puts "classname == #{classname}"
+ puts ":: method == #{method}"
+ puts "-> methodIds == #{methodIds.inspect}"
+ puts "candidate list:"
+ prototypes = dumpCandidates(methodIds).split("\n")
+ line_len = (prototypes.collect { |p| p.length }).max
+ prototypes.zip(methodIds) {
+ |prototype,id| puts "#{prototype.ljust line_len} (#{id})"
+ }
+ end
+
+ chosen = nil
+ if methodIds.length > 0
+ best_match = -1
+ methodIds.each do
+ |id|
+ puts "matching => #{id}" if debug_level >= DebugLevel::High
+ current_match = 0
+ (0...args.length).each do
+ |i|
+ current_match += checkarg( getVALUEtype(args[i]), getTypeNameOfArg(id, i) )
+ end
+
+ # Note that if current_match > best_match, then chosen must be nil
+ if current_match > best_match
+ best_match = current_match
+ chosen = id
+ # Multiple matches are an error; the equality test below _cannot_ be commented out.
+ # If ambiguous matches occur the problem must be fixed be adjusting the relative
+ # ranking of the arg types involved in checkarg().
+ elsif current_match == best_match
+ chosen = nil
+ end
+ puts "match => #{id} score: #{current_match}" if debug_level >= DebugLevel::High
+ end
+
+ puts "Resolved to id: #{chosen}" if !chosen.nil? && debug_level >= DebugLevel::High
+ end
+
+ if debug_level >= DebugLevel::Minimal && chosen.nil? && method !~ /^operator/
+ id = find_pclassid(normalize_classname(klass.name))
+ hash = findAllMethods(id)
+ constructor_names = nil
+ if method == classname
+ puts "No matching constructor found, possibles:\n"
+ constructor_names = hash.keys.grep(/^#{classname}/)
+ else
+ puts "Possible prototypes:"
+ constructor_names = hash.keys
+ end
+ method_ids = hash.values_at(*constructor_names).flatten
+ puts dumpCandidates(method_ids)
+ end
+
+ puts "setCurrentMethod(#{chosen})" if debug_level >= DebugLevel::High
+ setCurrentMethod(chosen) if chosen
+ return nil
+ end
+
+ def Internal.init_all_classes()
+ Qt::Internal::getClassList().each do |c|
+ if c == "Qt"
+ # Don't change Qt to Qt::t, just leave as is
+ @@cpp_names["Qt"] = c
+ elsif c != "QInternal"
+ Qt::Internal::init_class(c)
+ end
+ end
+
+ @@classes['Qt::Integer'] = Qt::Integer
+ @@classes['Qt::Boolean'] = Qt::Boolean
+ @@classes['Qt::Enum'] = Qt::Enum
+ end
+
+ def Internal.get_qinteger(num)
+ return num.value
+ end
+
+ def Internal.set_qinteger(num, val)
+ return num.value = val
+ end
+
+ def Internal.create_qenum(num, type)
+ return Qt::Enum.new(num, type)
+ end
+
+ def Internal.get_qenum_type(e)
+ return e.type
+ end
+
+ def Internal.get_qboolean(b)
+ return b.value
+ end
+
+ def Internal.set_qboolean(b, val)
+ return b.value = val
+ end
+
+ def Internal.getAllParents(class_id, res)
+ getIsa(class_id).each do |s|
+ c = idClass(s)
+ res << c
+ getAllParents(c, res)
+ end
+ end
+
+ def Internal.getSignalNames(klass)
+ meta = Meta[klass.name] || MetaInfo.new(klass)
+ signal_names = []
+ meta.get_signals.each do |signal|
+ signal_names.push signal.name
+ end
+ return signal_names
+ end
+
+ def Internal.signalInfo(qobject, signal_name)
+ signals = Meta[qobject.class.name].get_signals
+ signals.each_with_index do |signal, i|
+ if signal.name == signal_name
+ return [signal.full_name, i]
+ end
+ end
+ end
+
+ def Internal.signalAt(qobject, index)
+ klass = qobject.class
+ begin
+ meta = Meta[klass.name]
+ klass = klass.superclass
+ end while meta.nil? and klass != Object
+ meta.get_signals[index].full_name
+ end
+
+ def Internal.slotAt(qobject, index)
+ klass = qobject.class
+ begin
+ meta = Meta[klass.name]
+ klass = klass.superclass
+ end while meta.nil? and klass != Object
+ meta.get_slots[index].full_name
+ end
+
+ def Internal.getMocArguments(member)
+ argStr = member.sub(/.*\(/, '').sub(/\)$/, '')
+ args = argStr.scan(/([^,]*<[^>]+>)|([^,]+)/)
+ mocargs = allocateMocArguments(args.length)
+ args.each_with_index do |arg, i|
+ arg = arg.to_s
+ a = arg.sub(/^const\s+/, '')
+ a = (a =~ /^(bool|int|double|char\*|QString)&?$/) ? $1 : 'ptr'
+ valid = setMocType(mocargs, i, arg, a)
+ end
+ result = []
+ result << args.length << mocargs
+ result
+ end
+
+ def Internal.makeMetaData(data)
+ return nil if data.nil?
+ tbl = []
+ data.each do |entry|
+ name = entry.name
+ argStr = entry.arg_types
+ params = []
+ args = argStr.scan(/[^,]+/)
+ args.each do |arg|
+ name = '' # umm.. is this the aim?, well. it works. soo... ;-)
+ param = make_QUParameter(name, arg, 0, 1)
+ params << param
+ end
+ method = make_QUMethod(name, params)
+ tbl << make_QMetaData(entry.full_name, method)
+ end
+ make_QMetaData_tbl(tbl)
+ end
+
+ def Internal.getMetaObject(qobject)
+ klass = qobject.class
+ begin
+ meta = Meta[klass.name]
+ klass = klass.superclass
+ end while meta.nil? and klass != Object
+
+ return nil if meta.nil?
+
+ if meta.metaobject.nil? or meta.changed
+ slots = meta.get_slots
+ slotTable = makeMetaData(slots)
+ signals = meta.get_signals
+ signalTable = makeMetaData(signals)
+ meta.metaobject = make_metaObject(qobject.class.name,
+ qobject.staticMetaObject(),
+ slotTable,
+ slots.length,
+ signalTable,
+ signals.length)
+ addSignalMethods(qobject.class, getSignalNames(qobject.class))
+ meta.changed = false
+ end
+
+ meta.metaobject
+ end
+
+ def Internal.connect(src, signal, target, block)
+ signature = (signal =~ /\((.*)\)/) ? $1 : ""
+ return Qt::Object.connect( src,
+ signal,
+ Qt::BlockInvocation.new(target, block, signature),
+ SLOT("invoke(#{signature})") )
+ end
+
+ def Internal.signal_connect(src, signal, block)
+ signature = (signal =~ /\((.*)\)/) ? $1 : ""
+ return Qt::Object.connect( src,
+ signal,
+ Qt::SignalBlockInvocation.new(src, block, signature),
+ SLOT("invoke(#{signature})") )
+ end
+ end # Qt::Internal
+
+ Meta = {}
+
+ # An entry for each signal or slot
+ # Example
+ # foobar(QString,bool)
+ # :name is 'foobar'
+ # :full_name is 'foobar(QString,bool)'
+ # :arg_types is 'QString,bool'
+ QObjectMember = Struct.new :name, :full_name, :arg_types
+
+ class MetaInfo
+ attr_accessor :signals, :slots, :metaobject, :mocargs, :changed
+ def initialize(klass)
+ Meta[klass.name] = self
+ @klass = klass
+ @metaobject = nil
+ @signals = []
+ @slots = []
+ @changed = false
+ Internal.addMetaObjectMethods(klass)
+ end
+
+ def add_signals(signal_list)
+ signal_list.each do |signal|
+ if signal.kind_of? Symbol
+ signal = signal.to_s + "()"
+ end
+ signal = Qt::Object.normalizeSignalSlot(signal)
+ if signal =~ /([^\s]*)\((.*)\)/
+ @signals.push QObjectMember.new($1, signal, $2)
+ else
+ qWarning( "#{@klass.name}: Invalid signal format: '#{signal}'" )
+ end
+ end
+ end
+
+ # Return a list of signals, including inherited ones
+ def get_signals
+ all_signals = []
+ current = @klass
+ while current != Qt::Base
+ meta = Meta[current.name]
+ if !meta.nil?
+ all_signals.concat meta.signals
+ end
+ current = current.superclass
+ end
+ return all_signals
+ end
+
+ def add_slots(slot_list)
+ slot_list.each do |slot|
+ if slot.kind_of? Symbol
+ slot = slot.to_s + "()"
+ end
+ slot = Qt::Object.normalizeSignalSlot(slot)
+ if slot =~ /([^\s]*)\((.*)\)/
+ @slots.push QObjectMember.new($1, slot, $2)
+ else
+ qWarning( "#{@klass.name}: Invalid slot format: '#{slot}'" )
+ end
+ end
+ end
+
+ # Return a list of slots, including inherited ones
+ def get_slots
+ all_slots = []
+ current = @klass
+ while current != Qt::Base
+ meta = Meta[current.name]
+ if !meta.nil?
+ all_slots.concat meta.slots
+ end
+ current = current.superclass
+ end
+ return all_slots
+ end
+ end # Qt::MetaInfo
+
+ IO_Direct = 0x0100
+ IO_Sequential = 0x0200
+ IO_Combined = 0x0300
+ IO_TypeMask = 0x0f00
+ IO_Raw = 0x0040
+ IO_Async = 0x0080
+ IO_ReadOnly = 0x0001
+ IO_WriteOnly = 0x0002
+ IO_ReadWrite = 0x0003
+ IO_Append = 0x0004
+ IO_Truncate = 0x0008
+ IO_Translate = 0x0010
+ IO_ModeMask = 0x00ff
+ IO_Open = 0x1000
+ IO_StateMask = 0xf000
+ IO_Ok = 0
+ IO_ReadError = 1
+ IO_WriteError = 2
+ IO_FatalError = 3
+ IO_ResourceError = 4
+ IO_OpenError = 5
+ IO_ConnectError = 5
+ IO_AbortError = 6
+ IO_TimeOutError = 7
+ IO_UnspecifiedError= 8
+
+end # Qt
+
+class Object
+ def SIGNAL(signal)
+ if signal.kind_of? Symbol
+ return "2" + signal.to_s + "()"
+ else
+ return "2" + signal
+ end
+ end
+
+ def SLOT(slot)
+ if slot.kind_of? Symbol
+ return "1" + slot.to_s + "()"
+ else
+ return "1" + slot
+ end
+ end
+
+ def emit(signal)
+ return signal
+ end
+
+ # See the discussion here: http://eigenclass.org/hiki.rb?instance_exec
+ # about implementations of the ruby 1.9 method instance_exec(). This
+ # version is the one from Rails. It isn't thread safe, but that doesn't
+ # matter for the intended use in invoking blocks as Qt slots.
+ def instance_exec(*arguments, &block)
+ block.bind(self)[*arguments]
+ end
+end
+
+class Proc
+ # Part of the Rails Object#instance_exec implementation
+ def bind(object)
+ block, time = self, Time.now
+ (class << object; self end).class_eval do
+ method_name = "__bind_#{time.to_i}_#{time.usec}"
+ define_method(method_name, &block)
+ method = instance_method(method_name)
+ remove_method(method_name)
+ method
+ end.bind(object)
+ end
+end
+
+class Module
+ alias_method :_constants, :constants
+ alias_method :_instance_methods, :instance_methods
+ alias_method :_protected_instance_methods, :protected_instance_methods
+ alias_method :_public_instance_methods, :public_instance_methods
+
+ private :_constants, :_instance_methods
+ private :_protected_instance_methods, :_public_instance_methods
+
+ def constants
+ qt_methods(_constants, 0x10, true)
+ end
+
+ def instance_methods(inc_super=true)
+ qt_methods(_instance_methods(inc_super), 0x0, inc_super)
+ end
+
+ def protected_instance_methods(inc_super=true)
+ qt_methods(_protected_instance_methods(inc_super), 0x80, inc_super)
+ end
+
+ def public_instance_methods(inc_super=true)
+ qt_methods(_public_instance_methods(inc_super), 0x0, inc_super)
+ end
+
+ private
+ def qt_methods(meths, flags, inc_super=true)
+ if !self.kind_of? Class
+ return meths
+ end
+
+ klass = self
+ classid = 0
+ loop do
+ classid = Qt::Internal::find_pclassid(klass.name)
+ break if classid > 0
+
+ klass = klass.superclass
+ if klass.nil?
+ return meths
+ end
+ end
+
+ # These methods are all defined in Qt::Base, even if they aren't supported by a particular
+ # subclass, so remove them to avoid confusion
+ meths -= ["%", "&", "*", "**", "+", "-", "-@", "/", "<", "<<", "<=", ">", ">=", ">>", "|", "~", "^"]
+ ids = []
+ if inc_super
+ Qt::Internal::getAllParents(classid, ids)
+ end
+ ids << classid
+ ids.each { |c| Qt::Internal::findAllMethodNames(meths, c, flags) }
+ return meths.uniq
+ end
+end
diff --git a/qtruby/rubylib/qtruby/marshall.h b/qtruby/rubylib/qtruby/marshall.h
new file mode 100644
index 00000000..cf20b86d
--- /dev/null
+++ b/qtruby/rubylib/qtruby/marshall.h
@@ -0,0 +1,46 @@
+#ifndef MARSHALL_H
+#define MARSHALL_H
+
+#include <smoke.h>
+#include <ruby.h>
+
+class SmokeType;
+
+class Marshall {
+public:
+ /**
+ * FromVALUE is used for virtual function return values and regular
+ * method arguments.
+ *
+ * ToVALUE is used for method return-values and virtual function
+ * arguments.
+ */
+ typedef void (*HandlerFn)(Marshall *);
+ enum Action { FromVALUE, ToVALUE };
+ virtual SmokeType type() = 0;
+ virtual Action action() = 0;
+ virtual Smoke::StackItem &item() = 0;
+ virtual VALUE * var() = 0;
+ virtual void unsupported() = 0;
+ virtual Smoke *smoke() = 0;
+ /**
+ * For return-values, next() does nothing.
+ * For FromRV, next() calls the method and returns.
+ * For ToRV, next() calls the virtual function and returns.
+ *
+ * Required to reset Marshall object to the state it was
+ * before being called when it returns.
+ */
+ virtual void next() = 0;
+ /**
+ * For FromSV, cleanup() returns false when the handler should free
+ * any allocated memory after next().
+ *
+ * For ToSV, cleanup() returns true when the handler should delete
+ * the pointer passed to it.
+ */
+ virtual bool cleanup() = 0;
+
+ virtual ~Marshall() {}
+};
+#endif
diff --git a/qtruby/rubylib/qtruby/qtruby.h b/qtruby/rubylib/qtruby/qtruby.h
new file mode 100644
index 00000000..66f9fedc
--- /dev/null
+++ b/qtruby/rubylib/qtruby/qtruby.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ qtruby.h - description
+ -------------------
+ begin : Fri Jul 4 2003
+ copyright : (C) 2003 by Richard Dale
+ email : Richard_Dale@tipitina.demon.co.uk
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef QTRUBY_H
+#define QTRUBY_H
+
+#include "marshall.h"
+
+struct smokeruby_object {
+ bool allocated;
+ Smoke *smoke;
+ int classId;
+ void *ptr;
+};
+
+struct TypeHandler {
+ const char *name;
+ Marshall::HandlerFn fn;
+};
+
+extern int do_debug; // evil
+extern VALUE rv_qapp;
+extern int object_count;
+
+// keep this enum in sync with lib/Qt/debug.pm
+
+enum QtDebugChannel {
+ qtdb_none = 0x00,
+ qtdb_ambiguous = 0x01,
+ qtdb_method_missing = 0x02,
+ qtdb_calls = 0x04,
+ qtdb_gc = 0x08,
+ qtdb_virtual = 0x10,
+ qtdb_verbose = 0x20
+};
+
+void unmapPointer(smokeruby_object *, Smoke::Index, void*);
+smokeruby_object *value_obj_info(VALUE value);
+VALUE getPointerObject(void *ptr);
+
+#endif
diff --git a/qtruby/rubylib/qtruby/smokeruby.h b/qtruby/rubylib/qtruby/smokeruby.h
new file mode 100644
index 00000000..8f152c10
--- /dev/null
+++ b/qtruby/rubylib/qtruby/smokeruby.h
@@ -0,0 +1,321 @@
+#ifndef SMOKERUBY_H
+#define SMOKERUBY_H
+
+#include "smoke.h"
+
+#undef DEBUG
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#ifndef __USE_POSIX
+#define __USE_POSIX
+#endif
+#ifndef __USE_XOPEN
+#define __USE_XOPEN
+#endif
+#include "ruby.h"
+
+#include <qcstring.h>
+
+#include "qtruby.h"
+#include "marshall.h"
+
+
+class SmokeRuby;
+
+class SmokeType {
+ Smoke::Type *_t; // derived from _smoke and _id, but cached
+
+ Smoke *_smoke;
+ Smoke::Index _id;
+public:
+ SmokeType() : _t(0), _smoke(0), _id(0) {}
+ SmokeType(Smoke *s, Smoke::Index i) : _smoke(s), _id(i) {
+ if(_id < 0 || _id > _smoke->numTypes) _id = 0;
+ _t = _smoke->types + _id;
+ }
+ // default copy constructors are fine, this is a constant structure
+
+ // mutators
+ void set(Smoke *s, Smoke::Index i) {
+ _smoke = s;
+ _id = i;
+ _t = _smoke->types + _id;
+ }
+
+ // accessors
+ Smoke *smoke() const { return _smoke; }
+ Smoke::Index typeId() const { return _id; }
+ const Smoke::Type &type() const { return *_t; }
+ unsigned short flags() const { return _t->flags; }
+ unsigned short elem() const { return _t->flags & Smoke::tf_elem; }
+ const char *name() const { return _t->name; }
+ Smoke::Index classId() const { return _t->classId; }
+
+ // tests
+ bool isStack() const { return ((flags() & Smoke::tf_ref) == Smoke::tf_stack); }
+ bool isPtr() const { return ((flags() & Smoke::tf_ref) == Smoke::tf_ptr); }
+ bool isRef() const { return ((flags() & Smoke::tf_ref) == Smoke::tf_ref); }
+ bool isConst() const { return (flags() & Smoke::tf_const); }
+ bool isClass() const {
+ if(elem() == Smoke::t_class)
+ return classId() ? true : false;
+ return false;
+ }
+
+ bool operator ==(const SmokeType &b) const {
+ const SmokeType &a = *this;
+ if(a.name() == b.name()) return true;
+ if(a.name() && b.name() && qstrcmp(a.name(), b.name()) == 0)
+ return true;
+ return false;
+ }
+ bool operator !=(const SmokeType &b) const {
+ const SmokeType &a = *this;
+ return !(a == b);
+ }
+
+};
+
+class SmokeClass {
+ Smoke::Class *_c;
+ Smoke *_smoke;
+ Smoke::Index _id;
+public:
+ SmokeClass(const SmokeType &t) {
+ _smoke = t.smoke();
+ _id = t.classId();
+ _c = _smoke->classes + _id;
+ }
+ SmokeClass(Smoke *smoke, Smoke::Index id) : _smoke(smoke), _id(id) {
+ _c = _smoke->classes + _id;
+ }
+
+ Smoke *smoke() const { return _smoke; }
+ const Smoke::Class &c() const { return *_c; }
+ Smoke::Index classId() const { return _id; }
+ const char *className() const { return _c->className; }
+ Smoke::ClassFn classFn() const { return _c->classFn; }
+ Smoke::EnumFn enumFn() const { return _c->enumFn; }
+ bool operator ==(const SmokeClass &b) const {
+ const SmokeClass &a = *this;
+ if(a.className() == b.className()) return true;
+ if(a.className() && b.className() && qstrcmp(a.className(), b.className()) == 0)
+ return true;
+ return false;
+ }
+ bool operator !=(const SmokeClass &b) const {
+ const SmokeClass &a = *this;
+ return !(a == b);
+ }
+ bool isa(const SmokeClass &sc) const {
+ // This is a sick function, if I do say so myself
+ if(*this == sc) return true;
+ Smoke::Index *parents = _smoke->inheritanceList + _c->parents;
+ for(int i = 0; parents[i]; i++) {
+ if(SmokeClass(_smoke, parents[i]).isa(sc)) return true;
+ }
+ return false;
+ }
+
+ unsigned short flags() const { return _c->flags; }
+ bool hasConstructor() const { return flags() & Smoke::cf_constructor; }
+ bool hasCopy() const { return flags() & Smoke::cf_deepcopy; }
+ bool hasVirtual() const { return flags() & Smoke::cf_virtual; }
+ bool hasFire() const { return !(flags() & Smoke::cf_undefined); }
+};
+
+class SmokeMethod {
+ Smoke::Method *_m;
+ Smoke *_smoke;
+ Smoke::Index _id;
+public:
+ SmokeMethod(Smoke *smoke, Smoke::Index id) : _smoke(smoke), _id(id) {
+ _m = _smoke->methods + _id;
+ }
+
+ Smoke *smoke() const { return _smoke; }
+ const Smoke::Method &m() const { return *_m; }
+ SmokeClass c() const { return SmokeClass(_smoke, _m->classId); }
+ const char *name() const { return _smoke->methodNames[_m->name]; }
+ int numArgs() const { return _m->numArgs; }
+ unsigned short flags() const { return _m->flags; }
+ SmokeType arg(int i) const {
+ if(i >= numArgs()) return SmokeType();
+ return SmokeType(_smoke, _smoke->argumentList[_m->args + i]);
+ }
+ SmokeType ret() const { return SmokeType(_smoke, _m->ret); }
+ Smoke::Index methodId() const { return _id; }
+ Smoke::Index method() const { return _m->method; }
+
+ bool isStatic() const { return flags() & Smoke::mf_static; }
+ bool isConst() const { return flags() & Smoke::mf_const; }
+
+ void call(Smoke::Stack args, void *ptr = 0) const {
+ Smoke::ClassFn fn = c().classFn();
+ (*fn)(method(), ptr, args);
+ }
+};
+
+class Smoke_MAGIC { // to be rewritten
+ SmokeClass _c;
+ void *_ptr;
+ bool _isAllocated;
+public:
+ Smoke_MAGIC(void *p, const SmokeClass &c) :
+ _c(c), _ptr(p), _isAllocated(false) {}
+ const SmokeClass &c() const { return _c; }
+ void *ptr() const { return _ptr; }
+ bool isAllocated() const { return _isAllocated; }
+ void setAllocated(bool isAllocated) { _isAllocated = isAllocated; }
+};
+
+
+/**
+ * SmokeObject is a thin wrapper around VALUE objects. Each SmokeObject instance
+ * increments the refcount of its VALUE for the duration of its existance.
+ *
+ * SmokeObject instances are only returned from SmokeRuby, since the method
+ * of binding data to the scalar must be consistent across all modules.
+ */
+class SmokeObject {
+ VALUE rv;
+ Smoke_MAGIC *m;
+
+public:
+ SmokeObject(VALUE obj, Smoke_MAGIC *mag) : rv(obj), m(mag) {
+ rb_gc_register_address(&rv);
+ }
+
+ ~SmokeObject() {
+ rb_gc_unregister_address(&rv);
+ }
+
+ SmokeObject(const SmokeObject &other) {
+ rv = other.rv;
+ m = other.m;
+ rb_gc_register_address(&rv);
+ }
+
+ SmokeObject &operator =(const SmokeObject &other) {
+ rv = other.rv;
+ m = other.m;
+ rb_gc_register_address(&rv);
+ return *this;
+ }
+
+ const SmokeClass &c() { return m->c(); }
+ Smoke *smoke() { return c().smoke(); }
+ VALUE * var() { return &rv; }
+ void *ptr() { return m->ptr(); }
+ Smoke::Index classId() { return c().classId(); }
+ void *cast(const SmokeClass &toc) {
+ return smoke()->cast(
+ ptr(),
+ classId(),
+ smoke()->idClass(toc.className())
+ );
+ }
+ const char *className() { return c().className(); }
+
+ bool isValid() const { return !NIL_P(rv); }
+ bool isAllocated() const { return m->isAllocated(); }
+ void setAllocated(bool i) { m->setAllocated(i); }
+};
+
+
+/**
+ * Since it's not easy to share functions between Ruby modules, the common
+ * interface between all Smoked libraries and Ruby will be defined in this
+ * class. There will be only one SmokeRuby instance loaded for an entire Ruby
+ * process. It has no data members here -- this is only an abstract interface.
+ */
+
+class SmokeRuby {
+ void *future_extension;
+public:
+ SmokeRuby() : future_extension(0) {}
+
+ // don't need this, we're only defining an interface
+ virtual ~SmokeRuby() = 0;
+
+ /**
+ * Registers a Smoke object
+ */
+ virtual void registerSmoke(const char *name, Smoke *smoke) = 0;
+
+ /**
+ * Gets a smoke object from its name
+ */
+ virtual Smoke *getSmoke(const char *name) = 0;
+
+ /**
+ * Determines if the named smoke is registered.
+ */
+ bool isSmokeRegistered(const char *name) { return getSmoke(name) ? true : false; }
+
+ virtual void registerHandlers(TypeHandler *handlers) = 0;
+
+ /**
+ * Returns a new blessed SV referring to the pointer passed.
+ * Use sv_2mortal() before passing it around.
+ *
+ * @param p pointer to the C++ object. The pointer isn't automatically deleted by SmokePerl.
+ * @param c class of the pointer
+ * @see #getObject
+ * @see #deleteObject
+ */
+ virtual SmokeObject newObject(void *p, const SmokeClass &c) = 0;
+
+ /**
+ * Same as newObject(), except it doesn't treat p as owned by Perl
+ */
+ virtual SmokeObject wrapObject(void *p, const SmokeClass &c) = 0;
+
+ /**
+ * Any SV* created with newObject() on a class with virtual methods can be
+ * retrieved again.
+ */
+ virtual SmokeObject getObject(void *p) = 0;
+
+ /**
+ * Create a SmokeObject from the given VALUE
+ */
+ virtual SmokeObject getObject(VALUE value) = 0;
+};
+
+/*
+ * Type handling by moc is simple.
+ *
+ * If the type name matches /^(?:const\s+)?\Q$types\E&?$/, use the
+ * static_QUType, where $types is join('|', qw(bool int double char* QString);
+ *
+ * Everything else is passed as a pointer! There are types which aren't
+ * Smoke::tf_ptr but will have to be passed as a pointer. Make sure to keep
+ * track of what's what.
+ */
+
+/*
+ * Simply using typeids isn't enough for signals/slots. It will be possible
+ * to declare signals and slots which use arguments which can't all be
+ * found in a single smoke object. Instead, we need to store smoke => typeid
+ * pairs. We also need additional informatation, such as whether we're passing
+ * a pointer to the union element.
+ */
+
+enum MocArgumentType {
+ xmoc_ptr,
+ xmoc_bool,
+ xmoc_int,
+ xmoc_double,
+ xmoc_charstar,
+ xmoc_QString
+};
+
+struct MocArgument {
+ // smoke object and associated typeid
+ SmokeType st;
+ MocArgumentType argType;
+};
+
+#endif // SMOKERUBY_H
diff --git a/qtruby/rubylib/tutorial/t1/t1.rb b/qtruby/rubylib/tutorial/t1/t1.rb
new file mode 100755
index 00000000..19d8a029
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t1/t1.rb
@@ -0,0 +1,11 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt'
+
+a = Qt::Application.new(ARGV)
+hello = Qt::PushButton.new('Hello World!', nil)
+hello.resize(100, 30)
+a.setMainWidget(hello)
+hello.show()
+a.exec()
diff --git a/qtruby/rubylib/tutorial/t10/cannon.rb b/qtruby/rubylib/tutorial/t10/cannon.rb
new file mode 100644
index 00000000..3c02f8ff
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t10/cannon.rb
@@ -0,0 +1,71 @@
+require 'Qt'
+
+class CannonField < Qt::Widget
+ signals 'angleChanged(int)', 'forceChanged(int)'
+ slots 'setAngle(int)', 'setForce(int)'
+
+ def initialize(parent, name)
+ super
+ @ang = 45
+ @f = 0
+ setPalette( Qt::Palette.new( Qt::Color.new( 250, 250, 200) ) )
+ end
+
+ def setAngle( degrees )
+ if degrees < 5
+ degrees = 5
+ elsif degrees > 70
+ degrees = 70
+ end
+ if @ang == degrees
+ return
+ end
+ @ang = degrees
+ repaint()
+ emit angleChanged( @ang )
+ end
+
+ def setForce( newton )
+ if newton < 0
+ newton = 0
+ end
+ if @f == newton
+ return
+ end
+ @f = newton
+ emit forceChanged( @f )
+ end
+
+ def paintEvent( e )
+ if !e.rect().intersects( cannonRect() )
+ return
+ end
+
+ cr = cannonRect()
+ pix = Qt::Pixmap.new( cr.size() )
+ pix.fill( self, cr.topLeft() )
+
+ p = Qt::Painter.new( pix )
+ p.setBrush( blue )
+ p.setPen( Qt::NoPen )
+ p.translate( 0, pix.height() - 1 )
+ p.drawPie( Qt::Rect.new(-35, -35, 70, 70), 0, 90*16 )
+ p.rotate( - @ang )
+ p.drawRect( Qt::Rect.new(33, -4, 15, 8) )
+ p.end()
+
+ p.begin(self)
+ p.drawPixmap(cr.topLeft(), pix )
+ p.end()
+ end
+
+ def cannonRect()
+ r = Qt::Rect.new( 0, 0, 50, 50)
+ r.moveBottomLeft( rect().bottomLeft() )
+ return r
+ end
+
+ def sizePolicy()
+ return Qt::SizePolicy.new( Qt::SizePolicy::Expanding, Qt::SizePolicy::Expanding )
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t10/lcdrange.rb b/qtruby/rubylib/tutorial/t10/lcdrange.rb
new file mode 100644
index 00000000..a0adc842
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t10/lcdrange.rb
@@ -0,0 +1,35 @@
+require 'Qt'
+
+class LCDRange < Qt::VBox
+ signals 'valueChanged(int)'
+ slots 'setValue(int)', 'setRange(int, int)'
+
+ def initialize(parent, name)
+ super
+ lcd = Qt::LCDNumber.new(2, self, 'lcd')
+ @slider = Qt::Slider.new(Qt::VBox::Horizontal, self, 'slider')
+ @slider.setRange(0, 99)
+ @slider.setValue(0)
+ connect(@slider, SIGNAL('valueChanged(int)'), lcd, SLOT('display(int)'))
+ connect(@slider, SIGNAL('valueChanged(int)'), SIGNAL('valueChanged(int)'))
+ setFocusProxy(@slider)
+ end
+
+ def value()
+ @slider.value()
+ end
+
+ def setValue( value )
+ @slider.setValue( value )
+ end
+
+ def setRange( minVal, maxVal )
+ if minVal < 0 || maxVal > 99 || minVal > maxVal
+ qWarning( "LCDRange::setRange(#{minVal},#{maxVal})\n" +
+ "\tRange must be 0..99\n" +
+ "\tand minVal must not be greater than maxVal" )
+ return
+ end
+ @slider.setRange( minVal, maxVal )
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t10/t10.rb b/qtruby/rubylib/tutorial/t10/t10.rb
new file mode 100755
index 00000000..4168d507
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t10/t10.rb
@@ -0,0 +1,57 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt'
+require 'lcdrange.rb'
+require 'cannon.rb'
+
+class MyWidget < Qt::Widget
+ def initialize()
+ super
+ quit = Qt::PushButton.new('Quit', self, 'quit')
+ quit.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
+
+ connect(quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+
+ angle = LCDRange.new( self, 'angle' )
+ angle.setRange( 5, 70 )
+
+ force = LCDRange.new( self, 'force' )
+ force.setRange( 10, 50 )
+
+ cannonField = CannonField.new( self, 'cannonField' )
+
+ connect( angle, SIGNAL('valueChanged(int)'),
+ cannonField, SLOT('setAngle(int)') )
+ connect( cannonField, SIGNAL('angleChanged(int)'),
+ angle, SLOT('setValue(int)') )
+
+ connect( force, SIGNAL('valueChanged(int)'),
+ cannonField, SLOT('setForce(int)') )
+ connect( cannonField, SIGNAL('forceChanged(int)'),
+ force, SLOT('setValue(int)') )
+
+ grid = Qt::GridLayout.new( self, 2, 2, 10 )
+ grid.addWidget( quit, 0, 0 )
+ grid.addWidget( cannonField, 1, 1 )
+ grid.setColStretch( 1, 10 )
+
+ leftBox = Qt::VBoxLayout.new()
+ grid.addLayout( leftBox, 1, 0 )
+ leftBox.addWidget( angle )
+ leftBox.addWidget( force )
+
+ angle.setValue( 60 )
+ force.setValue( 25 )
+ angle.setFocus()
+ end
+end
+
+Qt::Application.setColorSpec( Qt::Application::CustomColor )
+a = Qt::Application.new(ARGV)
+
+w = MyWidget.new
+w.setGeometry( 100, 100, 500, 355 )
+a.setMainWidget(w)
+w.show
+a.exec
diff --git a/qtruby/rubylib/tutorial/t11/cannon.rb b/qtruby/rubylib/tutorial/t11/cannon.rb
new file mode 100644
index 00000000..e9446b02
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t11/cannon.rb
@@ -0,0 +1,137 @@
+include Math
+require 'Qt'
+
+class CannonField < Qt::Widget
+
+ signals 'angleChanged(int)', 'forceChanged(int)'
+ slots 'setAngle(int)', 'setForce(int)', 'shoot()', 'moveShot()'
+
+ def initialize(parent, name)
+ super
+ @ang = 45
+ @f = 0
+ @timerCount = 0;
+ @autoShootTimer = Qt::Timer.new( self, 'movement handler' )
+ connect( @autoShootTimer, SIGNAL('timeout()'),
+ self, SLOT('moveShot()') );
+ @shoot_ang = 0
+ @shoot_f = 0
+ setPalette( Qt::Palette.new( Qt::Color.new( 250, 250, 200) ) )
+ @barrelRect = Qt::Rect.new(33, -4, 15, 8)
+ end
+
+ def setAngle( degrees )
+ if degrees < 5
+ degrees = 5
+ elsif degrees > 70
+ degrees = 70
+ end
+ if @ang == degrees
+ return
+ end
+ @ang = degrees
+ repaint( cannonRect(), false )
+ emit angleChanged( @ang )
+ end
+
+ def setForce( newton )
+ if newton < 0
+ newton = 0
+ end
+ if @f == newton
+ return
+ end
+ @f = newton
+ emit forceChanged( @f )
+ end
+
+ def shoot()
+ if @autoShootTimer.isActive()
+ return
+ end;
+ @timerCount = 0
+ @shoot_ang = @ang
+ @shoot_f = @f
+ @autoShootTimer.start( 50 )
+ end
+
+ def moveShot()
+ r = Qt::Region.new( shotRect() )
+ @timerCount += 1
+
+ shotR = shotRect()
+
+ if shotR.x() > width() || shotR.y() > height()
+ @autoShootTimer.stop()
+ else
+ r = r.unite( Qt::Region.new( shotR ) )
+ end
+ repaint( r )
+ end
+
+ def paintEvent( e )
+ updateR = e.rect()
+ p = Qt::Painter.new( self )
+
+ if updateR.intersects( cannonRect() )
+ paintCannon( p )
+ end
+ if @autoShootTimer.isActive() &&
+ updateR.intersects( shotRect() )
+ paintShot( p )
+ end
+ p.end()
+ end
+
+ def paintShot( p )
+ p.setBrush( black )
+ p.setPen( Qt::NoPen )
+ p.drawRect( shotRect() )
+ end
+
+ def paintCannon(p)
+ cr = cannonRect()
+ pix = Qt::Pixmap.new( cr.size() )
+ pix.fill( self, cr.topLeft() )
+
+ tmp = Qt::Painter.new( pix )
+ tmp.setBrush( blue )
+ tmp.setPen( Qt::NoPen )
+ tmp.translate( 0, pix.height() - 1 )
+ tmp.drawPie( Qt::Rect.new(-35, -35, 70, 70), 0, 90*16 )
+ tmp.rotate( - @ang )
+ tmp.drawRect( @barrelRect )
+ tmp.end()
+
+ p.drawPixmap(cr.topLeft(), pix )
+ end
+
+ def cannonRect()
+ r = Qt::Rect.new( 0, 0, 50, 50)
+ r.moveBottomLeft( rect().bottomLeft() )
+ return r
+ end
+
+ def shotRect()
+ gravity = 4.0
+
+ time = @timerCount / 4.0
+ velocity = @shoot_f
+ radians = @shoot_ang*3.14159265/180.0
+
+ velx = velocity*cos( radians )
+ vely = velocity*sin( radians )
+ x0 = ( @barrelRect.right() + 5.0 )*cos(radians)
+ y0 = ( @barrelRect.right() + 5.0 )*sin(radians)
+ x = x0 + velx*time
+ y = y0 + vely*time - 0.5*gravity*time*time
+
+ r = Qt::Rect.new( 0, 0, 6, 6 );
+ r.moveCenter( Qt::Point.new( x.round, height() - 1 - y.round ) )
+ return r
+ end
+
+ def sizePolicy()
+ return Qt::SizePolicy.new( Qt::SizePolicy::Expanding, Qt::SizePolicy::Expanding )
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t11/lcdrange.rb b/qtruby/rubylib/tutorial/t11/lcdrange.rb
new file mode 100644
index 00000000..a0adc842
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t11/lcdrange.rb
@@ -0,0 +1,35 @@
+require 'Qt'
+
+class LCDRange < Qt::VBox
+ signals 'valueChanged(int)'
+ slots 'setValue(int)', 'setRange(int, int)'
+
+ def initialize(parent, name)
+ super
+ lcd = Qt::LCDNumber.new(2, self, 'lcd')
+ @slider = Qt::Slider.new(Qt::VBox::Horizontal, self, 'slider')
+ @slider.setRange(0, 99)
+ @slider.setValue(0)
+ connect(@slider, SIGNAL('valueChanged(int)'), lcd, SLOT('display(int)'))
+ connect(@slider, SIGNAL('valueChanged(int)'), SIGNAL('valueChanged(int)'))
+ setFocusProxy(@slider)
+ end
+
+ def value()
+ @slider.value()
+ end
+
+ def setValue( value )
+ @slider.setValue( value )
+ end
+
+ def setRange( minVal, maxVal )
+ if minVal < 0 || maxVal > 99 || minVal > maxVal
+ qWarning( "LCDRange::setRange(#{minVal},#{maxVal})\n" +
+ "\tRange must be 0..99\n" +
+ "\tand minVal must not be greater than maxVal" )
+ return
+ end
+ @slider.setRange( minVal, maxVal )
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t11/t11.rb b/qtruby/rubylib/tutorial/t11/t11.rb
new file mode 100755
index 00000000..8656f6f5
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t11/t11.rb
@@ -0,0 +1,67 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt'
+require 'lcdrange.rb'
+require 'cannon.rb'
+
+class MyWidget < Qt::Widget
+ def initialize()
+ super
+ quit = Qt::PushButton.new('Quit', self, 'quit')
+ quit.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
+
+ connect(quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+
+ angle = LCDRange.new( self, 'angle' )
+ angle.setRange( 5, 70 )
+
+ force = LCDRange.new( self, 'force' )
+ force.setRange( 10, 50 )
+
+ cannonField = CannonField.new( self, 'cannonField' )
+
+ connect( angle, SIGNAL('valueChanged(int)'),
+ cannonField, SLOT('setAngle(int)') )
+ connect( cannonField, SIGNAL('angleChanged(int)'),
+ angle, SLOT('setValue(int)') )
+
+ connect( force, SIGNAL('valueChanged(int)'),
+ cannonField, SLOT('setForce(int)') )
+ connect( cannonField, SIGNAL('forceChanged(int)'),
+ force, SLOT('setValue(int)') )
+
+ shoot = Qt::PushButton.new( '&Shoot', self, 'shoot' )
+ shoot.setFont( Qt::Font.new( 'Times', 18, Qt::Font::Bold ) )
+
+ connect( shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()') )
+
+ grid = Qt::GridLayout.new( self, 2, 2, 10 )
+ grid.addWidget( quit, 0, 0 )
+ grid.addWidget( cannonField, 1, 1 )
+ grid.setColStretch( 1, 10 )
+
+ leftBox = Qt::VBoxLayout.new()
+ grid.addLayout( leftBox, 1, 0 )
+ leftBox.addWidget( angle )
+ leftBox.addWidget( force )
+
+ topBox = Qt::HBoxLayout.new()
+ grid.addLayout( topBox, 0, 1 )
+ topBox.addWidget( shoot )
+ topBox.addStretch( 1 )
+
+ angle.setValue( 60 )
+ force.setValue( 25 )
+ angle.setFocus()
+ end
+end
+
+Qt::Application.setColorSpec( Qt::Application::CustomColor )
+a = Qt::Application.new(ARGV)
+
+w = MyWidget.new
+w.setGeometry( 100, 100, 500, 355 )
+a.setMainWidget(w)
+w.show
+a.exec
diff --git a/qtruby/rubylib/tutorial/t12/cannon.rb b/qtruby/rubylib/tutorial/t12/cannon.rb
new file mode 100644
index 00000000..1b72cbc0
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t12/cannon.rb
@@ -0,0 +1,173 @@
+include Math
+require 'Qt'
+
+class CannonField < Qt::Widget
+
+ signals 'hit()', 'missed()', 'angleChanged(int)', 'forceChanged(int)'
+ slots 'setAngle(int)', 'setForce(int)', 'shoot()', 'moveShot()', 'newTarget()'
+
+ def initialize(parent, name)
+ super
+ @ang = 45
+ @f = 0
+ @timerCount = 0;
+ @autoShootTimer = Qt::Timer.new( self, 'movement handler' )
+ connect( @autoShootTimer, SIGNAL('timeout()'),
+ self, SLOT('moveShot()') );
+ @shoot_ang = 0
+ @shoot_f = 0
+ @target = Qt::Point.new(0, 0)
+ setPalette( Qt::Palette.new( Qt::Color.new( 250, 250, 200) ) )
+ newTarget()
+ @barrelRect = Qt::Rect.new(33, -4, 15, 8)
+ end
+
+ def setAngle( degrees )
+ if degrees < 5
+ degrees = 5
+ elsif degrees > 70
+ degrees = 70
+ end
+ if @ang == degrees
+ return
+ end
+ @ang = degrees
+ repaint( cannonRect(), false )
+ emit angleChanged( @ang )
+ end
+
+ def setForce( newton )
+ if newton < 0
+ newton = 0
+ end
+ if @f == newton
+ return
+ end
+ @f = newton
+ emit forceChanged( @f )
+ end
+
+ def shoot()
+ if @autoShootTimer.isActive()
+ return
+ end;
+ @timerCount = 0
+ @shoot_ang = @ang
+ @shoot_f = @f
+ @autoShootTimer.start( 50 )
+ end
+
+ @@first_time = true
+
+ def newTarget()
+ if @@first_time
+ @@first_time = false
+ midnight = Qt::Time.new( 0, 0, 0 )
+ srand( midnight.secsTo(Qt::Time.currentTime()) )
+ end
+ r = Qt::Region.new( targetRect() )
+ @target = Qt::Point.new( 200 + rand(190),
+ 10 + rand(255) )
+ repaint( r.unite( Qt::Region.new(targetRect()) ) )
+ end
+
+ def moveShot()
+ r = Qt::Region.new( shotRect() )
+ @timerCount += 1
+
+ shotR = shotRect()
+
+ if shotR.intersects( targetRect() )
+ @autoShootTimer.stop()
+ emit hit()
+ elsif shotR.x() > width() || shotR.y() > height()
+ @autoShootTimer.stop()
+ emit missed()
+ else
+ r = r.unite( Qt::Region.new( shotR ) )
+ end
+
+ repaint( r )
+ end
+
+ def paintEvent( e )
+ updateR = e.rect()
+ p = Qt::Painter.new( self )
+
+ if updateR.intersects( cannonRect() )
+ paintCannon( p )
+ end
+ if @autoShootTimer.isActive() &&
+ updateR.intersects( shotRect() )
+ paintShot( p )
+ end
+ if updateR.intersects( targetRect() )
+ paintTarget( p )
+ end
+ p.end()
+ end
+
+ def paintShot( p )
+ p.setBrush( black )
+ p.setPen( Qt::NoPen )
+ p.drawRect( shotRect() )
+ end
+
+ def paintTarget( p )
+ p.setBrush( red )
+ p.setPen( black )
+ p.drawRect( targetRect() )
+ end
+
+ def paintCannon(p)
+ cr = cannonRect()
+ pix = Qt::Pixmap.new( cr.size() )
+ pix.fill( self, cr.topLeft() )
+
+ tmp = Qt::Painter.new( pix )
+ tmp.setBrush( blue )
+ tmp.setPen( Qt::NoPen )
+ tmp.translate( 0, pix.height() - 1 )
+ tmp.drawPie( Qt::Rect.new(-35, -35, 70, 70), 0, 90*16 )
+ tmp.rotate( - @ang )
+ tmp.drawRect( @barrelRect )
+ tmp.end()
+
+ p.drawPixmap(cr.topLeft(), pix )
+ end
+
+ def cannonRect()
+ r = Qt::Rect.new( 0, 0, 50, 50)
+ r.moveBottomLeft( rect().bottomLeft() )
+ return r
+ end
+
+ def shotRect()
+ gravity = 4.0
+
+ time = @timerCount / 4.0
+ velocity = @shoot_f
+ radians = @shoot_ang*3.14159265/180.0
+
+ velx = velocity*cos( radians )
+ vely = velocity*sin( radians )
+ x0 = ( @barrelRect.right() + 5.0 )*cos(radians)
+ y0 = ( @barrelRect.right() + 5.0 )*sin(radians)
+ x = x0 + velx*time
+ y = y0 + vely*time - 0.5*gravity*time*time
+
+ r = Qt::Rect.new( 0, 0, 6, 6 );
+ r.moveCenter( Qt::Point.new( x.round, height() - 1 - y.round ) )
+ return r
+ end
+
+ def targetRect()
+ r = Qt::Rect.new( 0, 0, 20, 10 )
+ r.moveCenter( Qt::Point.new(@target.x(),height() - 1 - @target.y()) );
+ return r
+ end
+
+ def sizePolicy()
+ return Qt::SizePolicy.new( Qt::SizePolicy::Expanding, Qt::SizePolicy::Expanding )
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t12/lcdrange.rb b/qtruby/rubylib/tutorial/t12/lcdrange.rb
new file mode 100644
index 00000000..ef5c849d
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t12/lcdrange.rb
@@ -0,0 +1,47 @@
+require 'Qt'
+
+class LCDRange < Qt::VBox
+ signals 'valueChanged(int)'
+ slots 'setValue(int)', 'setRange(int, int)', 'setText(const char *)'
+
+ def initialize(s, parent, name)
+ super(parent, name)
+ init()
+ setText(s)
+ end
+
+ def init()
+ lcd = Qt::LCDNumber.new(2, self, 'lcd')
+ @slider = Qt::Slider.new(Qt::VBox::Horizontal, self, 'slider')
+ @slider.setRange(0, 99)
+ @slider.setValue(0)
+ @label = Qt::Label.new( ' ', self, 'label' )
+ @label.setAlignment( Qt::AlignCenter )
+ connect(@slider, SIGNAL('valueChanged(int)'), lcd, SLOT('display(int)'))
+ connect(@slider, SIGNAL('valueChanged(int)'), SIGNAL('valueChanged(int)'))
+ setFocusProxy(@slider)
+ end
+
+ def value()
+ @slider.value()
+ end
+
+ def setValue( value )
+ @slider.setValue( value )
+ end
+
+ def setRange( minVal, maxVal )
+ if minVal < 0 || maxVal > 99 || minVal > maxVal
+ qWarning( "LCDRange::setRange(#{minVal},#{maxVal})\n" +
+ "\tRange must be 0..99\n" +
+ "\tand minVal must not be greater than maxVal" )
+ return
+ end
+ @slider.setRange( minVal, maxVal )
+ end
+
+ def setText( s )
+ @label.setText( s )
+ end
+
+end
diff --git a/qtruby/rubylib/tutorial/t12/t12.rb b/qtruby/rubylib/tutorial/t12/t12.rb
new file mode 100755
index 00000000..a02c3a8e
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t12/t12.rb
@@ -0,0 +1,68 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt'
+require 'lcdrange.rb'
+require 'cannon.rb'
+
+class MyWidget < Qt::Widget
+
+ def initialize()
+ super
+ quit = Qt::PushButton.new('&Quit', self, 'quit')
+ quit.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
+
+ connect(quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+
+ angle = LCDRange.new( 'ANGLE', self, 'angle' )
+ angle.setRange( 5, 70 )
+
+ force = LCDRange.new( 'FORCE', self, 'force' )
+ force.setRange( 10, 50 )
+
+ cannonField = CannonField.new( self, 'cannonField' )
+
+ connect( angle, SIGNAL('valueChanged(int)'),
+ cannonField, SLOT('setAngle(int)') )
+ connect( cannonField, SIGNAL('angleChanged(int)'),
+ angle, SLOT('setValue(int)') )
+
+ connect( force, SIGNAL('valueChanged(int)'),
+ cannonField, SLOT('setForce(int)') )
+ connect( cannonField, SIGNAL('forceChanged(int)'),
+ force, SLOT('setValue(int)') )
+
+ shoot = Qt::PushButton.new( '&Shoot', self, 'shoot' )
+ shoot.setFont( Qt::Font.new( 'Times', 18, Qt::Font::Bold ) )
+
+ connect( shoot, SIGNAL('clicked()'), cannonField, SLOT('shoot()') )
+
+ grid = Qt::GridLayout.new( self, 2, 2, 10 )
+ grid.addWidget( quit, 0, 0 )
+ grid.addWidget( cannonField, 1, 1 )
+ grid.setColStretch( 1, 10 )
+
+ leftBox = Qt::VBoxLayout.new()
+ grid.addLayout( leftBox, 1, 0 )
+ leftBox.addWidget( angle )
+ leftBox.addWidget( force )
+
+ topBox = Qt::HBoxLayout.new()
+ grid.addLayout( topBox, 0, 1 )
+ topBox.addWidget( shoot )
+ topBox.addStretch( 1 )
+
+ angle.setValue( 60 )
+ force.setValue( 25 )
+ angle.setFocus()
+ end
+end
+
+Qt::Application.setColorSpec( Qt::Application::CustomColor )
+a = Qt::Application.new(ARGV)
+
+w = MyWidget.new
+w.setGeometry( 100, 100, 500, 355 )
+a.setMainWidget(w)
+w.show
+a.exec
diff --git a/qtruby/rubylib/tutorial/t13/cannon.rb b/qtruby/rubylib/tutorial/t13/cannon.rb
new file mode 100644
index 00000000..d99f9a09
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t13/cannon.rb
@@ -0,0 +1,219 @@
+require 'Qt'
+include Math
+
+class CannonField < Qt::Widget
+
+ signals 'hit()', 'missed()', 'angleChanged(int)', 'forceChanged(int)',
+ 'canShoot(bool)'
+
+ slots 'setAngle(int)', 'setForce(int)', 'shoot()', 'moveShot()',
+ 'newTarget()', 'setGameOver()', 'restartGame'
+
+
+ def initialize(parent, name)
+ super
+ @ang = 45
+ @f = 0
+ @timerCount = 0;
+ @autoShootTimer = Qt::Timer.new( self, "movement handler" )
+ connect( @autoShootTimer, SIGNAL('timeout()'),
+ self, SLOT('moveShot()') );
+ @shoot_ang = 0
+ @shoot_f = 0
+ @target = Qt::Point.new(0, 0)
+ @gameEnded = false
+ setPalette( Qt::Palette.new( Qt::Color.new( 250, 250, 200) ) )
+ newTarget()
+ @barrelRect = Qt::Rect.new(33, -4, 15, 8)
+ end
+
+ def angle()
+ return @ang
+ end
+ def force()
+ return @f
+ end
+ def gameOver()
+ return @gameEnded
+ end
+
+ def setAngle( degrees )
+ if degrees < 5
+ degrees = 5
+ elsif degrees > 70
+ degrees = 70
+ end
+ if @ang == degrees
+ return
+ end
+ @ang = degrees
+ repaint( cannonRect(), false )
+ emit angleChanged( @ang )
+ end
+
+ def setForce( newton )
+ if newton < 0
+ newton = 0
+ end
+ if @f == newton
+ return
+ end
+ @f = newton
+ emit forceChanged( @f )
+ end
+
+ def shoot()
+ if isShooting()
+ return
+ end
+ @timerCount = 0
+ @shoot_ang = @ang
+ @shoot_f = @f
+ @autoShootTimer.start( 50 )
+ emit canShoot( false )
+ end
+
+ @@first_time = true
+
+ def newTarget()
+ if @@first_time
+ @@first_time = false
+ midnight = Qt::Time.new( 0, 0, 0 )
+ srand( midnight.secsTo(Qt::Time.currentTime()) )
+ end
+ r = Qt::Region.new( targetRect() )
+ @target = Qt::Point.new( 200 + rand(190),
+ 10 + rand(255) )
+ repaint( r.unite( Qt::Region.new(targetRect()) ) )
+ end
+
+ def setGameOver()
+ if @gameEnded
+ return
+ end
+ if isShooting()
+ @autoShootTimer.stop()
+ end
+ @gameEnded = true
+ repaint()
+ end
+
+ def restartGame()
+ if isShooting()
+ @autoShootTimer.stop()
+ end
+ @gameEnded = false
+ repaint()
+ emit canShoot( true )
+ end
+
+ def moveShot()
+ r = Qt::Region.new( shotRect() )
+ @timerCount += 1
+
+ shotR = shotRect()
+
+ if shotR.intersects( targetRect() )
+ @autoShootTimer.stop()
+ emit hit()
+ emit canShoot(true)
+ elsif shotR.x() > width() || shotR.y() > height()
+ @autoShootTimer.stop()
+ emit missed()
+ emit canShoot(true)
+ else
+ r = r.unite( Qt::Region.new( shotR ) )
+ end
+
+ repaint( r )
+ end
+
+ def paintEvent( e )
+ updateR = e.rect()
+ p = Qt::Painter.new( self )
+
+ if @gameEnded
+ p.setPen( black )
+ p.setFont( Qt::Font.new( "Courier", 48, QFont::Bold ) )
+ p.drawText( rect(), AlignCenter, "Game Over" )
+ end
+ if updateR.intersects( cannonRect() )
+ paintCannon( p )
+ end
+ if isShooting() && updateR.intersects( shotRect() )
+ paintShot( p )
+ end
+ if !@gameEnded && updateR.intersects( targetRect() )
+ paintTarget( p )
+ end
+ p.end()
+ end
+
+ def paintShot( p )
+ p.setBrush( black )
+ p.setPen( Qt::NoPen )
+ p.drawRect( shotRect() )
+ end
+
+ def paintTarget( p )
+ p.setBrush( red )
+ p.setPen( black )
+ p.drawRect( targetRect() )
+ end
+
+ def paintCannon(p)
+ cr = cannonRect()
+ pix = Qt::Pixmap.new( cr.size() )
+ pix.fill( self, cr.topLeft() )
+
+ tmp = Qt::Painter.new( pix )
+ tmp.setBrush( blue )
+ tmp.setPen( Qt::NoPen )
+ tmp.translate( 0, pix.height() - 1 )
+ tmp.drawPie( Qt::Rect.new(-35, -35, 70, 70), 0, 90*16 )
+ tmp.rotate( - @ang )
+ tmp.drawRect( @barrelRect )
+ tmp.end()
+
+ p.drawPixmap(cr.topLeft(), pix )
+ end
+
+ def cannonRect()
+ r = Qt::Rect.new( 0, 0, 50, 50)
+ r.moveBottomLeft( rect().bottomLeft() )
+ return r
+ end
+
+ def shotRect()
+ gravity = 4.0
+
+ time = @timerCount / 4.0
+ velocity = @shoot_f
+ radians = @shoot_ang*3.14159265/180.0
+
+ velx = velocity*cos( radians )
+ vely = velocity*sin( radians )
+ x0 = ( @barrelRect.right() + 5.0 )*cos(radians)
+ y0 = ( @barrelRect.right() + 5.0 )*sin(radians)
+ x = x0 + velx*time
+ y = y0 + vely*time - 0.5*gravity*time*time
+
+ r = Qt::Rect.new( 0, 0, 6, 6 );
+ r.moveCenter( Qt::Point.new( x.round, height() - 1 - y.round ) )
+ return r
+ end
+
+ def targetRect()
+ r = Qt::Rect.new( 0, 0, 20, 10 )
+ r.moveCenter( Qt::Point.new(@target.x(),height() - 1 - @target.y()) );
+ return r
+ end
+
+ def isShooting()
+ return @autoShootTimer.isActive()
+ end
+
+ def sizePolicy()
+ return Qt::SizePolicy.new( Qt::SizePolicy::Expanding, Qt::SizePolicy::Expanding )
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t13/gamebrd.rb b/qtruby/rubylib/tutorial/t13/gamebrd.rb
new file mode 100644
index 00000000..dc993927
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t13/gamebrd.rb
@@ -0,0 +1,112 @@
+require 'Qt'
+require 'lcdrange.rb'
+require 'cannon.rb'
+
+class GameBoard < Qt::Widget
+
+ slots 'fire()', 'hit()', 'missed()', 'newGame()'
+
+ def initialize()
+ super
+ quit = Qt::PushButton.new('&Quit', self, 'quit')
+ quit.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
+
+ connect(quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+
+ angle = LCDRange.new( 'ANGLE', self, 'angle' )
+ angle.setRange( 5, 70 )
+
+ force = LCDRange.new( 'FORCE', self, 'force' )
+ force.setRange( 10, 50 )
+
+ @cannonField = CannonField.new( self, 'cannonField' )
+
+ connect( angle, SIGNAL('valueChanged(int)'),
+ @cannonField, SLOT('setAngle(int)') )
+ connect( @cannonField, SIGNAL('angleChanged(int)'),
+ angle, SLOT('setValue(int)') )
+
+ connect( force, SIGNAL('valueChanged(int)'),
+ @cannonField, SLOT('setForce(int)') )
+ connect( @cannonField, SIGNAL('forceChanged(int)'),
+ force, SLOT('setValue(int)') )
+
+ connect( @cannonField, SIGNAL('hit()'),
+ self, SLOT('hit()') )
+ connect( @cannonField, SIGNAL('missed()'),
+ self, SLOT('missed()') )
+
+ shoot = Qt::PushButton.new( '&Shoot', self, 'shoot' )
+ shoot.setFont( Qt::Font.new( 'Times', 18, Qt::Font::Bold ) )
+
+ connect( shoot, SIGNAL('clicked()'), SLOT('fire()') )
+ connect( @cannonField, SIGNAL('canShoot(bool)'),
+ shoot, SLOT('setEnabled(bool)') )
+
+ restart = Qt::PushButton.new( '&New Game', self, 'newgame' )
+ restart.setFont( Qt::Font.new( 'Times', 18, Qt::Font::Bold ) )
+
+ connect( restart, SIGNAL('clicked()'), self, SLOT('newGame()') )
+
+ @hits = Qt::LCDNumber.new( 2, self, 'hits' )
+ @shotsLeft = Qt::LCDNumber.new( 2, self, 'shotsleft' )
+ hitsL = Qt::Label.new( 'HITS', self, 'hitsLabel' )
+ shotsLeftL = Qt::Label.new( 'SHOTS LEFT', self, 'shotsleftLabel' )
+
+ grid = Qt::GridLayout.new( self, 2, 2, 10 )
+ grid.addWidget( quit, 0, 0 )
+ grid.addWidget( @cannonField, 1, 1 )
+ grid.setColStretch( 1, 10 )
+
+ leftBox = Qt::VBoxLayout.new()
+ grid.addLayout( leftBox, 1, 0 )
+ leftBox.addWidget( angle )
+ leftBox.addWidget( force )
+
+ topBox = Qt::HBoxLayout.new()
+ grid.addLayout( topBox, 0, 1 )
+ topBox.addWidget( shoot )
+ topBox.addWidget( @hits )
+ topBox.addWidget( hitsL )
+ topBox.addWidget( @shotsLeft )
+ topBox.addWidget( shotsLeftL )
+ topBox.addStretch( 1 )
+ topBox.addWidget( restart )
+
+ angle.setValue( 60 )
+ force.setValue( 25 )
+ angle.setFocus()
+
+ newGame()
+ end
+
+ def fire()
+ if @cannonField.gameOver() || @cannonField.isShooting()
+ return
+ end
+ @shotsLeft.display( @shotsLeft.intValue() - 1 )
+ @cannonField.shoot()
+ end
+
+ def hit()
+ @hits.display( @hits.intValue() + 1 )
+ if @shotsLeft.intValue() == 0
+ @cannonField.setGameOver()
+ else
+ @cannonField.newTarget()
+ end
+ end
+
+ def missed()
+ if @shotsLeft.intValue() == 0
+ @cannonField.setGameOver()
+ end
+ end
+
+ def newGame()
+ @shotsLeft.display( 15.0 )
+ @hits.display( 0 )
+ @cannonField.restartGame()
+ @cannonField.newTarget()
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t13/lcdrange.rb b/qtruby/rubylib/tutorial/t13/lcdrange.rb
new file mode 100644
index 00000000..03edb89c
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t13/lcdrange.rb
@@ -0,0 +1,55 @@
+require 'Qt'
+
+class LCDRange < Qt::Widget
+ signals 'valueChanged(int)'
+ slots 'setValue(int)', 'setRange(int, int)', 'setText(const char*)'
+
+ def initialize(s, parent, name)
+ super(parent, name)
+ init()
+ setText(s)
+ end
+
+ def init()
+ @lcd = Qt::LCDNumber.new(2, self, 'lcd')
+ @slider = Qt::Slider.new(Qt::VBox::Horizontal, self, 'slider')
+ @slider.setRange(0, 99)
+ @slider.setValue(0)
+
+ @label = Qt::Label.new( ' ', self, 'label' )
+ @label.setAlignment( Qt::AlignCenter )
+
+ connect(@slider, SIGNAL('valueChanged(int)'), @lcd, SLOT('display(int)'))
+ connect(@slider, SIGNAL('valueChanged(int)'), SIGNAL('valueChanged(int)'))
+
+ setFocusProxy(@slider)
+
+ l = Qt::VBoxLayout.new( self )
+ l.addWidget( @lcd, 1 )
+ l.addWidget( @slider )
+ l.addWidget( @label )
+ end
+
+ def value()
+ @slider.value()
+ end
+
+ def setValue( value )
+ @slider.setValue( value )
+ end
+
+ def setRange( minVal, maxVal )
+ if minVal < 0 || maxVal > 99 || minVal > maxVal
+ qWarning( "LCDRange::setRange(#{minVal},#{maxVal})\n" +
+ "\tRange must be 0..99\n" +
+ "\tand minVal must not be greater than maxVal" )
+ return
+ end
+ @slider.setRange( minVal, maxVal )
+ end
+
+ def setText( s )
+ @label.setText( s )
+ end
+
+end
diff --git a/qtruby/rubylib/tutorial/t13/t13.rb b/qtruby/rubylib/tutorial/t13/t13.rb
new file mode 100755
index 00000000..817dfe70
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t13/t13.rb
@@ -0,0 +1,14 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt'
+require 'gamebrd.rb'
+
+Qt::Application.setColorSpec( Qt::Application::CustomColor )
+a = Qt::Application.new(ARGV)
+
+gb = GameBoard.new
+gb.setGeometry( 100, 100, 500, 355 )
+a.setMainWidget(gb)
+gb.show
+a.exec
diff --git a/qtruby/rubylib/tutorial/t14/cannon.rb b/qtruby/rubylib/tutorial/t14/cannon.rb
new file mode 100644
index 00000000..b0f77d37
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t14/cannon.rb
@@ -0,0 +1,279 @@
+require 'Qt'
+include Math
+
+class CannonField < Qt::Widget
+
+ signals 'hit()', 'missed()', 'angleChanged(int)', 'forceChanged(int)',
+ 'canShoot(bool)'
+
+ slots 'setAngle(int)', 'setForce(int)', 'shoot()', 'moveShot()',
+ 'newTarget()', 'setGameOver()', 'restartGame()'
+
+ def initialize(parent, name)
+ super
+ @ang = 45
+ @f = 0
+ @timerCount = 0;
+ @autoShootTimer = Qt::Timer.new( self, 'movement handler' )
+ connect( @autoShootTimer, SIGNAL('timeout()'),
+ self, SLOT('moveShot()') )
+ @shoot_ang = 0
+ @shoot_f = 0
+ @target = Qt::Point.new(0, 0)
+ @gameEnded = false
+ @barrelPressed = false
+ setPalette( Qt::Palette.new( Qt::Color.new( 250, 250, 200) ) )
+ newTarget()
+ @barrelRect = Qt::Rect.new(33, -4, 15, 8)
+ end
+
+ def angle()
+ return @ang
+ end
+
+ def force()
+ return @f
+ end
+
+ def gameOver()
+ return @gameEnded
+ end
+
+ def setAngle( degrees )
+ if degrees < 5
+ degrees = 5
+ elsif degrees > 70
+ degrees = 70
+ end
+ if @ang == degrees
+ return
+ end
+ @ang = degrees
+ repaint( cannonRect(), false )
+ emit angleChanged( @ang )
+ end
+
+ def setForce( newton )
+ if newton < 0
+ newton = 0
+ end
+ if @f == newton
+ return
+ end
+ @f = newton
+ emit forceChanged( @f )
+ end
+
+ def shoot()
+ if isShooting()
+ return
+ end
+ @timerCount = 0
+ @shoot_ang = @ang
+ @shoot_f = @f
+ @autoShootTimer.start( 50 )
+ emit canShoot( false )
+ end
+
+ @@first_time = true
+
+ def newTarget()
+ if @@first_time
+ @@first_time = false
+ midnight = Qt::Time.new( 0, 0, 0 )
+ srand( midnight.secsTo(Qt::Time.currentTime()) )
+ end
+ r = Qt::Region.new( targetRect() )
+ @target = Qt::Point.new( 200 + rand(190),
+ 10 + rand(255) )
+ repaint( r.unite( Qt::Region.new(targetRect()) ) )
+ end
+
+ def setGameOver()
+ if @gameEnded
+ return
+ end
+ if isShooting()
+ @autoShootTimer.stop()
+ end
+ @gameEnded = true
+ repaint()
+ end
+
+ def restartGame()
+ if isShooting()
+ @autoShootTimer.stop()
+ end
+ @gameEnded = false
+ repaint()
+ emit canShoot( true )
+ end
+
+ def moveShot()
+ r = Qt::Region.new( shotRect() )
+ @timerCount += 1
+
+ shotR = shotRect()
+
+ if shotR.intersects( targetRect() )
+ @autoShootTimer.stop()
+ emit hit()
+ emit canShoot(true)
+ elsif shotR.x() > width() || shotR.y() > height() ||
+ shotR.intersects(barrierRect())
+ @autoShootTimer.stop()
+ emit missed()
+ emit canShoot(true)
+ else
+ r = r.unite( Qt::Region.new( shotR ) )
+ end
+
+ repaint( r )
+ end
+ private :moveShot
+
+ def mousePressEvent( e )
+ if e.button() != Qt::LeftButton
+ return
+ end
+ if barrelHit( e.pos() )
+ @barrelPressed = true
+ end
+ end
+
+ def mouseMoveEvent( e )
+ if !@barrelPressed
+ return
+ end
+ pnt = e.pos();
+ if pnt.x() <= 0
+ pnt.setX( 1 )
+ end
+ if pnt.y() >= height()
+ pnt.setY( height() - 1 )
+ end
+ rad = atan2((rect().bottom()-pnt.y()), pnt.x())
+ setAngle( ( rad*180/3.14159265 ).round )
+ end
+
+ def mouseReleaseEvent( e )
+ if e.button() == Qt::LeftButton
+ @barrelPressed = false
+ end
+ end
+
+ def paintEvent( e )
+ updateR = e.rect()
+ p = Qt::Painter.new( self )
+
+ if @gameEnded
+ p.setPen( black )
+ p.setFont( Qt::Font.new( 'Courier', 48, Qt::Font::Bold ) )
+ p.drawText( rect(), Qt::AlignCenter, 'Game Over' )
+ end
+ if updateR.intersects( cannonRect() )
+ paintCannon( p )
+ end
+ if updateR.intersects( barrierRect() )
+ paintBarrier( p )
+ end
+ if isShooting() && updateR.intersects( shotRect() )
+ paintShot( p )
+ end
+ if !@gameEnded && updateR.intersects( targetRect() )
+ paintTarget( p )
+ end
+
+ p.end()
+ end
+
+ def paintShot( p )
+ p.setBrush( black )
+ p.setPen( Qt::NoPen )
+ p.drawRect( shotRect() )
+ end
+
+ def paintTarget( p )
+ p.setBrush( red )
+ p.setPen( black )
+ p.drawRect( targetRect() )
+ end
+
+ def paintBarrier( p )
+ p.setBrush( yellow )
+ p.setPen( black )
+ p.drawRect( barrierRect() )
+ end
+
+ def paintCannon(p)
+ cr = cannonRect()
+ pix = Qt::Pixmap.new( cr.size() )
+ pix.fill( self, cr.topLeft() )
+
+ tmp = Qt::Painter.new( pix )
+ tmp.setBrush( blue )
+ tmp.setPen( Qt::NoPen )
+
+ tmp.translate( 0, pix.height() - 1 )
+ tmp.drawPie( Qt::Rect.new(-35, -35, 70, 70), 0, 90*16 )
+ tmp.rotate( - @ang )
+ tmp.drawRect( @barrelRect )
+ tmp.end()
+
+ p.drawPixmap(cr.topLeft(), pix )
+ end
+ private :paintShot, :paintTarget, :paintBarrier, :paintCannon
+
+ def cannonRect()
+ r = Qt::Rect.new( 0, 0, 50, 50)
+ r.moveBottomLeft( rect().bottomLeft() )
+ return r
+ end
+
+ def shotRect()
+ gravity = 4.0
+
+ time = @timerCount / 4.0
+ velocity = @shoot_f
+ radians = @shoot_ang*3.14159265/180.0
+
+ velx = velocity*cos( radians )
+ vely = velocity*sin( radians )
+ x0 = ( @barrelRect.right() + 5.0 )*cos(radians)
+ y0 = ( @barrelRect.right() + 5.0 )*sin(radians)
+ x = x0 + velx*time
+ y = y0 + vely*time - 0.5*gravity*time*time
+
+ r = Qt::Rect.new( 0, 0, 6, 6 );
+ r.moveCenter( Qt::Point.new( x.round, height() - 1 - y.round ) )
+ return r
+ end
+
+ def targetRect()
+ r = Qt::Rect.new( 0, 0, 20, 10 )
+ r.moveCenter( Qt::Point.new(@target.x(),height() - 1 - @target.y()) )
+ return r
+ end
+
+ def barrierRect()
+ return Qt::Rect.new( 145, height() - 100, 15, 100 )
+ end
+
+ def barrelHit( p )
+ mtx = Qt::WMatrix.new
+ mtx.translate( 0, height() - 1 )
+ mtx.rotate( - @ang )
+ mtx = mtx.invert()
+ return @barrelRect.contains( mtx.map(p) )
+ end
+
+ private :cannonRect, :shotRect, :targetRect, :barrierRect, :barrelHit
+
+ def isShooting()
+ return @autoShootTimer.isActive()
+ end
+
+ def sizePolicy()
+ return Qt::SizePolicy.new( Qt::SizePolicy::Expanding, Qt::SizePolicy::Expanding )
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t14/gamebrd.rb b/qtruby/rubylib/tutorial/t14/gamebrd.rb
new file mode 100644
index 00000000..b72d58c1
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t14/gamebrd.rb
@@ -0,0 +1,121 @@
+require 'lcdrange.rb'
+require 'cannon.rb'
+
+class GameBoard < Qt::Widget
+
+ slots 'fire()', 'hit()', 'missed()', 'newGame()'
+
+ def initialize()
+ super
+ quit = Qt::PushButton.new('&Quit', self, 'quit')
+ quit.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
+
+ connect(quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+
+ angle = LCDRange.new( 'ANGLE', self, 'angle' )
+ angle.setRange( 5, 70 )
+
+ force = LCDRange.new( 'FORCE', self, 'force' )
+ force.setRange( 10, 50 )
+
+ box = Qt::VBox.new( self, 'cannonFrame' )
+ box.setFrameStyle( Qt::Frame::WinPanel | Qt::Frame::Sunken )
+ @cannonField = CannonField.new( box, 'cannonField' )
+
+ connect( angle, SIGNAL('valueChanged(int)'),
+ @cannonField, SLOT('setAngle(int)') )
+ connect( @cannonField, SIGNAL('angleChanged(int)'),
+ angle, SLOT('setValue(int)') )
+
+ connect( force, SIGNAL('valueChanged(int)'),
+ @cannonField, SLOT('setForce(int)') )
+ connect( @cannonField, SIGNAL('forceChanged(int)'),
+ force, SLOT('setValue(int)') )
+
+ connect( @cannonField, SIGNAL('hit()'),
+ self, SLOT('hit()') )
+ connect( @cannonField, SIGNAL('missed()'),
+ self, SLOT('missed()') )
+
+ shoot = Qt::PushButton.new( '&Shoot', self, 'shoot' )
+ shoot.setFont( Qt::Font.new( 'Times', 18, Qt::Font::Bold ) )
+
+ connect( shoot, SIGNAL('clicked()'), SLOT('fire()') )
+ connect( @cannonField, SIGNAL('canShoot(bool)'),
+ shoot, SLOT('setEnabled(bool)') )
+
+ restart = Qt::PushButton.new( '&New Game', self, 'newgame' )
+ restart.setFont( Qt::Font.new( 'Times', 18, Qt::Font::Bold ) )
+
+ connect( restart, SIGNAL('clicked()'), self, SLOT('newGame()') )
+
+ @hits = Qt::LCDNumber.new( 2, self, 'hits' )
+ @shotsLeft = Qt::LCDNumber.new( 2, self, 'shotsleft' )
+ hitsL = Qt::Label.new( 'HITS', self, 'hitsLabel' )
+ shotsLeftL = Qt::Label.new( 'SHOTS LEFT', self, 'shotsleftLabel' )
+
+ accel = Qt::Accel.new( self )
+ accel.connectItem( accel.insertItem( Qt::KeySequence.new(Key_Enter) ),
+ self, SLOT('fire()') )
+ accel.connectItem( accel.insertItem( Qt::KeySequence.new(Key_Return) ),
+ self, SLOT('fire()') )
+ accel.connectItem( accel.insertItem( Qt::KeySequence.new(CTRL+Key_Q) ),
+ $qApp, SLOT('quit()') )
+
+ grid = Qt::GridLayout.new( self, 2, 2, 10 )
+ grid.addWidget( quit, 0, 0 )
+ grid.addWidget( box, 1, 1)
+ grid.setColStretch( 1, 10 )
+
+ leftBox = Qt::VBoxLayout.new()
+ grid.addLayout( leftBox, 1, 0 )
+ leftBox.addWidget( angle )
+ leftBox.addWidget( force )
+
+ topBox = Qt::HBoxLayout.new()
+ grid.addLayout( topBox, 0, 1 )
+ topBox.addWidget( shoot )
+ topBox.addWidget( @hits )
+ topBox.addWidget( hitsL )
+ topBox.addWidget( @shotsLeft )
+ topBox.addWidget( shotsLeftL )
+ topBox.addStretch( 1 )
+ topBox.addWidget( restart )
+
+ angle.setValue( 60 )
+ force.setValue( 25 )
+ angle.setFocus()
+
+ newGame()
+ end
+
+ def fire()
+ if @cannonField.gameOver() || @cannonField.isShooting()
+ return
+ end
+ @shotsLeft.display( @shotsLeft.intValue() - 1 )
+ @cannonField.shoot()
+ end
+
+ def hit()
+ @hits.display( @hits.intValue() + 1 )
+ if @shotsLeft.intValue() == 0
+ @cannonField.setGameOver()
+ else
+ @cannonField.newTarget()
+ end
+ end
+
+ def missed()
+ if @shotsLeft.intValue() == 0
+ @cannonField.setGameOver()
+ end
+ end
+
+ def newGame()
+ @shotsLeft.display( 15.0 )
+ @hits.display( 0 )
+ @cannonField.restartGame()
+ @cannonField.newTarget()
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t14/lcdrange.rb b/qtruby/rubylib/tutorial/t14/lcdrange.rb
new file mode 100644
index 00000000..492d93b1
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t14/lcdrange.rb
@@ -0,0 +1,55 @@
+require 'Qt'
+
+class LCDRange < Qt::Widget
+ signals 'valueChanged(int)'
+ slots 'setValue(int)', 'setRange(int, int)', 'setText(const char*)'
+
+ def initialize(s, parent, name)
+ super(parent, name)
+ init()
+ setText(s)
+ end
+
+ def init()
+ @lcd = Qt::LCDNumber.new(2, self, 'lcd')
+ @slider = Qt::Slider.new(Qt::VBox::Horizontal, self, 'slider')
+ @slider.setRange(0, 99)
+ @slider.setValue(0)
+
+ @label = Qt::Label.new( ' ', self, 'label' )
+ @label.setAlignment( Qt::AlignCenter )
+
+ connect(@slider, SIGNAL('valueChanged(int)'), @lcd, SLOT('display(int)'))
+ connect(@slider, SIGNAL('valueChanged(int)'), SIGNAL('valueChanged(int)'))
+
+ setFocusProxy(@slider)
+
+ @l = Qt::VBoxLayout.new( self )
+ @l.addWidget( @lcd, 1 )
+ @l.addWidget( @slider )
+ @l.addWidget( @label )
+ end
+
+ def value()
+ @slider.value()
+ end
+
+ def setValue( value )
+ @slider.setValue( value )
+ end
+
+ def setRange( minVal, maxVal )
+ if minVal < 0 || maxVal > 99 || minVal > maxVal
+ qWarning( "LCDRange::setRange(#{minVal},#{maxVal})\n" +
+ "\tRange must be 0..99\n" +
+ "\tand minVal must not be greater than maxVal" )
+ return
+ end
+ @slider.setRange( minVal, maxVal )
+ end
+
+ def setText( s )
+ @label.setText( s )
+ end
+
+end
diff --git a/qtruby/rubylib/tutorial/t14/t14.rb b/qtruby/rubylib/tutorial/t14/t14.rb
new file mode 100755
index 00000000..817dfe70
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t14/t14.rb
@@ -0,0 +1,14 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt'
+require 'gamebrd.rb'
+
+Qt::Application.setColorSpec( Qt::Application::CustomColor )
+a = Qt::Application.new(ARGV)
+
+gb = GameBoard.new
+gb.setGeometry( 100, 100, 500, 355 )
+a.setMainWidget(gb)
+gb.show
+a.exec
diff --git a/qtruby/rubylib/tutorial/t2/t2.rb b/qtruby/rubylib/tutorial/t2/t2.rb
new file mode 100755
index 00000000..8139e98c
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t2/t2.rb
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt';
+
+a = Qt::Application.new(ARGV)
+
+quit = Qt::PushButton.new('Quit', nil)
+quit.resize(75, 30)
+quit.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
+
+Qt::Object.connect(quit, SIGNAL('clicked()'), a, SLOT('quit()'))
+
+a.setMainWidget(quit)
+quit.show
+a.exec
+exit
diff --git a/qtruby/rubylib/tutorial/t3/t3.rb b/qtruby/rubylib/tutorial/t3/t3.rb
new file mode 100755
index 00000000..305afbc4
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t3/t3.rb
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt'
+
+a = Qt::Application.new(ARGV)
+
+box = Qt::VBox.new()
+box.resize(200, 120)
+
+quit = Qt::PushButton.new('Quit', box)
+quit.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
+
+a.connect(quit, SIGNAL('clicked()'), SLOT('quit()'))
+
+a.setMainWidget(box)
+box.show
+
+a.exec
+exit
diff --git a/qtruby/rubylib/tutorial/t4/t4.rb b/qtruby/rubylib/tutorial/t4/t4.rb
new file mode 100755
index 00000000..ae48b7ac
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t4/t4.rb
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt'
+
+class MyWidget < Qt::Widget
+
+def initialize(parent = nil, name = nil)
+ super
+ setMinimumSize(200, 120)
+ setMaximumSize(200, 120)
+
+ quit = Qt::PushButton.new('Quit', self, 'quit')
+ quit.setGeometry(62, 40, 75, 30)
+ quit.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
+ connect(quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+end
+
+end
+
+a = Qt::Application.new(ARGV)
+
+w = MyWidget.new
+w.setGeometry(100, 100, 200, 120)
+a.setMainWidget(w)
+w.show
+a.exec
diff --git a/qtruby/rubylib/tutorial/t5/t5.rb b/qtruby/rubylib/tutorial/t5/t5.rb
new file mode 100755
index 00000000..6eb7f808
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t5/t5.rb
@@ -0,0 +1,31 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt'
+
+class MyWidget < Qt::VBox
+
+def initialize()
+ super
+ quit = Qt::PushButton.new('Quit', self, 'quit')
+ quit.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
+
+ connect(quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+
+ lcd = Qt::LCDNumber.new(2, self, 'lcd')
+
+ slider = Qt::Slider.new(Horizontal, self, 'slider')
+ slider.setRange(0, 99)
+ slider.setValue(0)
+
+ connect(slider, SIGNAL('valueChanged(int)'), lcd, SLOT('display(int)'))
+end
+
+end
+
+a = Qt::Application.new(ARGV)
+
+w = MyWidget.new
+a.setMainWidget(w)
+w.show
+a.exec
diff --git a/qtruby/rubylib/tutorial/t6/t6.rb b/qtruby/rubylib/tutorial/t6/t6.rb
new file mode 100755
index 00000000..d89203d0
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t6/t6.rb
@@ -0,0 +1,45 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt'
+
+class LCDRange < Qt::VBox
+
+def initialize(grid)
+ super
+ lcd = Qt::LCDNumber.new(2, self, 'lcd')
+
+ slider = Qt::Slider.new(Qt::VBox::Horizontal, self, 'slider')
+ slider.setRange(0, 99)
+ slider.setValue(0)
+
+ lcd.connect(slider, SIGNAL('valueChanged(int)'), SLOT('display(int)'))
+end
+
+end
+
+class MyWidget < Qt::VBox
+
+def initialize()
+ super
+ quit = Qt::PushButton.new('Quit', self, 'quit')
+ quit.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
+
+ connect(quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+ grid = Qt::Grid.new( 4, self )
+
+ for c in 0..3
+ for r in 0..3
+ LCDRange.new(grid)
+ end
+ end
+end
+
+end
+
+a = Qt::Application.new(ARGV)
+
+w = MyWidget.new
+a.setMainWidget(w)
+w.show
+a.exec
diff --git a/qtruby/rubylib/tutorial/t7/lcdrange.rb b/qtruby/rubylib/tutorial/t7/lcdrange.rb
new file mode 100644
index 00000000..3df3c961
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t7/lcdrange.rb
@@ -0,0 +1,25 @@
+#!/usr/bin/ruby -w
+require 'Qt'
+
+class LCDRange < Qt::VBox
+ signals 'valueChanged(int)'
+ slots 'setValue(int)'
+
+ def initialize(grid)
+ super
+ lcd = Qt::LCDNumber.new(2, self, 'lcd')
+ @slider = Qt::Slider.new(Qt::VBox::Horizontal, self, 'slider')
+ @slider.setRange(0, 99)
+ @slider.setValue(0)
+ connect(@slider, SIGNAL('valueChanged(int)'), lcd, SLOT('display(int)'))
+ connect(@slider, SIGNAL('valueChanged(int)'), SIGNAL('valueChanged(int)'))
+ end
+
+ def value()
+ @slider.value()
+ end
+
+ def setValue( value )
+ @slider.setValue( value )
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t7/t7.rb b/qtruby/rubylib/tutorial/t7/t7.rb
new file mode 100755
index 00000000..396953de
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t7/t7.rb
@@ -0,0 +1,37 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt'
+require 'lcdrange.rb'
+
+class MyWidget < Qt::VBox
+
+def initialize()
+ super
+ quit = Qt::PushButton.new('Quit', self, 'quit')
+ quit.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
+
+ connect(quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+ grid = Qt::Grid.new( 4, self )
+
+ previous = nil
+ for c in 0..3
+ for r in 0..3
+ lr = LCDRange.new(grid)
+ if previous != nil
+ connect( lr, SIGNAL('valueChanged(int)'),
+ previous, SLOT('setValue(int)') )
+ end
+ previous = lr
+ end
+ end
+end
+
+end
+
+a = Qt::Application.new(ARGV)
+
+w = MyWidget.new
+a.setMainWidget(w)
+w.show
+a.exec
diff --git a/qtruby/rubylib/tutorial/t8/cannon.rb b/qtruby/rubylib/tutorial/t8/cannon.rb
new file mode 100644
index 00000000..b3202a93
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t8/cannon.rb
@@ -0,0 +1,38 @@
+require 'Qt'
+
+class CannonField < Qt::Widget
+ signals 'angleChanged(int)'
+ slots 'setAngle(int)'
+
+ def initialize(parent, name)
+ super
+ @ang = 45
+ setPalette( Qt::Palette.new( Qt::Color.new( 250, 250, 200) ) )
+ end
+
+ def setAngle( degrees )
+ if degrees < 5
+ degrees = 5
+ elsif degrees > 70
+ degrees = 70
+ end
+ if @ang == degrees
+ return
+ end
+ @ang = degrees
+ repaint()
+ emit angleChanged( @ang )
+ end
+
+ def paintEvent( event )
+ s = "Angle = #{@ang}"
+ p = Qt::Painter.new( self )
+ p.drawText( 200, 200, s )
+ p.end()
+ end
+
+
+ def sizePolicy()
+ return Qt::SizePolicy.new( Qt::SizePolicy::Expanding, Qt::SizePolicy::Expanding )
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t8/lcdrange.rb b/qtruby/rubylib/tutorial/t8/lcdrange.rb
new file mode 100644
index 00000000..011196fd
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t8/lcdrange.rb
@@ -0,0 +1,35 @@
+require 'Qt'
+
+class LCDRange < Qt::VBox
+ signals 'valueChanged(int)'
+ slots 'setValue(int)', 'setRange(int, int)'
+
+ def initialize(parent, name)
+ super
+ lcd = Qt::LCDNumber.new(2, self, 'lcd')
+ @slider = Qt::Slider.new(Qt::VBox::Horizontal, self, 'slider')
+ @slider.setRange(0, 99)
+ @slider.setValue(0)
+ connect(@slider, SIGNAL('valueChanged(int)'), lcd, SLOT('display(int)'))
+ connect(@slider, SIGNAL('valueChanged(int)'), SIGNAL('valueChanged(int)'))
+ setFocusProxy(@slider)
+ end
+
+ def value()
+ @slider.value()
+ end
+
+ def setValue( value )
+ @slider.setValue( value )
+ end
+
+ def setRange( minVal, maxVal )
+ if minVal < 0 || maxVal > 99 || minVal > maxVal
+ qWarning( "LCDRange::setRange(#{minVal},#{maxVal})\n" +
+ "\tRange must be 0..99\n" +
+ "\tand minVal must not be greater than maxVal" )
+ return
+ end
+ @slider.setRange( minVal, maxVal )
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t8/t8.rb b/qtruby/rubylib/tutorial/t8/t8.rb
new file mode 100755
index 00000000..881d15e7
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t8/t8.rb
@@ -0,0 +1,44 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt'
+require 'lcdrange.rb'
+require 'cannon.rb'
+
+class MyWidget < Qt::Widget
+ def initialize()
+ super
+ quit = Qt::PushButton.new('Quit', self, 'quit')
+ quit.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
+
+ connect(quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+
+ angle = LCDRange.new( self, 'angle' )
+ angle.setRange( 5, 70 )
+
+ cannonField = CannonField.new( self, 'cannonField' )
+
+ connect( angle, SIGNAL('valueChanged(int)'),
+ cannonField, SLOT('setAngle(int)') )
+ connect( cannonField, SIGNAL('angleChanged(int)'),
+ angle, SLOT('setValue(int)') )
+ grid = Qt::GridLayout.new( self, 2, 2, 10 )
+ # 2x2, 10 pixel border
+
+ grid.addWidget( quit, 0, 0 )
+ grid.addWidget( angle, 1, 0, Qt.AlignTop )
+ grid.addWidget( cannonField, 1, 1 )
+ grid.setColStretch( 1, 10 )
+
+ angle.setValue( 60 )
+ angle.setFocus()
+ end
+end
+
+a = Qt::Application.new(ARGV)
+
+w = MyWidget.new
+w.setGeometry( 100, 100, 500, 355 )
+a.setMainWidget(w)
+w.show
+a.exec
diff --git a/qtruby/rubylib/tutorial/t9/cannon.rb b/qtruby/rubylib/tutorial/t9/cannon.rb
new file mode 100644
index 00000000..14bcc70f
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t9/cannon.rb
@@ -0,0 +1,43 @@
+require 'Qt'
+
+class CannonField < Qt::Widget
+ signals 'angleChanged(int)'
+ slots 'setAngle(int)'
+
+ def initialize(parent, name)
+ super
+ @ang = 45
+ setPalette( Qt::Palette.new( Qt::Color.new( 250, 250, 200) ) )
+ end
+
+ def setAngle( degrees )
+ if degrees < 5
+ degrees = 5
+ elsif degrees > 70
+ degrees = 70
+ end
+ if @ang == degrees
+ return
+ end
+ @ang = degrees
+ repaint()
+ emit angleChanged( @ang )
+ end
+
+ def paintEvent( event )
+ p = Qt::Painter.new( self )
+
+ p.setBrush( blue )
+ p.setPen( Qt::NoPen )
+ p.translate( 0, rect().bottom() )
+ p.drawPie( Qt::Rect.new(-35, -35, 70, 70), 0, 90*16 )
+ p.rotate( - @ang )
+ p.drawRect( Qt::Rect.new(33, -4, 15, 8) )
+ p.end()
+ end
+
+
+ def sizePolicy()
+ return Qt::SizePolicy.new( Qt::SizePolicy::Expanding, Qt::SizePolicy::Expanding )
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t9/lcdrange.rb b/qtruby/rubylib/tutorial/t9/lcdrange.rb
new file mode 100644
index 00000000..6eb2f732
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t9/lcdrange.rb
@@ -0,0 +1,36 @@
+require 'Qt'
+
+class LCDRange < Qt::VBox
+ signals 'valueChanged(int)'
+ slots 'setValue(int)', 'setRange(int, int)'
+
+ def initialize(parent, name)
+ super
+ lcd = Qt::LCDNumber.new(2, self, 'lcd')
+ @slider = Qt::Slider.new(Qt::VBox::Horizontal, self, 'slider')
+ @slider.setRange(0, 99)
+ @slider.setValue(0)
+ connect(@slider, SIGNAL('valueChanged(int)'), lcd, SLOT('display(int)'))
+ connect(@slider, SIGNAL('valueChanged(int)'), SIGNAL('valueChanged(int)'))
+ setFocusProxy(@slider)
+ end
+
+ def value()
+ @slider.value()
+ end
+
+ def setValue( value )
+ @slider.setValue( value )
+ end
+
+ def setRange( minVal, maxVal )
+ if minVal < 0 || maxVal > 99 || minVal > maxVal
+ printf( "LCDRange::setRange(%d,%d)\n" +
+ "\tRange must be 0..99\n" +
+ "\tand minVal must not be greater than maxVal",
+ minVal, maxVal )
+ return
+ end
+ @slider.setRange( minVal, maxVal )
+ end
+end
diff --git a/qtruby/rubylib/tutorial/t9/t9.rb b/qtruby/rubylib/tutorial/t9/t9.rb
new file mode 100755
index 00000000..4185b972
--- /dev/null
+++ b/qtruby/rubylib/tutorial/t9/t9.rb
@@ -0,0 +1,44 @@
+#!/usr/bin/env ruby
+$VERBOSE = true; $:.unshift File.dirname($0)
+
+require 'Qt'
+require 'lcdrange.rb'
+require 'cannon.rb'
+
+class MyWidget < Qt::Widget
+ def initialize()
+ super
+ quit = Qt::PushButton.new('Quit', self, 'quit')
+ quit.setFont(Qt::Font.new('Times', 18, Qt::Font::Bold))
+
+ connect(quit, SIGNAL('clicked()'), $qApp, SLOT('quit()'))
+
+ angle = LCDRange.new( self, 'angle' )
+ angle.setRange( 5, 70 )
+
+ cannonField = CannonField.new( self, 'cannonField' )
+
+ connect( angle, SIGNAL('valueChanged(int)'),
+ cannonField, SLOT('setAngle(int)') )
+ connect( cannonField, SIGNAL('angleChanged(int)'),
+ angle, SLOT('setValue(int)') )
+ grid = Qt::GridLayout.new( self, 2, 2, 10 )
+ # 2x2, 10 pixel border
+
+ grid.addWidget( quit, 0, 0 )
+ grid.addWidget( angle, 1, 0, Qt::AlignTop )
+ grid.addWidget( cannonField, 1, 1 )
+ grid.setColStretch( 1, 10 )
+
+ angle.setValue( 60 )
+ angle.setFocus()
+ end
+end
+
+a = Qt::Application.new(ARGV)
+
+w = MyWidget.new
+w.setGeometry( 100, 100, 500, 355 )
+a.setMainWidget(w)
+w.show
+a.exec