1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
|
<?xml version="1.0" ?>
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.1.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
<!ENTITY kdevelop "<application>KDevelop</application>">
<!ENTITY kappname "&kdevelop;">
<!ENTITY % addindex "INCLUDE">
<!ENTITY % English "INCLUDE" > <!-- change language only here -->
]>
<book lang="&language;">
<bookinfo>
<title>The &kdevelop; Programming Handbook</title>
<date>2002-12-05</date>
<releaseinfo>2.0</releaseinfo>
<authorgroup>
<author>
<firstname>Ralf</firstname>
<surname>Nolden</surname>
<affiliation><address><email>Ralf.Nolden@post.rwth-aachen.de</email></address></affiliation>
</author>
<author>
<firstname>Caleb</firstname>
<surname>Tennis</surname>
<affiliation><address><email>caleb@aei-tech.com</email></address></affiliation>
</author>
</authorgroup>
<copyright>
<year>1999</year>
<holder>Ralf Nolden</holder>
</copyright>
<copyright>
<year>2002</year>
<holder>Caleb Tennis</holder>
</copyright>
<!-- ROLES_OF_TRANSLATORS -->
<legalnotice>&FDLNotice;</legalnotice>
<abstract>
<para>The User Guide to C++ Application Design for the K Desktop Environment (KDE) with
the &kdevelop; IDE</para>
</abstract>
<keywordset>
<keyword>KDE</keyword>
<keyword>KDevelop</keyword>
<keyword>IDE</keyword>
<keyword>development</keyword>
<keyword>programming</keyword>
</keywordset>
</bookinfo>
<chapter id="chapter1">
<title>Introduction</title>
<para>
As Unix Systems are becoming more and more popular to even beginners working with computer machines
due to its advantages in regards of stability and functionality, most are somehow disappointed, because
those applications don't have a consistent look and each one behaves different from another. With KDE,
developers have an almost perfect way to create first-class applications for Unix desktop systems to get
a wider user community by the mere quality their applications have to offer. Therefore, KDE becomes more
and more popular as a base for programming design, and developers want to take advantage of the
possibilities that the system has to offer.
</para>
<sect1 id="c1s1">
<title>What you should know already</title>
<para>
For making the best use of this programming handbook, we assume that you already know about the
C++ programming language; if not, you should make yourself familiar with that first. Information about
C++ is available through various sources either in printed form at your local bookstore or by tutorials
found on the Internet. Knowledge about the design of Graphical User Interfaces is not required, as this
handbook tries to cover the application design for KDE programs, which also includes an introduction into
the Qt toolkit as well as the KDE libraries and the design of User Interfaces. Also, you should have made
yourself comfortable with &kdevelop; by reading The User Manual to &kdevelop;, which contains a descriptive
review of the functionality provided by the IDE.
</para>
</sect1>
<sect1 id="c1s2">
<title>About this Handbook</title>
<para>
This handbook has been written to give developers an introduction into KDE application development by
using the KDevelop Integrated Development Environment.
</para>
<para>
The following chapters therefore give an introduction on how to create projects, explains the sourcecode
already generated and shows how to extend the given sources on various topics such as toolbars, menu bars
and view areas.
</para>
<para>
Then the dialogeditor is discussed in detail, explaining how widgets are created and covers widget
properties settings in detail for all provided widgets.
</para>
<para>
Finally, you will learn about several topics that will complete your knowledge in regards of project design
and helps you work out additional issues besides coding such as adding API documentation and extending
online-manuals.
</para>
<sect2 id="c1s2s1">
<title>In the next chapter</title>
<para>
We'll take a look at the Qt and KDE libraries, showing basic concepts and why things are the way they are.
Also, we will discuss how to create the tutorial applications provided with the Qt toolkit by using
kdevelop;, so beginners can already see first results with a few steps, and thereby will learn how to make
use of some of &kdevelop;'s best features.
</para>
</sect2>
<sect2 id="c1s2s2">
<title>In the following chapters</title>
<para>
You will learn how to:
<itemizedlist>
<listitem><para>create an application with the KAppWizard</para></listitem>
<listitem><para>What the project skeleton already provides</para></listitem>
<listitem><para>What the code already create means</para></listitem>
<listitem><para>How to create your own views</para></listitem>
<listitem><para>How to extend your application's functionality by dialog, menu bars, and toolbars</para></listitem>
<listitem><para>How to make your application user friendly by providing help functions</para></listitem>
<listitem><para>How to write online documentation</para></listitem>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="c1s3">
<title>Additional Information</title>
<para>
Additional information about Qt/KDE programming is available by various sources:
<itemizedlist>
<listitem><para>Programming with Qt by Matthias Kalle Dalheimer</para></listitem>
<listitem><para><ulink url="www.kdevelop.org">The User Manual to KDevelop, provided with the KDevelop IDE</ulink></para></listitem>
<listitem><para><ulink url="doc.trolltech.com">The Online Reference to the Qt library</ulink></para></listitem>
<listitem><para><ulink url="developer.kde.org">The KDE Developer web site</ulink></para></listitem>
</itemizedlist>
</para>
<para>
Additionally, you should look for help by subscribing to the various mailing lists, whose addresses
are available on the mentioned web sites, and on the Usenet newsgroups dedicated to users of KDE and
Unix Systems as well as about the C and C++ programming language.
</para>
<para>
For obtaining help about the KDevelop IDE, you should send requests to our mailinglist at
<email>kdevelop@kdevelop.org</email>. Mind that the KDevelop team is dedicated to provide the means to enable you to
program applications and therefore is not intended as a technical support team in cases where the
applications you're developing don't work due to implementation errors or misconfigurations of your
operating system. By this, we ask all users to take advantage of the mailinglist in any case you're running
into problems with the use of the IDE itself, as well as for bug reports and suggestions for improving the
functionality of the development environment.
</para>
</sect1>
</chapter>
<chapter id="chapter2">
<title>The KDE and Qt Libraries</title>
<para>
The Norwegian company TrollTech (<ulink url="http://www.trolltech.com">http://www.trolltech.com</ulink>)
provides a so-called GUI toolkit, named Qt. GUI means "Graphical User Interface", and therefore, Qt-based
applications represent themselves with buttons, windows etc, allowing user input by visualizing the functions
an application provides. Such a toolkit is needed for developing graphical applications that run on the X-Window
interface on Unix Systems, because X does not contain a pre-defined user interface itself. Although other
toolkits are also available to create User Interfaces, Qt offers some technical advantages that make
application design very easy. Additionally, the Qt toolkit is also available for Microsoft Windows systems,
which allows developers to provide their applications for both platforms.
</para>
<para>
The KDE Team (<ulink url="http://www.kde.org">http://www.kde.org</ulink>) joined together with the goal
to make using Unix Systems more friendly, and decided to use the Qt toolkit for the development of a window
manager on X-Windows, plus a variety of tools included with the KDE packages. The K Desktop Environment
therefore contains the window manager kwm, the file manager kfm and the launch panel kpanel as the main
components plus a variety of first-class utilities and applications. After KDE was out, a lot of developers
turned their eyes towards the new environment and what it has to offer them. The KDE libraries are providing
essential methods and classes that make all applications designed with them look similar and consistent,
so the user has the great advantage that he only has to get accustomed with an application's specific
usage, not with handling dialogs or buttons. Also, KDE programs integrate themselves into the desktop and
are able to interact with the file manager via drag'n drop, offer session management and many more, if all
features offered by the KDE libraries are used. Both, the Qt toolkit and the KDE libraries, are implemented
in the C++ programming language; therefore applications that make use of these libraries are also mostly
written in C++. In the following chapter, we'll make a short trip through the libraries to see what already
is provided and how Qt and KDE applications are created in general.
</para>
<para>
Both, the Qt toolkit and the KDE libraries, are implemented in the C++ programming language;
therefore applications that make use of these libraries are also mostly written in C++. In the following
chapter, we'll make a short trip through the libraries to see what already is provided and how Qt and KDE
applications are created in general.
</para>
<sect1 id="c2s1">
<title>The Qt GUI Toolkit</title>
<para>
As said, the Qt library is a toolkit that offers graphical elements that are used for creating GUI
applications and are needed for X-Window programming. Additionally, the toolkit offers:
<itemizedlist>
<listitem><para>A complete set of classes and methods ready to use even for non-graphical programming issues</para></listitem>
<listitem><para>A good solution towards user interaction by virtual methods and the signal/slot mechanism</para></listitem>
<listitem><para>A set of predefined GUI-elements, called "widgets", that can be used easily for creating the visible elements</para></listitem>
<listitem><para>Additional completely pre-defined dialogs that are often used in applications such as progress and file dialogs</para></listitem>
</itemizedlist>
</para>
<para>
Therefore knowing the Qt classes is very essential, even if you only want to program KDE-applications.
To have an impression on the basic concept how GUI-applications are constructed and compiled, we'll first
have a look at a sample Qt-only program; then we'll extend it to a KDE program.
</para>
<sect2 id="c2s1s1">
<title>The first Qt Application</title>
<para>
As usual, programs in C++ have to contain a <function>main()</function> function, which is the starting point for application
execution. As we want them to be graphically visible in windows and offering user interaction,
we first have to know, how they can show themselves to the user. For an example, we'll have a look
at the first tutorial included with the Qt Online Reference Documentation and explain the basic execution
steps; also why and how the application window appears:
<programlisting>
#include <qapplication.h>
#include <qpushbutton.h>
int main( int argc, char **argv )
{
QApplication a( argc, argv );
QPushButton hello( "Hello world!", 0 );
hello.resize( 100, 30 );
a.setMainWidget( &hello );
hello.show();
return a.exec();
}
</programlisting>
</para>
<para>
This application merely paints a window containing a button with "Hello world" as its text. As for
all Qt-based applications, you first have to create an instance of the class <classname>QApplication</classname>, represented by
variable a.
</para>
<para>
Next, the program creates an instance of the class <classname>QPushButton</classname> called hello, this will be the button.
The constructor of hello gets a string as a parameter, which is the contents of the widget visible as
the buttons text.
</para>
<para>
Then the <methodname>resize()</methodname> method is called on the hello button. This changes the default size a widget
(which is in this case the <classname>QPushButton</classname>) has when created to the length of 100 pixels and the height of
30 pixels. Finally, the setMainWidget() method is called for a and the show() method for hello. The
QApplication is finally executed by <methodname>a.exec()</methodname>, enters the main event loop and waits until it has to return
an integer value to the overlaying Operating System signaling that the application is exited.
</para>
</sect2>
<sect2 id="c2s1s2">
<title>The Reference Documentation for Qt</title>
<para>
Now, let's have a quick look at the reference documentation of the Qt library. To do this, start
&kdevelop; and select "Qt" from the tree in the Documentation tab. The documentation browser opens
and shows you the start page of the Qt reference. This will be your first place to get information
about Qt, it's classes and the available functions they provide. Also, the above program is the first
that is included in the tutorials section. To get to the classes we want to have a look at,
<classname>QApplication</classname> and <classname>QPushButton</classname>, select "Alphabetical Class List"
and search for the according names. Follow either of them to have a look at the class documentation.
</para>
<para>
Alternatively, you can use the online documentation from Trolltech's <ulink url="doc.trolltech.com">Qt Documentation</ulink>
</para>
<para>
For <classname>QApplication</classname>, you will see the constructor and all other methods that this
class provides. If you follow a link, you will get more information about the usage and meaning of the
methods, which is very useful when you sometimes can't detect the correct use or want to have an example.
This also counts for the KDE library documentation, which uses a similar documentation type; therefore
this is almost all you have to know about using the class-references with the documentation browser.
</para>
<sect3 id="c2s1s2s1">
<title>Interpretation of the Sample</title>
<para>
Starting with <classname>QApplication</classname>, you will find all the methods used in our first example:
<itemizedlist>
<listitem><para>the constructor <methodname>QApplication()</methodname></para></listitem>
<listitem><para>the <methodname>setMainWidget()</methodname> method</para></listitem>
<listitem><para>the <methodname>exec()</methodname> method</para></listitem>
</itemizedlist>
</para>
<para>
The interpretation why we use these methods is very simple:
<orderedlist>
<listitem><para>Create an instance of the class <classname>QApplication</classname> with the constructor,
so we can make use of the GUI elements provided by Qt</para></listitem>
<listitem><para>Create a widget which will be the contents of our program window</para></listitem>
<listitem><para>Set the widget as the main widget for a</para></listitem>
<listitem><para>Execute the a instance of <classname>QApplication</classname></para></listitem>
</orderedlist>
</para>
<para>
The second object of our program is the pushbutton, an instance of the class <classname>QPushButton</classname>.
From the two constructors given to create an instance, we used the second: this accepts a text,
which is the label contents of the button; here, it is the string "Hello world!". Then we called the
<methodname>resize()</methodname> method to change the size of the button according to it's contents -
the button has to be larger to make the string completely visible.
</para>
<para>
But what about the <methodname>show()</methodname> method? Now, you see that like most other widgets,
<classname>QPushButton</classname> is based on a single inheritance, the documentation says, Inherits
<classname>QButton</classname>. Follow the link to the <classname>QButton</classname> class.
This shows you a lot of other widgets that are inherited by <classname>QPushButton</classname>,
which we'll use later to explain the signal/slot mechanism. Anyway, the <methodname>show()</methodname>
method is not listed, therefore, it must be a method that is provided by inheritance as well. The class
that <classname>QButton</classname> inherits is <classname>QWidget</classname>. Just follow the link
again, and you will see a whole bunch of methods that the QWidget class provides; including
the <methodname>show()</methodname> method. Now we understand what was done in the sample with the button:
<orderedlist>
<listitem><para>Create an instance of <classname>QPushButton</classname>, use the second constructor to set the button text</para></listitem>
<listitem><para>Resize the widget to its contents</para></listitem>
<listitem><para>Set the widget as the main widget of the <classname>QApplication</classname> instance a</para></listitem>
<listitem><para>Tell the widget to display itself on the screen by calling <methodname>show()</methodname>, an inherited method from <classname>QWidget</classname></para></listitem>
</orderedlist>
</para>
<para>
After calling the <methodname>exec()</methodname> method, the application is visible to the user,
showing a window with the button showing "Hello world!". Note: GUI programs behave somewhat differently
than procedural applications. The main thing here is that the application enters a so-called
"main event loop". This means that the program has to wait for user actions and then react to it, also
that for a Qt application, the program has to be in the main event loop to start the event handling.
The next section tells you in short what this means to the programmer and what Qt offers to process
user events.
</para>
<note><para>
For already advanced users: The button has no parent declared in the constructor, therefore it
is a top-level widget alone and runs in a local event loop which doesn't need to wait for the main
event loop. See the QWidget class documentation and The KDE Library Reference Guide</para>
</note>
</sect3>
</sect2>
<sect2 id="c2s1s3">
<title>User Interaction</title>
<para>
After reading the last sections, you should already know:
<itemizedlist>
<listitem><para>What the Qt-library provides in terms of GUI applications</para></listitem>
<listitem><para>How a program using Qt is created and</para></listitem>
<listitem><para>Where and how to find information about classes that you want to use with the documentation browser</para></listitem>
</itemizedlist>
</para>
<para>
Now we'll turn to give the application "life" by processing user events. Generally, the user has two ways
to interact with a program: the mouse and the keyboard. For both ways, a graphical user interface has to
provide methods that detect actions and methods that do something as a reaction to these actions.
</para>
<para>
The Window system therefore sends all interaction events to the according application. The
<classname>QApplication</classname> then sends them to the active window as a <classname>QEvent</classname>
and the widgets themselves have to decide what to do with them. A widget receives the event and processes
<methodname>QWidget::event(QEvent*)</methodname>, which then decides which event has been executed
and how to react; <methodname>event()</methodname> is therefore the main event handler. Then,
the <methodname>event()</methodname> method passes the event to so-called event filters
that determine what happened and what to do with the event. If no filter signs responsible for the
event, the specialized event handlers are called. Thereby we can decide between:
<itemizedlist>
<listitem><para>
Keyboard events -- TAB and Shift-TAB keys:</para>
<itemizedlist>
<listitem><para><methodname>virtual void focusInEvent(QFocusEvent *)</methodname></para></listitem>
<listitem><para><methodname>virtual void focusOutEvent(QFocusEvent *)</methodname></para></listitem>
</itemizedlist>
</listitem>
<listitem><para>
All other keyboard input:</para>
<itemizedlist>
<listitem><para><methodname>virtual void keyPressEvent(QKeyEvent *)</methodname></para></listitem>
<listitem><para><methodname>virtual void keyReleaseEvent(QKeyEvent *)</methodname></para></listitem>
</itemizedlist>
</listitem>
<listitem><para>
Mouse movements:</para>
<itemizedlist>
<listitem><para><methodname>virtual void mouseMoveEvent(QMouseEvent *)</methodname></para></listitem>
<listitem><para><methodname>virtual void enterEvent(QEvent *)</methodname></para></listitem>
<listitem><para><methodname>virtual void leaveEvent(QEvent *)</methodname></para></listitem>
</itemizedlist>
</listitem>
<listitem><para>
Mouse button actions</para>
<itemizedlist>
<listitem><para><methodname>virtual void mousePressEvent(QMouseEvent *)</methodname></para></listitem>
<listitem><para><methodname>virtual void mouseReleaseEvent(QMouseEvent *)</methodname></para></listitem>
<listitem><para><methodname>virtual void mouseDoubleClickEvent(QMouseEvent *)</methodname></para></listitem>
</itemizedlist>
</listitem>
<listitem><para>
Window events containing the widget</para>
<itemizedlist>
<listitem><para><methodname>virtual void moveEvent(QMoveEvent *)</methodname></para></listitem>
<listitem><para><methodname>virtual void resizeEvent(QResizeEvent *)</methodname></para></listitem>
<listitem><para><methodname>virtual void closeEvent(QCloseEvent *)</methodname></para></listitem>
</itemizedlist>
</listitem>
</itemizedlist>
</para>
<para>
Note that all event functions are virtual and protected; therefore you can re-implement the events
that you need in your own widgets and specify how your widget has to react. <classname>QWidget</classname>
also contains some other virtual methods that can be useful in your programs; anyway, it is sufficient
to know about <classname>QWidget</classname> very well.
</para>
</sect2>
<sect2 id="c1s2s4">
<title>Object Interaction by Signals and Slots</title>
<para>
Now we're coming to the most obvious advantages of the Qt toolkit: the signal/slot mechanism.
This offers a very handy and useful solution to object interaction, which usually is solved by
callback functions for X-Window toolkits. As this communication requires a strict programming and
sometimes makes user interface creation very difficult (as referred by the Qt documentation and explained
in Programming with Qt by K.Dalheimer), Troll Tech invented a new system where objects can emit signals
that can be connected to methods declared as slots. For the C++ part of the programmer, he only has to know
some things about this mechanism:
<itemizedlist>
<listitem><para>
the class declaration of a class using signals/slots has to contain the Q_OBJECT macro at the beginning
(without a semicolon); and have to be derved from the <classname>QObject</classname> class
</para></listitem>
<listitem><para>
a signal can be emitted by the keyword emit, e.g. emit signal(parameters); from within any member function
of a class that allows signals/slots
</para></listitem>
<listitem><para>
all signals used by the classes that are not inherited have to be added to the class declaration by a
signals section
</para></listitem>
<listitem><para>
all methods that can be connected with a signal are declared in sections with the additional keyword slot,
e.g. public slots: within the class declaration
</para></listitem>
<listitem><para>
the meta-object compiler moc has to run over the header file to expand the macros and to produce the
implementation (which is not necessary to know). The output files of moc are compiled also by the C++ compiler.
</para></listitem>
</itemizedlist>
</para>
<para>
Another way to use signals without deriving from <classname>QObject</classname> is to use the
<classname>QSignal</classname> class- see the reference documentation for more information and example
usage. In the following, we assume you're deriving from <classname>QObject</classname>.
</para>
<para>
This way, your class is able to send signals anywhere and to provide slots that signals can connect
to. By using the signals, you don't have to care about who's receiving it- you just have to emit the
signal and whatever slot you want to connect to it can react to the emission. Also the slots can be used
as normal methods during implementation.
</para>
<para>
Now, to connect a signal to a slot, you have to use the <methodname>connect()</methodname> methods that
are provided by <classname>QObject</classname> or, where available, special methods that objects provide
to set the connection for a certain signal.
</para>
<sect3 id="c1s2s4s1">
<title>Sample Usage</title>
<para>
To explain the way how to set up object-interaction, we'll take our first example again and extend it by a
simple connection:
<programlisting>
#include <qapplication.h>
#include <qpushbutton.h>
int main( int argc, char **argv )
{
QApplication a( argc, argv );
QPushButton hello( "Hello world!" , 0);
hello.resize( 100, 30 );
a.setMainWidget( &hello );
QObject::connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ));
hello.show();
return a.exec();
}
</programlisting>
</para>
<para>
You see, the only addition to give the button more interaction is to use a <methodname>connect()
</methodname> method: <methodname>connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ))</methodname>;
is all you have to add. What is the meaning now? The class declaration of QObject says about the
<methodname>connect()</methodname> method:
</para>
<para><methodname>
bool connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * member )
</methodname></para>
<para>
This means you have to specify a <classname>QObject</classname> instance pointer that is the sender
of the signal, meaning that it can emit this signal as first parameter; then you have to specify the signal
that you want to connect to. The last two parameters are the receiver object that provides a slot, followed
by the member function which actually is the slot that will be executed on signal emission.
</para>
<para>
By using signals and slots, your program's objects can interact with each other easily without explicitly
depending on the type of the receiver object. You will learn more about using this mechanism for productive
usage later in this handbook. More information about the Signals/Slot mechanism can also be found in
<ulink url="developer.kde.org/documentation/library/libraryref.html">The KDE Library Reference Guide</ulink>
and the <ulink url="doc.trolltech.com">Qt online reference</ulink>.
</para>
</sect3>
</sect2>
</sect1>
<sect1 id="c2s3">
<title>What KDE provides</title>
<sect2 id="c2s3s1">
<title>The KDE 3.x libraries</title>
<para>
The main KDE libraries you'll be using for creating your own KDE applications are:
<itemizedlist>
<listitem><para>
the kdecore library, containing all classes that are non-visible elements to provide application functionality
</para></listitem>
<listitem><para>
the kdeui library, containing user interface elements like menubars, toolbars, etc.
</para></listitem>
<listitem><para>
the kfile library, containing the file selection dialogs
</para></listitem>
</itemizedlist>
</para>
<para>
Additionally, for specific solutions KDE offers the following libraries:
<itemizedlist>
<listitem><para>
the kdefx library, containing pixmaps, image effects the KStyle extension to QStyle
</para></listitem>
<listitem><para>
the khtml library, containing KDE's html component
</para></listitem>
<listitem><para>
the kjs library, containing KDE's Javascript support
</para></listitem>
<listitem><para>
the kio library, containing low level access to network files
</para></listitem>
<listitem><para>
the kparts library, containing support for re-usable embeddable extendable applications
</para></listitem>
</itemizedlist>
</para>
<para>
Next we'll have a look at what is needed to turn out first Qt Application into a KDE one.
</para>
</sect2>
<sect2 id="c2s3s2">
<title>Example KDE Application</title>
<para>
In the following, you will see that writing a KDE application is not much more difficult than a
Qt application. For the use of KDE's features, you just have to use some other classes, and you're almost
done. As an example, we'll discuss the changed version of the Qt example from above:
<programlisting>
#include <kapplication.h>
#include <qpushbutton.h>
int main( int argc, char **argv )
{
KApplication a( argc, argv );
QPushButton hello( "Hello world!", 0 );
hello.resize( 100, 30 );
a.setTopWidget( &hello );
QObject::connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ));
hello.show();
return a.exec();
}
</programlisting>
</para>
<para>
You see that first we have changed from <classname>QApplication</classname> to <classname>KApplication
</classname>. Further, we had to change the previously used <methodname>setMainWidget()</methodname> method
to <methodname>setTopWidget</methodname>, which <classname>KApplication</classname> uses to set the main
widget. That's it! Your first KDE application is ready - you only have to tell the compiler the KDE
include path and the linker to link in the kdecore library with -lkdecore.
</para>
<para>
As you now know what at least the <function>main()</function> function provides generally and how an
application gets visible and allows user and object interaction, we'll go on with the next chapter,
where our first application is made with &kdevelop;. There you can also test everything which was
mentioned before and see the effects.
</para>
<para>
What you should have looked into additionally until now is the reference documentation for Qt,
especially the <classname>QApplication</classname>, <classname>QWidget</classname> and <classname>QObject
</classname> class and the kdecore library documentation for the <classname>KApplication</classname> class.
The <ulink url="developer.kde.org/documentation/library/libraryref.html">KDE Library Reference handbook</ulink>
also covers a complete description about the invocation of the <classname>QApplication</classname> and
<classname>KApplication</classname> constructors including command-line argument processing.
</para>
</sect2>
</sect1>
</chapter>
<chapter id="chapter3">
<title>Creating New Applications</title>
<sect1 id="c3s1">
<title>The Application Wizard</title>
<para>
&kdevelop;'s Application Wizard is intended to let you start working on new project with &kdevelop;. Therefore
all of your projects are first created by the wizard, and then you can start building them and extend what is
already provided by the source skeleton. You can choose from several project types according to your project goals:
<itemizedlist>
<listitem><para>
KDE Application Framework: includes source code for a complete frame structre of a standard KDE application
</para></listitem>
<listitem><para>
QMake Project: Creates an application framework based around Trolltech's qmake configuration system
</para></listitem>
<listitem><para>
Simple hello world program: Creates a C++ terminal based program with no GUI support
</para></listitem>
<listitem><para>
A multitude of other program skeletons
</para></listitem>
</itemizedlist>
</para>
<para>
In this chapter we'll see how the Application Wizard can be invoked and what has to be done to generate
a KDE application project. This will also be the initial step of our coverage, where we will create the
initial version of a sample project. For all other project types the steps are usualyl the same, but you
may not have as many options available.
</para>
</sect1>
<sect1 id="c3s2">
<title>Invoking the Application Wizard and Project Generation</title>
<sect2 id="c3s2s1">
<title>Starting the Application Wizard and the First Page</title>
<para>
To start with your KDE application, open &kdevelop;. From the Project menu, selection New Project. The
Application Wizard starts, and you'll see the selection tree on the first page containing available project
types that can be created. Choose the C++ subtree, then KDE, then Application Framework.
</para>
<para>
For our sample project, we are going to create the application KScribble. Enter this as the application
name, and change any other information at the bottom of this screen that may need it. Then, select Next.
<screenshot><mediaobject><imageobject>
<imagedata fileref="appwizard.png" format="PNG"/>
</imageobject><textobject><phrase>Application Wizard</phrase></textobject>
</mediaobject></screenshot>
</para>
</sect2>
<sect2 id="c3s2s2">
<title>Version control information</title>
<para>
On this screen you have the ability to decide if your project will use a version control system like
CVS. For our sample project we will not use source control, so make sure the selection box reads None
and select Next.
</para>
</sect2>
<sect2 id="c3s2s3">
<title>Header and Source Templates</title>
<para>
The next two pages show example headers that will go at the top of each of the header and source files that
you create using &kdevelop;. For now, just leave these as the default, and select Next, then Finish. If the
Finish button is not activated, you haven't set all of the options correct. Use the Back button to return
to earlier menus and correct any mistakes.
</para>
</sect2>
<sect2 id="c3s2s4">
<title>Finishing Up</title>
<para>
Upon completion, the Application Wizard should close and the messages window should popup displaying
information about the tasks that &kdevelop; is currently doing. At the end of all of the tasks, you
should see **** Success *****. This means the application framework was successfully loaded.
</para>
</sect2>
</sect1>
<sect1 id="c3s3">
<title>The First Build</title>
<para>
After our project is generated, we'll first make a trip through the source code to get a general understanding
of how the application framework looks. This won't only help us get started, but we'll know where to change
what in later steps.
</para>
<para>
This chapter makes the assumption that you understand the basic navigation of &kdevelop;. Consult the
KDevelop User Manual for information if you need it.
</para>
<para>
The Automake manager shows the project files as follows:
<screenshot><mediaobject><imageobject>
<imagedata fileref="kscribblefiles.png" format="PNG"/>
</imageobject><textobject><phrase>Files in our project</phrase></textobject>
</mediaobject></screenshot>
</para>
<para>
Before diving into the sources, we'll let &kdevelop; build an run our new application. To do this, select
Build Project from the Build menu, or press F8. The output window opens and displays output messages during
the compilation phase.
<programlisting>
1 cd /home/caleb/kscribble && WANT_AUTOCONF_2_5=1 WANT_AUTOMAKE_1_6=1 gmake k
2 gmake all-recursive
3 gmake[1]: Entering directory `/home/caleb/kscribble'
4 Making all in doc
5 gmake[2]: Entering directory `/home/caleb/kscribble/doc'
6 Making all in .
7 gmake[3]: Entering directory `/home/caleb/kscribble/doc'
8 gmake[3]: Nothing to be done for `all-am'.
9 gmake[3]: Leaving directory `/home/caleb/kscribble/doc'
10 Making all in en
11 gmake[3]: Entering directory `/home/caleb/kscribble/doc/en'
12 /usr/local/trinity/bin/meinproc --check --cache index.cache.bz2 /home/caleb/kscribble/doc/en/index.docbook
13 gmake[3]: Leaving directory `/home/caleb/kscribble/doc/en'
14 gmake[2]: Leaving directory `/home/caleb/kscribble/doc'
15 Making all in po
16 gmake[2]: Entering directory `/home/caleb/kscribble/po'
17 gmake[2]: Nothing to be done for `all'.
18 gmake[2]: Leaving directory `/home/caleb/kscribble/po'
19 Making all in src
20 gmake[2]: Entering directory `/home/caleb/kscribble/src'
21 source='main.cpp' object='main.o' libtool=no \
22 depfile='.deps/main.Po' tmpdepfile='.deps/main.TPo' \
23 depmode=gcc3 /bin/sh /home/caleb/kscribble/admin/depcomp \
24 g++ -DHAVE_CONFIG_H -I. -I/home/caleb/kscribble/src -I.. -I/usr/local/trinity/include
-I/usr/lib/qt/include -I/usr/X11R6/include -DQT_THREAD_SUPPORT -D_REENTRANT -Wnon-virtual-dtor
-Wno-long-long -Wundef -Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings
-ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new
-c -o main.o `test -f 'main.cpp' || echo '/home/caleb/kscribble/src/'`main.cpp
25 /usr/lib/qt/bin/moc /home/caleb/kscribble/src/kscribble.h -o kscribble.moc
26 source='kscribble.cpp' object='kscribble.o' libtool=no \
27 depfile='.deps/kscribble.Po' tmpdepfile='.deps/kscribble.TPo' \
28 depmode=gcc3 /bin/sh /home/caleb/kscribble/admin/depcomp \
29 g++ -DHAVE_CONFIG_H -I. -I/home/caleb/kscribble/src -I.. -I/usr/local/trinity/include
-I/usr/lib/qt/include -I/usr/X11R6/include -DQT_THREAD_SUPPORT -D_REENTRANT -Wnon-virtual-dtor
-Wno-long-long -Wundef -Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings
-ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new
-c -o kscribble.o `test -f 'kscribble.cpp' || echo '/home/caleb/kscribble/src/'`kscribble.cpp
30 kscribble.cpp: In member function `void KScribble::setupActions()'
31 kscribble.cpp:107: warning: unused variable `KAction*custom'
32 /usr/lib/qt/bin/moc /home/caleb/kscribble/src/kscribbleview.h -o kscribbleview.moc
33 source='kscribbleview.cpp' object='kscribbleview.o' libtool=no \
34 depfile='.deps/kscribbleview.Po' tmpdepfile='.deps/kscribbleview.TPo' \
35 depmode=gcc3 /bin/sh /home/caleb/kscribble/admin/depcomp \
36 g++ -DHAVE_CONFIG_H -I. -I/home/caleb/kscribble/src -I.. -I/usr/local/trinity/include
-I/usr/lib/qt/include -I/usr/X11R6/include -DQT_THREAD_SUPPORT -D_REENTRANT -Wnon-virtual-dtor
-Wno-long-long -Wundef -Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -ansi
-D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new -c
-o kscribbleview.o `test -f 'kscribbleview.cpp' || echo '/home/caleb/kscribble/src/'`kscribbleview.cpp
37 kscribbleview.cpp: In member function `void KScribbleView::print(QPainter*,
38 int, int)':
39 kscribbleview.cpp:79: warning: unused parameter `QPainter*p'
40 kscribbleview.cpp:79: warning: unused parameter `int height'
41 kscribbleview.cpp:79: warning: unused parameter `int width'
42 /usr/lib/qt/bin/moc /home/caleb/kscribble/src/pref.h -o pref.moc
43 source='pref.cpp' object='pref.o' libtool=no \
44 depfile='.deps/pref.Po' tmpdepfile='.deps/pref.TPo' \
45 depmode=gcc3 /bin/sh /home/caleb/kscribble/admin/depcomp \
46 g++ -DHAVE_CONFIG_H -I. -I/home/caleb/kscribble/src -I.. -I/usr/local/trinity/include
-I/usr/lib/qt/include -I/usr/X11R6/include -DQT_THREAD_SUPPORT -D_REENTRANT -Wnon-virtual-dtor
-Wno-long-long -Wundef -Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings
-ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new
-c -o pref.o `test -f 'pref.cpp' || echo '/home/caleb/kscribble/src/'`pref.cpp
47 /usr/local/trinity/bin/dcopidl /home/caleb/kscribble/src/kscribbleiface.h > kscribbleiface.kidl ||
( rm -f kscribbleiface.kidl ; /bin/false )
48 /usr/local/trinity/bin/dcopidl2cpp --c++-suffix cpp --no-signals --no-stub kscribbleiface.kidl
49 source='kscribbleiface_skel.cpp' object='kscribbleiface_skel.o' libtool=no \
50 depfile='.deps/kscribbleiface_skel.Po' tmpdepfile='.deps/kscribbleiface_skel.TPo' \
51 depmode=gcc3 /bin/sh /home/caleb/kscribble/admin/depcomp \
52 g++ -DHAVE_CONFIG_H -I. -I/home/caleb/kscribble/src -I.. -I/usr/local/trinity/include
-I/usr/lib/qt/include -I/usr/X11R6/include -DQT_THREAD_SUPPORT -D_REENTRANT -Wnon-virtual-dtor
-Wno-long-long -Wundef -Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings
-ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new
-c -o kscribbleiface_skel.o `test -f 'kscribbleiface_skel.cpp' ||
echo '/home/caleb/kscribble/src/'`kscribbleiface_skel.cpp
53 /bin/sh ../libtool --silent --mode=link --tag=CXX g++ -Wnon-virtual-dtor -Wno-long-long -Wundef -Wall
-pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -ansi -D_XOPEN_SOURCE=500
-D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new -o kscribble -R
/usr/local/trinity/lib -R /usr/lib/qt/lib -R /usr/X11R6/lib -L/usr/X11R6/lib -L/usr/lib/qt/lib
-L/usr/local/trinity/lib main.o kscribble.o kscribbleview.o pref.o kscribbleiface_skel.o -lkio
54 source='kscribble_client.cpp' object='kscribble_client.o' libtool=no \
55 depfile='.deps/kscribble_client.Po' tmpdepfile='.deps/kscribble_client.TPo' \
56 depmode=gcc3 /bin/sh /home/caleb/kscribble/admin/depcomp \
57 g++ -DHAVE_CONFIG_H -I. -I/home/caleb/kscribble/src -I.. -I/usr/local/trinity/include
-I/usr/lib/qt/include -I/usr/X11R6/include -DQT_THREAD_SUPPORT -D_REENTRANT -Wnon-virtual-dtor
-Wno-long-long -Wundef -Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings
-ansi -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new
-c -o kscribble_client.o `test -f 'kscribble_client.cpp' || echo
'/home/caleb/kscribble/src/'`kscribble_client.cpp
58 /bin/sh ../libtool --silent --mode=link --tag=CXX g++ -Wnon-virtual-dtor -Wno-long-long -Wundef
-Wall -pedantic -W -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -ansi -D_XOPEN_SOURCE=500
-D_BSD_SOURCE -Wcast-align -Wconversion -O2 -fno-exceptions -fno-check-new -o kscribble_client -R
/usr/local/trinity/lib -R /usr/lib/qt/lib -R /usr/X11R6/lib -L/usr/X11R6/lib -L/usr/lib/qt/lib
-L/usr/local/trinity/lib kscribble_client.o -lkdecore
59 gmake[2]: Leaving directory `/home/caleb/kscribble/src'
60 gmake[2]: Entering directory `/home/caleb/kscribble'
61 gmake[2]: Nothing to be done for `all-am'.
62 gmake[2]: Leaving directory `/home/caleb/kscribble'
63 gmake[1]: Leaving directory `/home/caleb/kscribble'
64 *** Success ***
</programlisting>
</para>
<para>
As you can see, we've put line numbers in front of each line which won't appear on your output but it makes it
easier to describe what is happening during the build. First of all, gmake works recursively. This means
that it starts from the directory it is invoked and goes into the subdirectories first, one at a time, then
returns to the directory it was started, processes it, then finishes.
</para>
<para>
Our first line of interest is 24. Notice on this line that g++, which is our C++ compiler, gets called by make
to compile the first source code file in our project - in this case main.cpp. Many extra command line options
are also being used with the g++ compiler; some of which are defaults and some of which can be configured
via &kdevelop;.
</para>
<para>
Before the next file (kscribble.cpp, line 29) is compiled, the moc (meta object compiler) is first
invoked on kscribble.h (line 25). This is because KScribble classes use signals/slots, so the
Q_OBJECT macro must be expanded, and the moc does this for us. The resultant file, kscribble.moc, is
used by kscribble.cpp via an #include statement inside of the file.
</para>
</sect1>
<sect1 id="c3s4">
<title>The source skeleton</title>
<para>
To conceptualize how a KDE application works, we'll first have a very close look at the source
skeleton already provided by the Application Wizard. As we already saw, we're having a set of source
and header files that build the initial code for the application and make it ready-to-run. Therefore,
the easiest way to explain the code is to follow the implementation line by line as it is processed
during executing the program until it enters the main event loop and is ready to accept user input.
Then, we'll have a look at the functionality that enables user interaction and how certain things work.
This is probably the best way to explain the framework and, as it is similar to almost all KDE
applications, will enable you to read source codes from other projects as well; additionally, you will
know where to change what part of the code to make your applications behave the way they are designed for.
</para>
<sect2 id="c3s4s1">
<title>The main() function</title>
<para>
As the application begins its execution with entering the <function>main()</function> function,
this will be the start for our code examination. The <function>main()</function> function of
KScribble is implemented in the file main.cpp and can also be found using the Class Browser
by selecting the "Global Functions" folder.
<programlisting>
1 int main(int argc, char **argv)
2 {
3 KAboutData about("kscribble", I18N_NOOP("KScribble"), version, description,
4 KAboutData::License_GPL, "(C) 2002 Your Name", 0, 0, "you@you.com");
5 about.addAuthor( "Your Name", 0, "you@you.com" );
6 KCmdLineArgs::init(argc, argv, &about);
7 KCmdLineArgs::addCmdLineOptions(options);
8 KApplication app;
9
10 // register ourselves as a dcop client
11 app.dcopClient()->registerAs(app.name(), false);
12
13 // see if we are starting with session management
14 if (app.isRestored())
15 RESTORE(KScribble)
16 else
17 {
18 // no session.. just start up normally
19 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
20 if (args->count() == 0)
21 {
22 KScribble *widget = new KScribble;
23 widget->show();
24 }
25 else
26 {
27 int i = 0;
28 for (; i < args->count(); i++)
29 {
30 KScribble *widget = new KScribble;
31 widget->show();
32 widget->load(args->url(i));
33 }
34 }
35 args->clear();
36 }
37
38 return app.exec();
39 }
</programlisting>
</para>
<para>
Now, what happens first is the usual creation of a <classname>KApplication</classname> object, but we've
added some KDE methods that set program and author information for this application.
</para>
</sect2>
<sect2>
<title>User Application Start</title>
<para>... (not written yet)</para>
</sect2>
<sect2>
<title>The Constructor</title>
<para>
Let's have a look at the constructor and see how this instance is called
<programlisting>
1 KScribble::KScribble()
2 : KMainWindow( 0, "KScribble" ),
3 m_view(new KScribbleView(this)),
4 m_printer(0)
5 {
6 // accept dnd
7 setAcceptDrops(true);
8
9 // tell the KMainWindow that this is indeed the main widget
10 setCentralWidget(m_view);
11
12 // then, setup our actions
13 setupActions();
14
15 // and a status bar
16 statusBar()->show();
17
18 // allow the view to change the statusbar and caption
19 connect(m_view, SIGNAL(signalChangeStatusbar(const QString&)),
20 this, SLOT(changeStatusbar(const QString&)));
21 connect(m_view, SIGNAL(signalChangeCaption(const QString&)),
22 this, SLOT(changeCaption(const QString&)));
23
24 }
</programlisting>
</para>
<para>
Notice that <classname>KScribble</classname> inherits the <classname>KMainWindow</classname> class - a
commonly used base class for KDE applications. We initialize a class called <classname>KScribbleView</classname>
as our central widget, create a <classname>KStatusBar</classname> via the <methodname>statusBar()</methodname>
method (line 16), and connect some signals and slots together.
</para>
</sect2>
</sect1>
</chapter>
<chapter id="chapter4">
<title>Application View Design</title>
<sect1 id="c4s1">
<title>Introduction</title>
<para>
When developing an application with a graphical user interface, the main work takes place in
providing a so-called "view" for the application. A view generally is a widget that displays the data
of a document and provides methods to manipulate the document contents. This can be done by the user via
the events he emits by the keyboard or the mouse; more complex operations are often processed by toolbars
and menubars which interact with the view and the document. The statusbar then provides information about
the document, view or application status. As an example, we look at how an editor is constructed and where
we can find which part.
</para>
<para>
An editor generally is supposed to provide an interface to view and/or change the contents of a text
document for the user. If you start Kate, you see the visual interface as the following:
<itemizedlist>
<listitem><para>
The menubar: providing complex operations as well as opening, saving and closing files and
exiting the application.
</para></listitem>
<listitem><para>
The toolbar: offers icons which allow quicker access for most needed functions,
</para></listitem>
<listitem><para>
The statusbar: displays the status of the cursor position by the current row and column,
</para></listitem>
<listitem><para>
The view in the center of the window, displaying a document and offering a cursor connected to
the keyboard and the mouse to operate on the data.
</para></listitem>
</itemizedlist>
</para>
<para>
Now it's easy to understand that a view is the most unique part of the application and the design
of the view decides about the usability and acceptability of an application. This means that one of
the first steps in development is to determine the purpose of the application and what kind of view
design would match best to allow any user to work with the application with a minimum of work
learning how to handle the user interface.
</para>
<para>
For some purposes like text editing and displaying HTML files, views are provided by the Qt and KDE
libraries; we will discuss certain aspects of these high-level widgets in the next section.
But for most applications new widgets have to be designed and implemented. It is that what makes a
programmer also a designer and where his abilities on creativity are asked. Nevertheless, you should
watch for intuitivity first. Remember, a lot of users won't accept an application that isn't:
<itemizedlist>
<listitem><para>
graphically nice.
</para></listitem>
<listitem><para>
offering a lot of features
</para></listitem>
<listitem><para>
easy to handle
</para></listitem>
<listitem><para>
fast to learn how to use it
</para></listitem>
</itemizedlist>
</para>
<para>
Needless to say that stability is a major design goal. Nobody can prevent bugs, but a minimum can
be reached at least by clever design goals and wide use of object-oriented design. C++ makes programming
a joy if you know how to exploit it's capabilities- inheritance, information hiding and reusablitity of
already existing code.
</para>
<para>
When creating a KDE or Qt project, you always have to have a view that inherits QWidget, either by
direct inheritance or because the library widget you want to use inherits QWidget. Therefore, the
Application Wizard already constructed a view that is an instance of a class yourappView, which
inherits QWidget already.
</para>
<para>
This chapter therefore describes how to use library widgets for creating views of KDE or
Qt applications that are generated with &kdevelop;, then we look at the libraries and what kind of
views are already offered.
</para>
</sect1>
<sect1 id="c4s2">
<title>Using Library Views</title>
<para>
When your application design has been set up, you first should look for already existing code that
will make your life a lot easier. A part of this search is to look for a widget that can be used as
a view or at least as a part of it; either directly or by inheritance. The KDE and Qt libraries already
contain a set of widgets that can be used for this purpose. To use them, you have two options:
<orderedlist>
<listitem><para>
Remove the new view class and create an instance of a library widget; then set this as the view,
</para></listitem>
<listitem><para>
Change the inheritance of the provided view class to the class of the library widget to use.
</para></listitem>
</orderedlist>
</para>
<para>
In either way, it is important to know that if the application framework is currently not linked
against the library that contains the widget, the linker will fail. After you decided to use a
certain widget, look for the library to link to; then open "Project"->"Options" from the &kdevelop;
menubar. Switch to the "Linker Options" page and look for the checkmarks indicating the libraries
that are currently used. If the library of your view widget is already checked, you can leave the
project options untouched and start doing the necessary changes due to your choice. If not, and the
linker options offer to add the library by a check box, check it and press "OK" to leave the project
options dialog again. In any other case, add the library in the edit line below with the -l option.
For libraries that your application has to search for before preparing the Makefiles by the
configure script on the end-user machine, add the according search macro to the configure.in file
located at the root directory of your project and add the macro to the edit line. Mind that you have
to run "Build"->"Autoconf and automake" and "Build"->"Configure" before the Makefiles contain the
correct expansion for the library macro.
</para>
<para>
Also, if the include files for the library to add are not in the current include path
(which can be seen by the -I options in the output window on "Make"), you have to add the path to the
Project Options dialog -"Compiler Options" page with the -I option or the according automake macro at
the edit line for "Additional Options".
</para>
<sect2 id="c4s3s1">
<title>Qt Views</title>
<para>
Looking at the first page of the Qt online documentation, you will find a link to
"Widget Screenshots" where you can have a look at how the widgets Qt contains look like.
These are ready to use and can be combined together to form complex widgets to create application
views or dialogs. In the following, we'll discuss some of these which are very usable for creating
application views, but keep in mind that the KDE libraries sometimes contain other widgets for the
same purpose; those will be reviewed in the next section.
</para>
<para>
Here are a set of hints for what purpose you could use which Qt component:
<orderedlist>
<listitem><para>
If your view area isn't big enough to display all your data, the user must be enabled to scroll
over the document with bars on the left and bottom of the view. For this, Qt provides the class
<classname>QScrollView</classname>, which offers a scrollable child area. As explained, you could
inherit your own widget from <classname>QScrollView</classname> or use an instance to manage your
document's view widget.
</para></listitem>
<listitem><para>
to create a ScrollView yourself, inherit the View widget from <classname>QWidget</classname>
and add vertical and horizontal <classname>QScrollBars </classname>.
(This is done by KDE`s KHTMLView widget.)
</para></listitem>
<listitem><para>
For text processing, use <classname>QTextEdit</classname>. This class provides a complete
text editor widget that is already capable to cut, copy and paste text and is managed by a scrollview.
</para></listitem>
<listitem><para>
Use <classname>QTable</classname> to display data that is arranged in a table.
As <classname>QTable</classname> is managed by scrollbars as well, it offers a good solution for
table calculation applications.
</para></listitem>
<listitem><para>
To display two different widgets or two widget instances at the same time, use <classname>QSplitter
</classname>. This allows to tile views by horizontal or vertical dividers.
KMail is a good example what this would look like- the main view is separated by a
splitter vertically, the right window then is divided again horizontally.
</para></listitem>
<listitem><para>
<classname>QListView</classname> displays information in a list and tree.
This is useful for creating file trees or any other hierarchical information you want to interact with.
</para></listitem>
</orderedlist>
</para>
<para>
You see that Qt alone offers a whole set of widgets which are ready to use so you don't have to invent
new solutions if these match your needs. The sideffect when using standard widgets is that users already
know how to handle them and only have to concentrate on the displayed data.
</para>
</sect2>
<sect2 id="c4s3s2">
<title>KDE Views</title>
<para>
The KDE libraries were invented to make designing applications for the K Desktop Environment easier
and capable of more functionality than what Qt alone is offering. The kdeui library offers:
<orderedlist>
<listitem><para>
KListView: a more powerful version of <classname>QListView</classname>
</para></listitem>
<listitem><para>
KIconView: a graphical viewer of icon files
</para></listitem>
</orderedlist>
</para>
<para>
The khtml library, on the other hand, offers a complete HTML-interpreting widget that is ready to use.
It is scrollable already, so you don't even have to take care for that. A possible use could be to
integrate it as a preview widget for an HTML editor; used by applications such as Konqueror to display HTML files.
</para>
</sect2>
</sect1>
<sect1 id="c4s4">
<title>Creating your own Views</title>
<para>
Not yet written
</para>
</sect1>
</chapter>
<chapter id="chapter5">
<title>Configuring Menubars and Toolbars</title>
<sect1 id="c5s1">
<title>Introduction</title>
<para>
Menubars and toolbars are one of the most important parts of an application to provide methods to
work with a document structure. As a general rule, you should make all functions available by the menubar.
Those methods that should not be available at a current stage of the application process should be
disabled.
</para>
<para>
Further, an application can only contain one menubar, but several toolbars.
Toolbars on the other hand should contain only the most frequently used commands by pixmap
icons or provide quick access methods like combos to select values.
</para>
</sect1>
<sect1 id="c5s2">
<title>How does it work?</title>
<para>
Our application inherits the <classname>KMainWindow</classname> class, which automatically handles creating
a menu bar and tool bars for us. In the <methodname>KScribble::setupActions()</methodname> method there is
a call to <methodname>KMainWindow::createGUI()</methodname>. This method loads a resource file, in this
case kscribbleui.rc, to initialize menus at startup. Note that kscribbleui.rc is listed as one of the
project files in the Automake Manager. Opening that file up reveals this:
<programlisting>
1 <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
2 <kpartgui name="kscribble" version="1">
3 <MenuBar>
4 <Menu name="custom"><text>C&ustom</text>
5 <Action name="custom_action" />
6 </Menu>
7 </MenuBar>
8 </kpartgui>
</programlisting>
</para>
<para>
Explanation...
</para>
<para>
Another way to modify the contents of the menu and tool bars is to directly manipulate them through the
methods provided by their class. For example, the <methodname>menuBar()</methodname> method returns the
<classname>KMenuBar</classname> widget that the menubar for our program. Looking at the documentation for
<classname>KMenuBar</classname> and its inheritor class <classname>QMenuBar</classname>, you will find
a large number of <methodname>insertItem()</methodname> methods which allow you to add items to the
menu bar.
</para>
<para>
<classname>KMainWindow</classname>'s methods <methodname>statusBar()</methodname> and <methodname>
toolBar()</methodname> will also provide you with applicable widgets.
</para>
</sect1>
<sect1 id="c5s3">
<title>Keyboard Accelerator Configuration</title>
<para>
A very professional thing you should always add to your application are keyboard accelerators.
Those are mainly used by experienced users that want to work fast with their applications and
are willing to learn shortcuts. For this, the KDE libraries provide the class <classname>
KAction</classname>, which provides the keyboard accelerator keys and access to global configured
standard keyboard accelerators.
</para>
<para>
By default, frame applications generated by &kdevelop; only use standard keyboard accelerators
such as F1 for accessing online-help, Ctrl+N for New File etc.
</para>
<para>
If your application contains a lot of accelerators, you should make them configurable
by an Options-menu; either it could be combined with other application configuration in a QWidget
or stand alone. The KDE library already provides a <classname>KKeyChooser</classname>
for use in tab dialogs, whereas <classname>KKeyDialog</classname> provides a ready-to use
key-configuration dialog.
</para>
</sect1>
</chapter>
<!--
<chapter id="chapter6">
<title>Other Features</title>
</chapter>
<chapter id="chapter7">
<title>Printing Support</title>
</chapter>
-->
<chapter id="chapter8">
<title>Help Functions</title>
<sect1 id="c8s1">
<title>Introduction</title>
<para>
A very important part of the development process is to provide help functionality to the user
wherever possible. Most developers tend to delay this, but you should remember that a normal user
isn't necessarily a Unix expert. He may come from the the dark side of computer software usage offering
all sweets that a user may need to work himself into using an application even without ever touching the
manuals. Therefore, the KDE and Qt library provide all means usually considered making an application
professional in the eyes of the normal user by help functions that are ready to use.
Within the application, those are:</para>
<itemizedlist>
<listitem><para>Tool-Tips</para></listitem>
<listitem><para>Statusbar help</para></listitem>
<listitem><para>What's this...? buttons</para></listitem>
</itemizedlist>
<para>
Additionally, the application should provide means to access a HTML-based online manual directly
using the standard help key F1. This context based help system is provided automatically through the
<classname>KMainWindow</classname> class, though as the author you must provide the content.
</para>
<para>
As &kdevelop; also offers all types of help as well as the KDE framework generated by the
application wizard already contains support for this, this chapter will help you find out where
and how to add your help functionality. </para>
<para>
During the development of your application you should try to be consistent whatever you're doing;
therefore you should do the necessary steps directly while extending the code. This will prevent you
from diving into the code again and figuring out what your application does or what you intended by
certain parts of the code.
</para>
</sect1>
<sect1 id="c8s2">
<title>Tool-Tips</title>
<para>
A very easy means of providing help are tool-tips. Those are small help messages popping up while
the user moves the mouse over a widget that provides a tool-tip and disappears when the mouse moves away.
The most popular usage of tool-tips is made in toolbars where your tool-tips should be kept as small
as possible because toolbars can be configured to display their contents in various ways:
either displaying the button, button with text on the right, button with text below, text only.
This possibility should be made configurable by the user, but isn't a must-be. The text is shown
as a tool-tip anyway and a toolbar usually consists of buttons and other widgets like lineedits and
combo boxes. For a complete reference, see the <classname>KToolBar</classname> class reference located
in the kdeui library.
</para>
<para>
As an example, we have a look at the "New File" button in a generic application:
</para>
<para>
There, the part i18n("New File") provides a tool-tip message. It is enclosed by the i18n()
macro provided by kapp.h to translate the tool-tip towards the currently selected language.
</para>
<para>
Tool-tips can also be added to any custom widget by using the <classname>QToolTip</classname>
provided by Qt. An example of that would be:
</para>
</sect1>
<sect1 id="c8s3">
<title>Extending the Statusbar</title>
<para>
As the applications that inherit <classname>KMainWindow</classname> contain a statusbar as well,
it also offers a set of statusbar messages already for all menu and toolbar items. A statusbar
help message is a short message that extends the meaning of a tool-tip or can be seen as a replacement
for a tool-tip over menubar items and is (as the name suggests) displayed in the statusbar when the user
enters a menu and highlights the menu entry.
</para>
</sect1>
<sect1 id="c8s4">
<title>The <guibutton>What's This...?</guibutton> Button</title>
<para>
The <guibutton>What's This...?</guibutton> button provides help windows with the intention
that the user wants to get help about a certain widget within the working view or a toolbar item.
It is placed in the toolbar and gets activated once the user hits the button. The cursor changes
to an arrow cursor with a question mark like the button itself looks like. The the user can press on
a visible widget item and gets a help window. As an exercise, you could try this behavior with the
<guibutton>What's this...?</guibutton> button within &kdevelop;.
</para>
<para>
To add the What's This...? help to one of your widgets, use the static method
<methodname>QWhatsThis::add(QWidget *widget, const QString &text)</methodname>
</para>
</sect1>
</chapter>
<chapter id="chapter9">
<title>Documentation</title>
<sect1 id="c9s1">
<title>Introduction</title>
<para>
Due to the fact that projects often lack a complete set of user documentation,
all &kdevelop; projects contain a pre-build handbook that can be easily adapted;
therefore fulfiling another goal of KDE: providing enough online-help to support users that
are not familiar with an application. This chapter therefore introduces you on how to extend
the provided documentation template and what you have to do to make it available to the user.
</para>
</sect1>
<sect1 id="c9s2">
<title>User Documentation</title>
<para>
The documentation for your project lies in projectdir/doc/en, or perhaps another directory if English
isn't your native language. Therein lies a file, index.docbook, in which the documentation is stored.
The format for editing this file is explained on
<ulink url="http://i18n.kde.org/doc/markup/">KDE's documentation website</ulink>.
</para>
</sect1>
<sect1 id="c9s3">
<title>Programmer Documentation</title>
<para>
Another important part of the documentation is including a descriptive help for your class interfaces.
This will allow you and other programmers to use your classes by reading the HTML class documentation
that can be created with KDoc. &kdevelop; supports the use of KDoc completely by creating the
KDE-library documentation, also your application frameworks are already documented. To work yourself
into the provided code, it would be a good start to read the included documentation online.
The following describes what to do to get the API documentation, where &kdevelop; helps you add it
and what kind of special tags KDoc provides.
</para>
</sect1>
</chapter>
<chapter id="chapter10">
<title>Internationalization</title>
<sect1 id="c10s1">
<title>Introdction</title>
<para>
i18n is an internationalization system that is used to offer internationalized versions of an
application or project. The difficulty with writing applications is that they only support the
language they originally are composed with; visually this can be seen on labels, menu entries and the
like. The goal of the internationalization is to provide applications and library functions in the
language of the user; therefore enabling users that are not native speakers the original language to make
use of the provided functionality and feel more comfortable.
</para>
</sect1>
<!--
<sect1 id="c10s2">
<title>How KDE support Internationalization</title>
<para>
</para>
</sect1> -->
</chapter>
<!--
<chapter id="chapter11">
<title>Finding Errors</title>
</chapter>
<chapter id="chapter12">
<title>Licensing</title>
</chapter>
<chapter id="chapter13">
<title>References</title>
</chapter>
-->
<chapter id="credits">
<title>Credits</title>
<para>
(... to be written ...)
</para>
<!--CREDITS_FOR_TRANSLATORS-->
</chapter> <!-- credits -->
<appendix id="bibliography">
<title>Bibliography</title>
<bibliography>
<biblioentry>
<title><ulink url="info://make/Top">GNU Make Manual</ulink></title>
<authorgroup>
<author><firstname>Richard M.</firstname><surname>Stallman</surname></author>
<author><firstname>Roland</firstname><surname>McGrath</surname></author>
</authorgroup>
</biblioentry>
<biblioentry>
<title><ulink url="info://automake/Top">GNU Automake</ulink></title>
<authorgroup>
<author><firstname>David</firstname><surname>MacKenzie</surname></author>
<author><firstname>Tom</firstname><surname>Tromey</surname></author>
</authorgroup>
</biblioentry>
<biblioentry>
<title><ulink url="info://autoconf/Top">GNU Autoconf</ulink></title>
<authorgroup>
<author><firstname>David</firstname><surname>MacKenzie</surname></author>
<author><firstname>Ben</firstname><surname>Elliston</surname></author>
</authorgroup>
</biblioentry>
<biblioentry>
<title><ulink url="info://gcc/Top">Using the GNU Compiler Collection</ulink></title>
<author><firstname>Richard M.</firstname><surname>Stallman</surname></author>
</biblioentry>
<biblioentry>
<title><ulink url="info://libtool/Top">GNU Libtool</ulink></title>
<authorgroup>
<author><firstname>Gordon</firstname><surname>Matzigkeit</surname></author>
<author><firstname>Alexandre</firstname><surname>Oliva</surname></author>
<author><firstname>Thomas</firstname><surname>Tanner</surname></author>
<author><firstname>Gary V.</firstname><surname>Vaughan</surname></author>
</authorgroup>
</biblioentry>
<biblioentry>
<title>GNU Autoconf, Automake, and Libtool</title>
<edition>1st edition</edition>
<pubdate>October 2000</pubdate>
<authorgroup>
<author><firstname>Gary V.</firstname><surname>Vaughan</surname></author>
<author><firstname>Ben</firstname><surname>Elliston</surname></author>
<author><firstname>Tom</firstname><surname>Tromey</surname></author>
<author><firstname>Ian Lance</firstname><surname>Taylor</surname></author>
</authorgroup>
<publisher><publishername>New Riders Publishing</publishername></publisher>
<isbn>ISBN 1578701902</isbn>
</biblioentry>
<biblioentry>
<title>Advanced Programming in the UNIX(R) Environment</title>
<edition>1st edition</edition>
<pubdate>June 1992</pubdate>
<author><firstname>W. Richard</firstname><surname>Stevens</surname></author>
<publisher><publishername>Addison-Wesley Pub Co</publishername></publisher>
<isbn>ISBN 0201563177</isbn>
</biblioentry>
<biblioentry>
<title>Thinking in C++, Volume 1: Introduction to Standard C++</title>
<edition>2nd Edition</edition>
<pubdate>April 15, 2000</pubdate>
<author><firstname>Bruce</firstname><surname>Eckel</surname></author>
<publisher><publishername>Prentice Hall</publishername></publisher>
<isbn>ISBN 0139798099</isbn>
</biblioentry>
<biblioentry>
<title>Open Source Development with CVS</title>
<edition>2nd Edition</edition>
<pubdate>October 12, 2001</pubdate>
<authorgroup>
<author><firstname>Karl</firstname><surname>Fogel</surname></author>
<author><firstname>Moshe</firstname><surname>Bar</surname></author>
</authorgroup>
<publisher><publishername>The Coriolis Group</publishername></publisher>
<isbn>ISBN 158880173X</isbn>
</biblioentry>
<biblioentry>
<title>Programming PHP</title>
<edition>1st edition</edition>
<pubdate>March 2002</pubdate>
<authorgroup>
<author><firstname>Rasmus</firstname><surname>Lerdorf</surname></author>
<author><firstname>Kevin</firstname><surname>Tatroe</surname></author>
</authorgroup>
<publisher><publishername>O'Reilly & Associates</publishername></publisher>
<isbn>ISBN 1565926102</isbn>
</biblioentry>
<biblioentry>
<title>Programming Python</title>
<edition>2nd Edition</edition>
<pubdate>March 2001</pubdate>
<author><firstname>Mark</firstname><surname>Lutz</surname></author>
<publisher><publishername>O'Reilly & Associates</publishername></publisher>
<isbn>ISBN 0596000855</isbn>
</biblioentry>
<biblioentry>
<title>Gui Programming With Python : Using the Qt Toolkit</title>
<edition>Bk&Cd-r edition</edition>
<pubdate>January 2002</pubdate>
<author><firstname>Boudewijn</firstname><surname>Rempt</surname></author>
<publisher><publishername>Opendocs Llc</publishername></publisher>
<isbn>ISBN 0970033044</isbn>
</biblioentry>
<biblioentry>
<title>Programming Perl</title>
<subtitle>The Camel book</subtitle>
<edition>3rd Edition</edition>
<pubdate>July 2000</pubdate>
<authorgroup>
<author><firstname>Larry</firstname><surname>Wall</surname></author>
<author><firstname>Tom</firstname><surname>Christiansen</surname></author>
<author><firstname>Jon</firstname><surname>Orwant</surname></author>
</authorgroup>
<publisher><publishername>O'Reilly & Associates</publishername></publisher>
<isbn>ISBN 0596000278</isbn>
</biblioentry>
<biblioentry>
<title>Learning Perl</title>
<subtitle>The Lama book</subtitle>
<edition>3rd Edition</edition>
<pubdate>July 15, 2001</pubdate>
<authorgroup>
<author><firstname>Randal L.</firstname><surname>Schwartz</surname></author>
<author><firstname>Tom</firstname><surname>Phoenix</surname></author>
</authorgroup>
<publisher><publishername>O'Reilly & Associates</publishername></publisher>
<isbn>ISBN 0596001320</isbn>
</biblioentry>
</bibliography>
&underFDL;
</appendix>
</book>
|