~ubuntu-branches/debian/sid/kdevelop/sid

« back to all changes in this revision

Viewing changes to doc/tutorial/index.docbook

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2010-07-23 20:08:00 UTC
  • mfrom: (5.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100723200800-fh72fo2fhlxb16ud
Tags: 4:4.0.1-1
* New upstream release.
* Add localization packages: Finnish (fi), Dutch (nl), Slovenian (sl) and
  Thai (th).
* Update debian/control:
  - bump Standards-Version to 3.9.0 (no changes needed).
  - bump kdevplatform-dev and kdebase-workspace-dev build dependency version.
  - add shared-mime-info build dependency.
  - comment turkish localization package, not shipped in this release.
* Update debian/rules: remove workaround for FindKDE4Internal.cmake default
  rpath value, fixed in kdelibs5-dev 4.4.1.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook V3.1-Based Variant V1.0//EN" [
 
2
 <!ENTITY kdevelop "<application>KDevelop</application>">
 
3
 <!ENTITY % addindex "IGNORE">
 
4
 <![ %addindex; [ <!ENTITY docindex SYSTEM "docindex.docbook"> ]]>
 
5
]>
 
6
<book lang="en">
 
7
<bookinfo>
 
8
<title>KDE Application Tutorials
 
9
</title>
 
10
<subtitle>The KDE Application Tutorials Handbook for the KDevelop Integrated Development Environment</subtitle>
 
11
 
 
12
<authorgroup>
 
13
<author>
 
14
<firstname>Ralf</firstname>
 
15
<surname>Nolden</surname>
 
16
<affiliation>
 
17
<orgname>The KDevelop Team</orgname>
 
18
<address><email>Ralf.Nolden@post.rwth-aachen.de</email></address>
 
19
</affiliation>
 
20
</author>
 
21
</authorgroup>
 
22
 
 
23
<date>21/03/2000</date>
 
24
<releaseinfo>1.02.00</releaseinfo>
 
25
 
 
26
<keywordset>
 
27
<keyword>KDE</keyword>
 
28
<keyword>KDevelop</keyword>
 
29
<keyword>application tutorials</keyword>
 
30
</keywordset>
 
31
 
 
32
<abstract>
 
33
<para>The KDE Application Tutorials Handbook for the KDevelop Integrated
 
34
Development Environment, a tutorial collection on how to create KDE applications
 
35
through examples. This handbook itself is part of the KDevelop Integrated Development
 
36
Environment and is therefore also licensed under the GNU General Public License;
 
37
see <link linkend="copyright">Copyright</link> for more information.</para>
 
38
</abstract>
 
39
 
 
40
</bookinfo>
 
41
 
 
42
<chapter id="introduction">
 
43
<title>Introduction</title>
 
44
 
 
45
<para>As KDE is currently becoming a standard for Unix System desktops, more and
 
46
more developers want to take advantage of the well-written <abbrev>API</abbrev>
 
47
that the KDE project includes, to create new applications that offer a
 
48
<abbrev>GUI</abbrev> as well as an easy use of the classes provided with
 
49
Qt/KDE. The &kdevelop; project therefore intends to provide an
 
50
<abbrev>IDE</abbrev> which enables developers to create and extend their
 
51
applications rapidly with the main focus on KDE.</para><para>As beginners always have
 
52
difficulties getting started, this handbook tries to explain certain aspects of
 
53
application creation for KDE, by describing how to create running applications
 
54
with the sample code included with the Qt library, using the &kdevelop; 
 
55
<abbrev>IDE</abbrev> as well as creating KDE applications by examples.</para>
 
56
 
 
57
<para>The next chapter will explain to you how to create a project with
 
58
&kdevelop; that is already a complete application.  Then we'll walk through the Qt
 
59
online documentation, containing the sources for examples on how to use the Qt
 
60
library.</para>
 
61
 
 
62
<para>This will give you a first understanding of how the underlying Qt library
 
63
functions, and how to use the classes provided with it. Qt is our starting
 
64
point, as KDE is on top of the Qt library classes, and KDE applications make a
 
65
wide use of the QT classes.</para>
 
66
 
 
67
<para>Later, we will cover how to create a KDE application with &kdevelop;'s
 
68
application wizard. From the minimum framework provided, we will create a
 
69
running example KDE application that makes use of the KDE libraries, and will
 
70
explain the different parts of a KDE application in detail.</para>
 
71
 
 
72
<para>The &kdevelop; Team wishes you success in learing about KDE and Qt with
 
73
this handbook, and hope that it will enable you to become another programmer
 
74
contributing to the KDE project.</para>
 
75
    
 
76
<sect1 id="what-you-should-know-already">
 
77
<title>What you should know already</title>
 
78
 
 
79
<para>This handbook requires a base knowledge about the C++ programming language
 
80
as a minimum to understand the code examples and their functionality. Further,
 
81
it is assumed that you have read <ulink url="index.html">The User Manual to
 
82
&kdevelop;</ulink> as well as <ulink url="programming.html">The &kdevelop 
 
83
Programming Handbook</ulink> and know how the &kdevelop <abbrev>IDE</abbrev>
 
84
works in general, and what generated projects are.</para>
 
85
</sect1>
 
86
</chapter>
 
87
 
 
88
<chapter id="getting-started">
 
89
<title>Getting Started</title>
 
90
 
 
91
<para>Before you start the tutorial, you should have set up &kdevelop; to work correctly. Ensure you have
 
92
access to the Qt online reference documentation in the <guimenu>"Help"</guimenu>
 
93
menu or the corresponding book in the documentation tree. When looking at the
 
94
first page of the Ot documentation, you will see that it contains a link to a
 
95
section "Tutorials" and "Examples". Under "Tutorials", you will find a 14-step
 
96
introduction into using the Qt library to build applications. 
 
97
"Examples" will lead you to a list of example programs that Qt includes, and
 
98
show for example, usage reference in certain classes. Now, if you are an
 
99
absolute beginner, you should make yourself comfortable with the idea behind Qt - providing a
 
100
library that offers:</para>
 
101
 
 
102
<itemizedlist>
 
103
<listitem>
 
104
<para>a base application class (<classname>QApplication</classname>)</para>
 
105
</listitem>
 
106
<listitem>
 
107
<para>a widget library for graphical user interfaces</para>
 
108
</listitem>
 
109
<listitem>
 
110
<para>a set of additional helper classes for graphics, file, and data handling</para>
 
111
</listitem>
 
112
<listitem>
 
113
<para>the signal-slot mechanism for object communication</para>
 
114
</listitem>
 
115
<listitem>
 
116
<para>event controlling through event loops and virtual methods</para>
 
117
</listitem>
 
118
</itemizedlist>
 
119
 
 
120
<para>If the above list doesn't make sense to you right now, you should read about the Qt
 
121
library in <ulink url="programming-2.html#ss2.1">The &kdevelop; Programming
 
122
Handbook</ulink> where the basics for a Qt application are described in
 
123
detail. There, you will also find an introduction about the difference between
 
124
a Qt and a KDE application, which is not covered much at the first level of the
 
125
Qt tutorial step.</para>
 
126
 
 
127
<para>To learn about Qt first is a good start for programming KDE
 
128
applications as well, so we will create a project that will produce the tutorial
 
129
applications after editing.</para>
 
130
    
 
131
<para>To do this, start with opening &kdevelop; and select
 
132
<menuchoice><guimenu>"Project"</guimenu><guimenuitem>"New"</guimenuitem></menuchoice>
 
133
from the menubar. The application wizard opens and you have to select which type
 
134
of project you want to build. For Qt applications, you would choose the Qt
 
135
application, but we will use the mini-KDE project to build our examples. The
 
136
reason is simple: the Qt tutorials don't contain much code, and by choosing the
 
137
Qt application in the application wizard, we would have to do a lot of changing
 
138
in the provided code, to create "true" examples.</para>
 
139
 
 
140
<para>But as the mini-KDE application only consists of an empty main window but
 
141
also checks for the Qt library and header files, it will fit for our purposes
 
142
and doesn't require much change.</para>
 
143
 
 
144
<para>When entering the next wizard page, we have to enter the project-specific
 
145
information. There, we can leave out any KDE-specific additions such as a
 
146
mini-icon and a main icon, documentation etc. We just fill in the information
 
147
that will be useful for building a suitable base for the tutorials. As the
 
148
structure of the tutorial steps builds the next step on the previously created
 
149
code, we can start with "MyWidget" as the project name. This will already build
 
150
us the base class that is needed in chapter 4, so we don't have to take care of
 
151
that later. As we want to start with the first tutorial step, we will use '1' as
 
152
the project number, which we can increase later when moving to the next
 
153
step.</para>
 
154
 
 
155
<para>Then, fill in the other required information such as your name, email
 
156
address, and project directory. That would be all we need, and we can flip to
 
157
the next page. Insert your header for the project's header file here or use the
 
158
given example. The same is done with the fourth page, where the same has to be
 
159
set for the source files. Finally, the last page is entered, where you have to
 
160
press <guibutton>"Create"</guibutton> to build the project. If the button is not
 
161
available, start at the first page again and make sure you didn't miss inserting
 
162
any required information.</para>
 
163
 
 
164
<para>If everything went OK, the project has been build and the messages window
 
165
in the application wizard will have "READY" at it's last line.  Select
 
166
<guibutton>"Close"</guibutton> to finish the wizard.</para>
 
167
    
 
168
<para>When looking at the treeview on the left, you will see that the project
 
169
alreay includes a class <classname>"MyWidget"</classname> - this is because we
 
170
chose this to be the application name. Further, when opening
 
171
<guilabel>"Functions"</guilabel> in the classviewer's
 
172
<guilabel>"Globals"</guilabel> folder, you will see that the application already
 
173
contains a <function>main()</function> function where the execution will
 
174
start.</para>
 
175
 
 
176
<para>Now the application is already set up. You could do an
 
177
<guimenuitem>"Execute"</guimenuitem> or <guimenuitem>"Make"</guimenuitem>, but
 
178
as we want to create the tutorial applications, we can go ahead and change the
 
179
code first to create our tutorial examples, which we'll do in the next
 
180
step.</para>
 
181
</chapter>
 
182
  
 
183
<chapter id="building-the-qt-tutorials">
 
184
<title>Building the Qt Tutorials</title>
 
185
 
 
186
<sect1 id="step-one-hello-world">
 
187
<title>Step One: Hello World!</title>
 
188
 
 
189
<para>As the previous chapter explains, we created a project called "MyWidget".
 
190
Now, when looking at the first tutorial page of the Qt documentation, you will
 
191
see that the first application only uses a <function>main()</function>
 
192
function. Therefore, we only have to change the given <function>main()</function>
 
193
function of our generated project to get the first tutorial step running.</para>
 
194
 
 
195
<para>To access the <function>main()</function> function, select it from the
 
196
classviewer's <guilabel>"Globals"</guilabel> folder, which contains a subfolder
 
197
for <guilabel>"Functions"</guilabel> where all non-class functions are
 
198
listed. This will open the file <filename>main.cpp</filename> in the
 
199
<guilabel>"C/C++ Files"</guilabel> window and the editing cursor is already set
 
200
in front of the first line of <function>main()</function>.</para>
 
201
 
 
202
<sect2 id="what-to-change-first">
 
203
<title>What to change first</title>
 
204
 
 
205
<para>We could start changing the given code towards the desired result which is
 
206
listed in the tutorial, but it can be even easier. Select the contents of the
 
207
<function>main()</function> function with the mouse, or by holding the
 
208
<keycombo><keycap>Shift</keycap></keycombo> key pressed while selecting the
 
209
lines with the <keycombo><keycap>down-arrow</keycap></keycombo> key. Then select
 
210
<guimenuitem>"Cut"</guimenuitem> from the <guimenu>"Edit"</guimenu> menu or
 
211
press the <keycombo><keycap>DEL</keycap></keycombo> key to remove the selected
 
212
code. This will clear the main function and we can start from scratch to build
 
213
our first tutorial.</para>
 
214
 
 
215
</sect2>
 
216
 
 
217
<sect2 id="entering-the-tutorial-code">
 
218
<title>Entering the tutorial code</title>
 
219
 
 
220
<para>Now, to insert the code from the tutorial, you could first read it
 
221
carefully and try to remember which line contained which code. Then, 
 
222
after reading the tutorial's line-by-line description, you could use it as an
 
223
example to write the tutorial by yourself.</para>
 
224
 
 
225
<para>Those who want to go the easy way: select the contents of the listed
 
226
<function>main()</function> function in the documentation browser and press the 
 
227
<guiicon>"Copy"</guiicon> icon from the toolbar. Optionally, you could use the
 
228
context-menu or the according entry in the <guimenu>"Edit"</guimenu> menu. This
 
229
will copy the selection into the clipboard and, after switching back to the
 
230
sourcecode window, can be inserted with <guimenuitem>"Paste"</guimenuitem>
 
231
(either from the context menu, the toolbar icon, or the according entry in the
 
232
<guimenu>"Edit"</guimenu> menu).</para>
 
233
 
 
234
<para>Finally, add the according header files outside the
 
235
<function>main()</function> function:</para>
 
236
 
 
237
<programlisting>
 
238
#include &lt;qapplication.h&gt;
 
239
#include &lt;qpushbutton.h&gt;
 
240
</programlisting>
 
241
 
 
242
<para>That's it! The source code is done for your first tutorial
 
243
application.</para>
 
244
 
 
245
</sect2>
 
246
 
 
247
<sect2 id="building-hello-world">
 
248
<title>Building Hello World!</title>
 
249
 
 
250
<para>To build the first tutorial, select <guimenuitem>"Make"</guimenuitem> from
 
251
the <guimenu>"Build"</guimenu> menu or press the corresponding toolbar
 
252
icon. Optionally, you could choose <guimenuitem>"Execute"</guimenuitem> as well,
 
253
which results in running the application after the build was successful.</para> 
 
254
 
 
255
<para>If the build stops due to an error, be assured the fault was on the
 
256
programmer's side, not on the tutorial! It would be sad to have to 
 
257
search for an error, just when you decided to program for KDE and/or Qt, but you
 
258
can use this to train yourself to use &kdevelop;.</para>
 
259
 
 
260
<para> To find an error, you have two options: either select the according error
 
261
message in the output window, which will bring you to the line the error
 
262
occured, or press the <keycap>F4</keycap> key. If there is
 
263
more than one error, you could use the <guimenuitem>"Next Error"</guimenuitem>
 
264
entry in the <guimenu>"View"</guimenu> menu.</para>
 
265
 
 
266
</sect2>
 
267
 
 
268
<sect2 id="exercises">
 
269
<title>Exercises</title>
 
270
 
 
271
<para>You may ask "Exercises? This one was so simple, I don't need to
 
272
excercise!", but be assured, things will get more complicated. This one was the
 
273
easiest example, and the more complex they get, the more thinking is asked
 
274
on your side, to understand and follow the tutorial steps. Also the excercises
 
275
will enable you to learn how to actually use &kdevelop; and it's
 
276
features.</para>
 
277
 
 
278
<para>To teach yourself more with the first tutorial, you should try to do the
 
279
following changes to the given code and see how this will influence the
 
280
application behaviour:</para>
 
281
 
 
282
<orderedlist>
 
283
<listitem><para>change the pushbutton to a
 
284
<classname>QLabel</classname>.</para></listitem> <listitem><para>use
 
285
<function>setText()</function> instead of directly setting the text in the
 
286
pushbutton's constructor</para></listitem> <listitem><para>use
 
287
<literal>QPushButton::resize ( const QSize & s )</literal> instead of setting
 
288
the size by width and height directly. Create a <classname>QSize</classname>
 
289
instance first that contains the size</para></listitem> <listitem><para>play
 
290
with the sizes to see which is width and which is height</para></listitem>
 
291
</orderedlist>
 
292
 
 
293
</sect2>
 
294
</sect1>
 
295
 
 
296
<sect1 id="step-2-and-3-extensions">
 
297
<title>Step 2 and 3: Extensions</title>
 
298
 
 
299
<para>The tutorial steps 2 and 3 are extending the facilities of the first
 
300
tutorial. Here, you will learn about signals and slots, as well as parent-child
 
301
relationships between widgets.</para>
 
302
 
 
303
<para>Why is it important to learn about that? Well, the signals and slots
 
304
are building the technology which make the difference when comparing the Qt
 
305
library to other widget library.  Whenever you will hit an implementation
 
306
problem where you want to communicate between objects, this will make your work
 
307
incredibly short, and nothing serious will happen if something went wrong, even
 
308
misconnections do not lead to a segmentation fault. This is the strength of the
 
309
Qt library and a lot of KDE/Qt developers will not want to miss it's
 
310
it's flexibility. Understanding the signal/slot mechanism therefore,
 
311
is essential to create any KDE/Qt application.</para>
 
312
      
 
313
<para>Another thing to watch out for is the fact that the button terminates the <classname>QApplication</classname> instance by calling <function>quit()</function>. You will meet <function>quit()</function> again when working with <classname>QApplication</classname>'s KDE-pendant, <application>KApplication</application></para>
 
314
</sect1>
 
315
    
 
316
<sect1 id="writing-your-own-widgets">
 
317
<title>Writing your own Widgets</title>
 
318
 
 
319
<para>Now, after having successfully modified and extended the
 
320
<function>main()</function> function, you will hit the point where you need to
 
321
create a new widget.  A unique widget, that only can be constructed with the class
 
322
you're about to write in step 4.  Actually, the class has been created by the
 
323
application wizard for you, so there is not much to add. You have to insert the
 
324
code that lesson 4 places in the <filename>main.cpp</filename> file into the
 
325
<classname>MyWidget</classname> classes' header and implementation
 
326
file. Fortunately, you only have to add the implementation to the constructor
 
327
code.</para>
 
328
      
 
329
<para>To access the constructor, select it from the classviewer. This will
 
330
automatically bring you to the implementation where you have to add the
 
331
code.</para>
 
332
      
 
333
<para>Here, you only have to watch out for the include of
 
334
<filename>qfont.h</filename>.  <classname>QFont</classname> is only used in the
 
335
constructor code of <classname>MyWidget</classname>.  Therefore, add
 
336
<userinput>#include &lt;qfont.h&gt;</userinput> to the top of the
 
337
<filename>mywidget.cpp</filename> file.</para>
 
338
      
 
339
<para>To run the new application, just hit
 
340
<guimenuitem>"Execute"</guimenuitem>. This will result in compling the changes
 
341
after an autosaving.</para>
 
342
</sect1>
 
343
    
 
344
<sect1 id="extending-the-widget-class">
 
345
<title>Extending the Widget Class</title>
 
346
 
 
347
<para>Now, in lesson 5 the target is to extend the widget class, and you will
 
348
learn about virtual functions as well. Here, the
 
349
<function>resizeEvent()</function> is reimplemented. What is important to learn
 
350
here (besides extending a class,) is that Qt works with user events by virtual
 
351
functions that take an event as a parameter. Therefore, you should make yourself
 
352
comfortable with the following classes of the Qt library:</para>
 
353
 
 
354
<para><itemizedlist>
 
355
<listitem>
 
356
<para><classname>QEvent</classname></para>
 
357
</listitem>
 
358
<listitem>
 
359
<para><classname>QChildEvent</classname></para>
 
360
</listitem>
 
361
<listitem>
 
362
<para><classname>QCloseEvent</classname></para>
 
363
</listitem>
 
364
<listitem>
 
365
<para><classname>QFocusEvent</classname></para>
 
366
</listitem>
 
367
<listitem>
 
368
<para><classname>QKeyEvent</classname></para>
 
369
</listitem>
 
370
<listitem>
 
371
<para><classname>QMouseEvent</classname></para>
 
372
</listitem>
 
373
<listitem>
 
374
<para><classname>QMoveEvent</classname></para>
 
375
</listitem>
 
376
<listitem>
 
377
<para><classname>QPaintEvent</classname></para>
 
378
</listitem>
 
379
<listitem>
 
380
<para><classname>QResizeEvent</classname></para>
 
381
</listitem>
 
382
<listitem>
 
383
<para><classname>QTimerEvent</classname></para>
 
384
</listitem>
 
385
</itemizedlist>
 
386
</para>
 
387
      
 
388
<para>Whenever writing custom widgets, especially view areas of applications,
 
389
you will have to overwrite the default implementation of the widget's
 
390
event-methods with your own for certain events that have to be processed. Those
 
391
would be <abbrev>e.g.</abbrev></para>
 
392
<informalexample>
 
393
<para><function><type>virtual void </type> mousePressEvent ( <type>QMouseEvent *</type>
 
394
)</function></para> </informalexample> <para> for processing a mouse event to pop
 
395
up a context menu. In the implementation, you have to insert a formal parameter
 
396
into the function header, most developers either use
 
397
<parameter>event</parameter> or just <parameter>e</parameter> as the parameter
 
398
name.</para>
 
399
      
 
400
<para>Then, you can process the event's parameters. For a
 
401
<classname>QMouseEvent</classname>, you have to ask if the
 
402
<mousebutton>right</mousebutton>, <mousebutton>middle</mousebutton> or
 
403
<mousebutton>left</mousebutton> mouse button was the one that caused the
 
404
event.</para>
 
405
</sect1>
 
406
 
 
407
<sect1 id="adding-a-new-class">
 
408
<title>Adding a new Class</title>
 
409
 
 
410
<para>In lesson 6, you will have to add a class to the tutorial
 
411
application. Now, normally you would think "I just will create a header file and
 
412
an implementation file, then I'm done". &kdevelop; will make it easier for you!
 
413
When adding a class, you should always use the Classgenerator. This will do all
 
414
the work for you, so you just will have to add the specific code.</para>
 
415
      
 
416
<para>To add a class with the Classgenerator, choose
 
417
<menuchoice><guimenu>"Project"</guimenu><guimenuitem>"New
 
418
Class"</guimenuitem></menuchoice>, which will open a dialog to enter all needed
 
419
values for the class you want to add. The first thing we have to insert is the
 
420
classname. The tutorial name this <classname>LCDRange</classname>, so this has
 
421
to be inserted first. Then proceed to the baseclass. The baseclass is the one
 
422
that the new class inherits. Looking at the tutorial (Qt 1.42), this is
 
423
<classname>QWidget</classname>.  Now, as most <abbrev>GUI</abbrev> classes to
 
424
add would inherit <classname>QWidget</classname>, the Classgenerator makes it
 
425
even easier. Leave the baseclass empty, and instead check <guilabel>"QWidget
 
426
child class"</guilabel> in the <guilabel>"Additional Options"</guilabel>
 
427
section. This will automatically add the required <literal remap="tt">Q_OBJECT</literal> macro to the headerfile, to add slots and signals
 
428
later (which is required in <link linkend="step-7-14">chapter 7</link>).</para>
 
429
      
 
430
<para>As the filenames are automatically inserted, you don't have to take care
 
431
of that. The only thing that we would suggest adding is the documentation. It is
 
432
always a good style to add a desciptive documentation to the class, especially
 
433
as the classname <classname>LCDRange</classname> doesn't inform you specifically
 
434
about the purpose of the widget.</para>
 
435
</sect1>
 
436
 
 
437
<sect1 id="step-7-14">
 
438
<title>Step 7-14</title>
 
439
 
 
440
<para>For the rest of the tutorial steps, you are prepared and you already know
 
441
everything you have to know about adding the classes required, and doing the
 
442
changes.</para>
 
443
 
 
444
<para>After each change you should do a new build, and check your code for
 
445
errors. Run the application, and follow it's execution. Additionally, you should
 
446
play with &kdevelop;'s options for <guimenu>"Build"</guimenu>.  Try executing the
 
447
application with a commandline argument such as <option>--geometry</option>, and
 
448
debugging it with <application>KDbg</application> in the Tools-window.</para><para> Then you
 
449
should be able to proceed with the Qt examples that are provided with Qt.</para>
 
450
 
 
451
<para> In the next chapter, you will be introduced into development for KDE 2,
 
452
by an example application <application>KScribble</application>, which is a small
 
453
drawing application that will show you the concepts of application design, and
 
454
how to implement you own program.</para>
 
455
 
 
456
</sect1>
 
457
</chapter>
 
458
 
 
459
<chapter id="creating-kde-applications">
 
460
<title>Creating KDE Applications</title>
 
461
 
 
462
<para>This handbook will try to teach you KDE/Qt application design by creating
 
463
an example application step-by-step. The major intention is to gain a certain
 
464
understanding how two of the most important ideas of graphical user interface
 
465
programming work: the document-view model, and the multiple document interface
 
466
(<abbrev>MDI</abbrev>) model.</para>
 
467
 
 
468
<para>You will also get a good idea of concepts that are coming up ahead.  These
 
469
include the KDE 2 and the Qt 2.1 libraries, bringing new enhancements and
 
470
technology to the programmer's hands, that will improve application design and
 
471
widen the possibilities that are open to use.  Keywords such as "widget themes",
 
472
"Inter-Process Communication" and "embedded applications" are talked about and
 
473
will allow even more than you can imagine right now.</para>
 
474
    
 
475
<para>&kdevelop; 1.1, still based on KDE 1.1.x, provides developers some of the
 
476
most exciting possibilities, including the ability to begin developing
 
477
applications for KDE 2, while still running a stable desktop environment. For this reason, 
 
478
this tutorial will be based on a KDE 2 application that
 
479
already makes use of Qt-2.1, offering a solution for the mentioned
 
480
<abbrev>MDI</abbrev> model, which we provide as a ready-to-go frame
 
481
application. During this tutorial you will get a clear insight on how it works
 
482
and this will also make it much easier to understand the document-view model,
 
483
which is hard to understand even for advanced programmers. That will help you
 
484
create other type of applications, which uses the document-view model, even if
 
485
they only contain one window and you can't see an obvious need for
 
486
it.</para>
 
487
 
 
488
<para>But let's just move on - you will see what's coming up on you and how
 
489
easy it actually is.</para>
 
490
 
 
491
<para>The upcoming chapters of the tutorial cover the following several
 
492
steps:</para>
 
493
 
 
494
<itemizedlist>
 
495
<listitem><para>installing KDE 2 (libraries) and setting up &kdevelop; to create
 
496
KDE 2 applications.</para></listitem>
 
497
<listitem><para>understanding the basic concepts of <abbrev>MDI</abbrev> and
 
498
document-view model.</para></listitem>
 
499
<listitem><para>creating the generic framework for
 
500
<application>KScribble</application>, and explaining the concept of the
 
501
framework.</para></listitem>
 
502
<listitem><para>implementing the document class, which will provide the
 
503
interface to read and write the document data, as well as maintaining the
 
504
document.</para></listitem>
 
505
<listitem><para>implementing the view class, to visualize the data. This class
 
506
also takes over the interaction with the user.</para></listitem>
 
507
<listitem><para>adding dialogs to set the pen width, and color of the pen to
 
508
draw with, including their integration into the toolbar and
 
509
menubar</para></listitem>
 
510
<listitem><para>changing the view from the default
 
511
<classname>QWidget</classname> inheritance to a scrollable
 
512
view.</para></listitem>
 
513
</itemizedlist>
 
514
    
 
515
<para>The tutorial example itself is based on the code found in the scribble example application that comes with the Qt
 
516
library. The source of the original example can also be found within the Qt documentation, in the examples section.</para>
 
517
</chapter>
 
518
 
 
519
<chapter id="installing-kde-2">
 
520
<title>Installing KDE 2</title>
 
521
 
 
522
<para>In this chapter we will first go through a couple of steps that will help
 
523
you set up &kdevelop; for creating KDE 2 / Qt 2.x applications. The requirements
 
524
are:</para>
 
525
 
 
526
<itemizedlist>
 
527
<listitem>
 
528
<para>a current Qt-2.1 snapshot, available at <ulink url="http://www.troll.no">http://www.troll.no</ulink></para>
 
529
</listitem>
 
530
<listitem>
 
531
<para>a current KDE 2 snapshot of the packages <literal>kdesupport</literal> and <literal> kdelibs</literal></para>
 
532
</listitem>
 
533
</itemizedlist>
 
534
 
 
535
<para>Both the Qt-2.1 and KDE 2 libraries are currently under development but
 
536
are you may consider them close to final.  Changes to be expected for the final
 
537
versions are minimal, and may not even affect your application. This means
 
538
you are getting to know the newest libraries available - and you have got a
 
539
valuable time-saving, enabling you to create your application even before the libraries are
 
540
completed.</para>
 
541
 
 
542
<para>The following sections describe what to do in detail within three steps:</para>
 
543
 
 
544
<procedure>
 
545
<step><para>installing the Qt library</para></step>
 
546
<step><para>installing the KDE libraries</para></step>
 
547
<step><para>setting up &kdevelop;</para></step>
 
548
</procedure>
 
549
 
 
550
<para>Then you are ready to go, and we will proceed with creating the first step
 
551
of the example program <application>KScribble</application> in the next
 
552
chapter.</para>
 
553
    
 
554
<sect1 id="setting-up-qt-2.1">
 
555
<title>Setting up Qt-2.1</title>
 
556
 
 
557
<para>This first step will give you the minimum requirement to follow our
 
558
example.  There is a possibility to avoid installing KDE 2 if
 
559
you're only interested in creating Qt-only programs. As Qt-2.1 contains all
 
560
needed classes, and &kdevelop; provides a project template for multiple document
 
561
interface applications for Qt-2.1, (as well based on the same framecode that is
 
562
used in the KDE 2 template), you should have no problem at all following the
 
563
example with a Qt-only application.</para>
 
564
 
 
565
<para>To get the newest Qt library, get a recent version from the Troll
 
566
 Tech website at <ulink url="http://www.troll.no">http://www.troll.no</ulink>,
 
567
 in the download section. Then change user to root, and copy the tarball to the
 
568
 directory where your currently used Qt version is placed as well - on a SuSE
 
569
 Linux system this would be <filename>/usr/lib</filename>, where you should
 
570
 have a directory for either qt-1.44 or qt-2.0.2, depending on the distribution
 
571
 version. Untar the library sources with</para>
 
572
 
 
573
<informalexample><screen><command>tar zxvf <replaceable>qtxxx.tar.gz</replaceable></command></screen></informalexample>
 
574
 
 
575
<para>depending on the name of the tarball. Then set the environment variable
 
576
<envar>QTDIR</envar> to point to the directory where your new Qt-2.1 library is
 
577
placed with <abbrev>e.g.</abbrev></para>
 
578
<informalexample><screen><command>setenv <envar>QTDIR</envar>=<replaceable>/usr/lib/qt-2.1</replaceable></command></screen></informalexample>
 
579
 
 
580
<para> Another solution would be to move the qt-1.44 directory, usually just
 
581
named <filename>qt</filename>, to <filename>qt-1.44</filename> and create a
 
582
symlink that for now has to point to <filename>qt-2.1</filename>.  After the
 
583
library is built, change it back to point to the
 
584
<filename>qt-1.44</filename>directory.</para>
 
585
 
 
586
<para>Change to the Qt-2.1 directory and type:</para>
 
587
 
 
588
<screen><command>./configure</command> 
 
589
<command>make</command>
 
590
</screen>
 
591
 
 
592
<para>You can now change back your <envar>QTDIR</envar> variable to point to
 
593
your qt-1.44 installation, after successfully compiling the Qt-2.1
 
594
library.</para>
 
595
 
 
596
<para>Now switch to the directory <filename>/usr/lib/qt-2.1/lib</filename> and
 
597
copy the created libraries to <filename>/usr/lib</filename> 
 
598
<emphasis>exept</emphasis> the symbolic link
 
599
<filename>libqt.so</filename>.</para>
 
600
 
 
601
<para>Then you are done with Qt, and you can proceed to the next step, setting
 
602
up KDE 2 libraries. If you want to develop for Qt only, proceed directly to the
 
603
section <link linkend="setting-up-kdevelop">Setting up &kdevelop;</link>.</para>
 
604
</sect1>
 
605
 
 
606
<sect1 id="setting-up-kde-2-libraries">
 
607
<title>Setting up KDE 2 Libraries</title>
 
608
 
 
609
<para>The second step leads you through installing the needed KDE
 
610
libraries. Download a recent snapshot of the library packages <literal>kdesupport</literal> and <literal>kdelibs</literal> from
 
611
<ulink url="http://www.kde.org/">http://www.kde.org/</ulink>. Then things will
 
612
go a bit easier than for the Qt library. Just untar the sources to your
 
613
directory, and change to the new kdesupport directory first. There, type:</para>
 
614
 
 
615
<informalexample><screen>
 
616
<command>./configure <option>--with-qt-dir=<replaceable>/usr/lib/qt-2.1</replaceable> --prefix=<replaceable>/opt/kde2</replaceable></option></command> 
 
617
<command>make</command>
 
618
 
 
619
and as root:
 
620
 
 
621
<command>make install</command>
 
622
</screen></informalexample>
 
623
 
 
624
<para>This will install the kdesupport package to the directory given in the
 
625
<option>--prefix</option> option and compile using the new build Qt-2.1 library,
 
626
to which you give the path to configure by the option
 
627
<option>--with-qt-dir</option>.</para>
 
628
 
 
629
<para>The same applies to the kdelibs package, just change to the kdelibs
 
630
directory, and type the same as you did above for the kdesupport package.</para>
 
631
 
 
632
<para>You are now done with setting up the requirements for the required
 
633
libraries to build a KDE 2 application.</para>
 
634
 
 
635
<note><para>As a note aside, the KDE library package contains support for
 
636
automatic <abbrev>HTML</abbrev> documentation generation, which you can easily
 
637
get by installing <application>KDoc</application>, version 2.x. Then type
 
638
<command>makekdedoc</command> in your kdelibs directory and
 
639
<application>KDoc</application> will create the <abbrev>HTML</abbrev>
 
640
documentation in a subdirectory <filename>srcdoc</filename>. In &kdevelop; you
 
641
can access the KDE library documentation online with setting the KDE library
 
642
documentation path in the &kdevelop; Setup dialog to point to
 
643
<filename>kdelibs/srcdoc</filename>. In the same way, set your Qt-Online
 
644
documentation path in &kdevelop; to point to
 
645
<filename>/usr/lib/qt-2.1/html</filename>, so you can access the documentation
 
646
right away from within &kdevelop;.</para></note>
 
647
 
 
648
<para>If you successfully installed the Qt-2.1 and KDE 2 libraries, you're just
 
649
one step away from creating your first KDE 2 application.  You just need to give
 
650
&kdevelop; the information as to where you installed the libraries - which we'll
 
651
do in the next section.</para>
 
652
</sect1>
 
653
 
 
654
<sect1 id="setting-up-kdevelop">
 
655
<title>Setting up KDevelop</title>
 
656
 
 
657
<para>This part is somewhat the easiest in the whole configuration process for
 
658
KDE 2 development: Setting up &kdevelop;. Just open &kdevelop;, then select
 
659
<menuchoice><guimenu>"Options"</guimenu><guimenuitem>"KDevelop
 
660
Setup"</guimenuitem></menuchoice> to access the &kdevelop; configuration. There,
 
661
change to the last page, titled <guilabel>"Path"</guilabel>. This page contains
 
662
two entry fields, one for the Qt library, and one for the KDE 2 libraries. As
 
663
you have successfully installed everything, select
 
664
<filename>/usr/lib/qt-2.1</filename> for the Qt-2.x library path and
 
665
<filename>/opt/kde2</filename> for the KDE 2 library path. Press the
 
666
<guibutton>"OK"</guibutton> button and you're done.</para>
 
667
 
 
668
<para>Users that only want to develop for Qt-2.x (including the current Qt-2.0.2
 
669
version) just have to set the Qt-2.x library path.</para>
 
670
 
 
671
<para>Now we can proceed to the next chapter where we will create the first step
 
672
of the <application>KScribble</application> example.</para>
 
673
</sect1>
 
674
</chapter>
 
675
 
 
676
<chapter id="application-concepts">
 
677
<title>Application Concepts</title>
 
678
 
 
679
<para>This chapter now introduces you into the ideas of the application models
 
680
mentioned already: the <abbrev>MDI</abbrev> (Multiple Document Interface) and
 
681
the Document-View model. A basic introduction into the Document-View model and
 
682
the generating of a project with &kdevelop; is already given in <ulink url="../programming/index.html">The &kdevelop; Programming Handbook</ulink>, but
 
683
based on a Single Document Interface (<abbrev>SDI</abbrev>). In any case, you
 
684
should be familiar with the basics of the KDE and Qt classes that are explained
 
685
in <ulink url="../kde_libref/index.html">The KDE Library Reference
 
686
Guide</ulink>. There, the base classes of the underlying libraries are explained
 
687
in detail, and how to use them, with an additional description of the Qt
 
688
signal-slot mechanism and event handling.</para>
 
689
    
 
690
<para>As a guideline, you should know already:</para>
 
691
<itemizedlist>
 
692
<listitem>
 
693
<para>that every KDE application needs one instance of
 
694
<classname>KApplication</classname> (for a Qt application one instance of
 
695
<classname>QApplication</classname>)</para>
 
696
</listitem>
 
697
<listitem>
 
698
<para>generally a main window is inherited from
 
699
<classname>KTMainWindow</classname> for KDE (for a Qt application inherited from
 
700
<classname>QMainWindow</classname>)</para>
 
701
</listitem>
 
702
<listitem>
 
703
<para>that events (<abbrev>e.g.</abbrev>, keyboard presses or mouse movements)
 
704
are sent to the application by the underlying window system</para>
 
705
</listitem>
 
706
<listitem>
 
707
<para>that <application>QWidget</application> as the base class for all visible
 
708
Graphical User Interface (<abbrev>GUI</abbrev>) components provides specialized
 
709
event handlers by virtual functions that filter out the according events by
 
710
reimplementing <literal remap="bf">QObject::event()</literal></para>
 
711
</listitem>
 
712
<listitem>
 
713
<para>that the Qt signal-slot mechanism means basically that a component can
 
714
send out signals and a receiver can connect to those signals to process some
 
715
actions</para>
 
716
</listitem>
 
717
<listitem>
 
718
<para>that this mechanism avoids inheriting classes for <abbrev>GUI</abbrev>
 
719
components because the signals inform you about <abbrev>e.g.</abbrev> mouse
 
720
presses where appropriate for a wiget</para>
 
721
</listitem>
 
722
</itemizedlist>
 
723
 
 
724
<sect1 id="the-document-view-model">
 
725
<title>The Document-View Model</title>
 
726
 
 
727
<para>The Document-View Model is one of the most basic concepts in the design of
 
728
applications that rely on graphical user interfaces. Therefore, a certain
 
729
understanding of the why this is, helps you understand that although the
 
730
programmer has other possibilities, it makes sense to make use of the
 
731
Document-View Model.</para>
 
732
 
 
733
<para> But first let's follow the usual design of a typical KDE / Qt
 
734
application:</para>
 
735
 
 
736
<para>Your application instance provides the first connection to your
 
737
application and is the starting point of the event handling for a program. The
 
738
program itself represents itself to the user by a Graphical User Interface which
 
739
is most often called a main-window. The main window then provides the
 
740
appropriate functions for the user such as key accelerators, a menubar, toolbar
 
741
and a statusbar. In the center, it contains a so-called "view-area" which means
 
742
that this part is an instance of another class, usually called a "View". The
 
743
view instance is created when the main window is constructed at program start,
 
744
and has to be set as the view area component with a method provided by the main
 
745
window: <function>setView(<symbol>your_view</symbol>)</function> for KDE applications using
 
746
<classname>KTMainWindow</classname>,
 
747
<function>setCentralWidget(<symbol>your_view</symbol>)</function> for a Qt application using
 
748
<classname>QMainWindow</classname>. Now, the view obviously is the area that is
 
749
responsible for interacting with the user to manipulate the data that it
 
750
represents. As an example, you could use a <classname>QMultiLineEdit</classname>
 
751
as a view and you will have an editor. Then you can use the provided slots of
 
752
the view for connections to menubar or toolbar command like this:</para>
 
753
      
 
754
<para>While creating the menubar, you want to provide a method for the command
 
755
<guimenuitem>"cut"</guimenuitem> in the <guimenu>"Edit"</guimenu> menu:</para>
 
756
 
 
757
<informalexample>
 
758
<screen>  
 
759
pEditMenu-&gt;insertItem(BarIcon("editcut"), i18n("Cu&amp;t"),view, SLOT(cut()),KAccel::Cut, ID_EDIT_CUT);
 
760
</screen>
 
761
</informalexample>
 
762
 
 
763
<para>This creates a menu item in the <guimenu>"Edit"</guimenu> menu, that, when
 
764
activated, directly calls the slot <function>cut()</function> of the instance
 
765
<literal remap="tt">view</literal>.  We are assuming here, that you have created
 
766
this instance as a <classname>QMultiLineEdit</classname> and set it as the view
 
767
area. The Multiline-edit's slot is called, and cuts out the selected text as a
 
768
result.  The functionality is already provided by the class itself, and so there
 
769
is no need to inherit from <classname>QMultiLineEdit</classname> to create a
 
770
view area that is capable of such actions. They are ready to use, and make
 
771
application development very fast- you just need the application instance and
 
772
the main window, including the connections to your view area, and you're
 
773
done!</para>
 
774
      
 
775
<para>That means, a simple editor can be written by creating one single class
 
776
that defines the main window behavoir and how to save and read files into the
 
777
editor - just some basic slots your main view has to implement itself.</para>
 
778
      
 
779
<para>But here is the reason why we're now introducing this mysterious
 
780
Document-View model: You have to provide methods of your own, to read and write
 
781
the actual files you want to edit with the <classname>QMultiLineEdit</classname>
 
782
view-area <emphasis>within</emphasis> the main window's interface.
 
783
Yes, this is obviously the easiest thing to do in this case, and the most
 
784
logical.</para>
 
785
 
 
786
<para>Now, if we have a look at the files and their contents as a so-called
 
787
"Document", which we can subscribe with the attribute of an "Object" in C++
 
788
terminology, the next step is just a little one: If I have a document, a view
 
789
and a main window, why don't I separate these three objects from each other? We
 
790
could easily create a small class that is responsible for reading in a file into
 
791
a text stream, and then call the view to draw the text visible to the user.  The
 
792
same applies to saving the file again - the document class should then provide a
 
793
saving method that retrieves the text from the view again and saves it as a
 
794
file. In the example these two methods would be the only actions that are needed
 
795
to be done by a document class, because the edit-view already provides all
 
796
methods basically needed for and editor by slots and you can manipulate the
 
797
content of the view by them directly.</para>
 
798
 
 
799
<para>The main idea behind the need for this separation into three objects
 
800
(document, view, main window) instead of the minimum of two, the view and the
 
801
main window, is this: what if I want to give the user the possibility to work
 
802
with a file in <emphasis>two</emphasis> or even more views?  Such things can
 
803
even be done within one main window by splitters or deviders, containing two
 
804
view instances which shall both display <emphasis>one</emphasis> file. The
 
805
solution can only be that if the user manipulates the file contents in one view,
 
806
the other view has to be notified about that and to actualize its
 
807
contents. Otherwise a bad scenario will occur: if the user closes one view where
 
808
he added something at the end of the file, which he had cut out at the beginning
 
809
of the file <emphasis>in</emphasis> the other view, the file will be saved later
 
810
still containing the cut section, because if the second and last view did not
 
811
recognize this, it still contains the text without modification from the
 
812
beginning, plus the inserted one. This means that both views have to be
 
813
synchronized in the contents they are displaying, and that can be done if all
 
814
views get notified about each action that the user does, which view he actually
 
815
uses should be irrelevant. So finally a document class is needed to be the one
 
816
and only holder of the true contents of the document and is providing the views
 
817
the possibility to manipulate the contents.</para>
 
818
      
 
819
<para>I hope this has given some insight into this model, although in most cases
 
820
it seems that the programmer can live without it - equally by just using a
 
821
provided class as the view area, or writing a widget on his own to handle user
 
822
interaction, as long as you represent <emphasis>one</emphasis>
 
823
document or file by <emphasis>one</emphasis> view area, the view can
 
824
be responsible for the data as well and only provide methods to retrieve or set
 
825
the document contents for actions like reading a file or saving it. The next
 
826
model to describe, the Multiple Document Interface, will make a difference at
 
827
this point- there you will see the actual need and the functionality the
 
828
Document-View model provides.</para>
 
829
</sect1>
 
830
 
 
831
<sect1 id="the-multiple-document-interface-mdi">
 
832
<title>The Multiple Document Interface (MDI)</title>
 
833
 
 
834
<para>As the last section described the Document-View model, you will probably
 
835
guess what <abbrev>MDI</abbrev> means. Users that come from other Operating
 
836
Systems than Unix/Linux are used to it, as are programmers developing for those
 
837
platforms. X-Window applications traditionally are more targeted towards
 
838
functionality and stability, Unix users are used to single windows that provide
 
839
functionality, therefore even the Document-View model is often not needed to
 
840
create applications. With Qt as a multi-platform toolkit, developers are having
 
841
even more choice - developing for <abbrev>MS</abbrev> Windows(tm) as well as for
 
842
Unix systems. While on Windows the difficult of creating applications that are
 
843
capable of handling so-called child windows has been getting to some kind of
 
844
standard, this is adressed by the Qt 2.1 library, but on the other hand Unix
 
845
users can profit from this architecture as well.</para>
 
846
 
 
847
<para>What is the meaning of <abbrev>MDI</abbrev>? An <abbrev>MDI</abbrev>
 
848
application generally has the same concept of a usual application that has, as
 
849
described above, one application instance and a main window. The view area now
 
850
make the difference: you don't directly use a view that represents data and
 
851
provides interaction to manipulate that data but a view that handles other
 
852
windows looking like top-level windows. These windows are now representing the
 
853
former view area and the main difference is that the interaction chain changes
 
854
from</para>
 
855
      
 
856
<informalexample>
 
857
<para>application instance -&gt; main window -&gt; view</para>
 
858
</informalexample>
 
859
<para>to</para>
 
860
<informalexample>
 
861
<para>application instance -&gt; main window -&gt; view -&gt; active child window</para>
 
862
</informalexample>
 
863
 
 
864
<para>The view now is capable of several actions:</para>
 
865
<itemizedlist>
 
866
<listitem>
 
867
<para>creating as many child windows as the user requests,</para>
 
868
</listitem>
 
869
<listitem>
 
870
<para>providing methods to retrieve the currently active child window,</para>
 
871
</listitem>
 
872
<listitem>
 
873
<para>maintaining a list of open views,</para>
 
874
</listitem>
 
875
<listitem>
 
876
<para>managing the child window behaviour for maximize, minimize, as a window manager does for top-level windows.</para>
 
877
</listitem>
 
878
</itemizedlist>
 
879
 
 
880
<para>Now, you can use "complete" widgets like the
 
881
<classname>QMultiLineEdit</classname> as child windows, for example for an
 
882
application that only provides one window and each child window is responsible
 
883
for it's own data. That could be described as "Multiple Document Interface",
 
884
whereby each child window is equal to a single document. The application then
 
885
manages the usual actions such as providing methods for the child window
 
886
interaction such as cut or copy.</para> 
 
887
 
 
888
<para>Extending this concept with the document-view model enhances the
 
889
possibilities by far: imagine that you can open as many windows as you like
 
890
within the main window, and that a new child window can be a new view of a
 
891
document that is already shown by another child window. The management for this
 
892
requires a separation into the already described three objects model, but
 
893
doesn't limit the actual number of instances of the documents as well as the
 
894
views.</para>
 
895
 
 
896
<para>Fortunately, Qt 2.1 contains the possibility to create such applications,
 
897
and &kdevelop; provides you with the corresponding application frameworks for
 
898
both Qt-only programs, as well as KDE 2 applications, both with the same
 
899
interface methods.  So &kdevelop; is appropriate wether you want to develop for
 
900
either one of these. Using KDE 2 interfaces will offer you still more
 
901
possibilites through library functions as well as inter-process communication,
 
902
but those are special aspects that we are to cover by separate introductions to
 
903
these techniques.</para>
 
904
 
 
905
<para>Now you are prepared for following the development for KDE 2 - just follow
 
906
the next chapter to get a first look at the functionality already provided by
 
907
&kdevelop; when creating applications. There, we will generate the framework for
 
908
our tutorial application <application>KScribble</application> and describe the
 
909
practical aspects of programming <abbrev>MDI</abbrev> applications.</para>
 
910
 
 
911
</sect1>
 
912
</chapter>
 
913
 
 
914
<chapter id="the-mdi-framework">
 
915
<title>The MDI Framework</title>
 
916
 
 
917
<para>If you're already familiar with previous versions of &kdevelop;, you will
 
918
know that your <abbrev>IDE</abbrev> uses so-called "frameworks" as a starting
 
919
point of application development. These frameworks by default contain a support
 
920
for a generic document-view model, but were limited to <abbrev>SDI</abbrev>
 
921
(Single Document Interface, one window with one view area) model
 
922
structures. From &kdevelop; 1.1 on, the application wizard is capable of a lot
 
923
more than the previous versions. It now offers some new project types especially
 
924
for those developers that want to stay up-to-date with the upcoming KDE 2, as
 
925
well as for Qt 2.1.</para>
 
926
 
 
927
<para>One major extension are <abbrev>MDI</abbrev> application frameworks for
 
928
both, KDE 2 and Qt 2.1. These frameworks differ only in the use of some library
 
929
functions such as file dialogs or message boxes as well as the used toolbar and
 
930
statusbar classes - the KDE version uses KDE 2 methods, the Qt version the
 
931
according Qt functions.</para>
 
932
 
 
933
<para>To create the fist step of this tutorial application
 
934
<application>KScribble</application>, be sure that you have followed the
 
935
instructions in chapter 2 of this tutorial handbook: setting up KDE 2. If that
 
936
went all right, nothing can go wrong. If you couldn't set up the KDE 2
 
937
libraries, be sure that you have Qt-2.1 installed and set up &kdevelop; for that
 
938
at least. You can follow this tutorial by choosing the according Qt framework as
 
939
well (which has the differences as mentioned above: other method calls for
 
940
dialogs and <abbrev>GUI</abbrev> components).</para>
 
941
 
 
942
<sect1 id="creating-an-mdi-framework">
 
943
<title>Creating an <abbrev>MDI</abbrev> Framework</title>
 
944
 
 
945
<para>Now we will start jumping into development by creating the frame
 
946
 application for <application>KScribble</application>.</para>
 
947
 
 
948
<para> Start &kdevelop; and choose
 
949
<menuchoice><guimenu>"Project"</guimenu><guimenuitem>"New"</guimenuitem></menuchoice>
 
950
from the menubar, to invoke the application wizard. On the first page, you will
 
951
be shown a tree of project types. These contain KDE and Qt projects. There,
 
952
select <guilabel>"KDE 2 MDI"</guilabel> from the KDE section. If you only have
 
953
Qt 2.1 installed, choose <guilabel>"Qt 2.1 MDI"</guilabel> from the Qt
 
954
section. Then select <guibutton>"Next"</guibutton>, enter "KScribble" as project
 
955
name and "1.0" as version number. Add your name and email address into the
 
956
according fields and you're done. Click on the <guibutton>"Create"</guibutton>
 
957
button and &kdevelop; will generate our first version of
 
958
<application>KScribble</application>, while you can watch the output in the last
 
959
page of the wizard. Finally, press <guibutton>"Exit"</guibutton> to return to
 
960
&kdevelop;. In the output window you will see an additional message showing that
 
961
the messages file has been set up for your project, which will be important to
 
962
translate <application>KScribble</application> into other languages.</para>
 
963
 
 
964
</sect1>
 
965
 
 
966
<sect1 id="overview">
 
967
<title>Overview</title>
 
968
 
 
969
<para>It is important to have an understanding "where to find what" in the
 
970
generated sources, and where your place as a programmer can be found to make
 
971
<application>KScribble</application> a unique KDE application.</para>
 
972
 
 
973
<para>First of all, in the Classviewer you will see three already created
 
974
classes, <classname>KScribbleApp</classname>,
 
975
<classname>KScribbleDoc</classname> and <classname>KScribbleView</classname>. As
 
976
explained above, each of them has a certain part within the application; the App
 
977
class builds the main window and coordinates user interaction, the Doc class
 
978
maintains the documents that an application can manipulate, and finally the View
 
979
class is responsible for user interaction with the child windows and
 
980
communicates with the document connected to it. This has several
 
981
consequences. To make a good use of the provided functionality, the programmer
 
982
is bound to use the given View class. By default, the View inherits
 
983
<classname>QWidget</classname> as a minimum requirement, but you are not limited
 
984
to that at all. Inheriting from another class is not too much work and there is
 
985
also the possibility to use a <classname>QMainWindow</classname>, or
 
986
<classname>KTMainWindow</classname> for example, as the class to inherit and use
 
987
another class that manages the view.</para>
 
988
 
 
989
<para>In the next chapter we'll continue with extending
 
990
<application>KScribble</application> to manage it's documents. After that we'll
 
991
implement the user interaction and you will see the first functionality that is
 
992
unique to our application: we can draw pictures, load and save them.</para>
 
993
 
 
994
</sect1>
 
995
</chapter>
 
996
 
 
997
<chapter id="defining-the-documents">
 
998
<title>Defining the Documents</title>
 
999
 
 
1000
<para>The first step when creating an application based on the Document-View
 
1001
model should always be to think what kind of data the application has to
 
1002
manage. This decides how the view class will look, and especially how the
 
1003
document clas will read and write data to and from files, and offer methods to
 
1004
manipulate the data. As <application>KScribble</application> will be a simple
 
1005
drawing application that operates on graphical data, we will use the Qt class
 
1006
<classname>QPixmap</classname> for storing our paintings while it is
 
1007
edited.</para>
 
1008
 
 
1009
<para><classname>QPixmap</classname> also offers simple methods to read
 
1010
and write pictures into files, so the serialization of the document data is done
 
1011
in just two lines, one for reading and one for writing. Further, we need to
 
1012
define a pen that draws into a document, set it's width and color and make it
 
1013
available for the view class to retrieve the pen.  Actually you want the view
 
1014
offering the drawing methods, but the document as the central element for all
 
1015
views has to hold the pen originally, because two views of the same document
 
1016
would otherwise use different pens!</para>
 
1017
 
 
1018
<para>Therefore to define how our document class should work, we will add one
 
1019
instance of <classname>QPixmap</classname>, one of <classname>QPen</classname>
 
1020
and edit the methods <function>newDocument()</function>,
 
1021
<function>openDocument()</function> and
 
1022
<function>saveDocument()</function>.</para>
 
1023
 
 
1024
<sect1 id="adding-the-instances">
 
1025
<title>Adding the Instances</title>
 
1026
 
 
1027
<para>Open the file <filename>kscribbledoc.h</filename>, by selecting it in one
 
1028
of the fileviewers, or by a click on the classviewer over the class 
 
1029
<classname>KScribbleDoc</classname>.</para>
 
1030
 
 
1031
<para>Then add the lines marked with -&gt; from the following code snippet:</para>
 
1032
 
 
1033
<programlisting>-&gt;  #include &lt;qpixmap.h&gt;
 
1034
-&gt;  #include &lt;qpen.h&gt;
 
1035
 
 
1036
    class KScribbleDoc
 
1037
    {
 
1038
 
 
1039
-&gt;           protected:
 
1040
 
 
1041
-&gt;        QPen currentPen(){ return pen;};   
 
1042
                
 
1043
-&gt;                   int penWidth()
 
1044
-&gt;                           { return pen.width(); }
 
1045
 
 
1046
      public slots:
 
1047
        void updateAllViews(KScribbleView *sender);
 
1048
        
 
1049
        protected:
 
1050
        
 
1051
-&gt;                   QPixmap buffer;
 
1052
        
 
1053
      private:
 
1054
-&gt;                   QPen pen;
 
1055
        /** the modified flag of the current document */
 
1056
        bool modified;</programlisting>
 
1057
 
 
1058
<para>As you see, we added pen and buffer, as well as
 
1059
<function>currentPen()</function> and <function>penWidth()</function>. As pen is
 
1060
declared private, we offer a possibility to retrive the pen as well as the pen
 
1061
width. As these are already implemented within the classdeclaration, we don't
 
1062
have to add them to the implementation file, where we're turning to now.</para>
 
1063
</sect1>
 
1064
 
 
1065
<sect1 id="initialization-of-the-document">
 
1066
<title>Initialization of the Document</title>
 
1067
 
 
1068
<para>Select the method <function>newDocument()</function> in the
 
1069
<classname>KScribbleDoc</classname> class to jump to the method declaration. Here,
 
1070
we're only adding one line, marked with the arrow:</para>
 
1071
 
 
1072
<programlisting>  kscribbledoc.cpp
 
1073
 
 
1074
  bool KScribbleDoc::newDocument()
 
1075
  {
 
1076
    /////////////////////////////////////////////////
 
1077
    // TODO: Add your document initialization code here
 
1078
-&gt;  pen=QPen( Qt::black, 3 );
 
1079
    /////////////////////////////////////////////////
 
1080
    modified=false;
 
1081
    return true;
 
1082
  }</programlisting>
 
1083
 
 
1084
<para>This initializes the pen with the color black and width of 3 pixels; the
 
1085
<classname>QPen</classname> class has some more constructors, but this one suits
 
1086
our needs here.</para>
 
1087
</sect1>
 
1088
 
 
1089
<sect1 id="implementing-the-serialization">
 
1090
<title>Implementing the Serialization</title>
 
1091
 
 
1092
<para>What is left to do is to define how to open and save our pictures. This is
 
1093
done in the according methods:</para>
 
1094
 
 
1095
<programlisting>    
 
1096
bool KScribbleDoc::openDocument(const QString &amp;filename, const char *format /*=0*/)
 
1097
    {
 
1098
 
 
1099
        QFile f( filename );
 
1100
-&gt;     //if ( !f.open( IO_ReadOnly ) )
 
1101
-&gt;     //    return false;
 
1102
     /////////////////////////////////////////////////
 
1103
     // TODO: Add your document opening code here
 
1104
-&gt;     if(!buffer.load( filename, "PNG" ))
 
1105
-&gt;           return false;
 
1106
     /////////////////////////////////////////////////
 
1107
-&gt;     //f.close();
 
1108
 
 
1109
 
 
1110
    bool KScribbleDoc::saveDocument(const QString &amp;filename, const char *format /*=0*/)
 
1111
    {
 
1112
      QFile f( filename );
 
1113
-&gt;     // if ( !f.open( IO_WriteOnly ) )
 
1114
-&gt;     //    return false;
 
1115
 
 
1116
      /////////////////////////////////////////////////
 
1117
      // TODO: Add your document saving code here
 
1118
-&gt;           if(!buffer.save( filename, "PNG" ))
 
1119
-&gt;                   return false;
 
1120
      /////////////////////////////////////////////////
 
1121
 
 
1122
-&gt;      //f.close();
 
1123
</programlisting>
 
1124
 
 
1125
<para>Add the lines marked with the arrow again to your code. What we did here
 
1126
is to comment out the passages where the file <filename>filename</filename> is
 
1127
opened, because that is done automatically by the load and save methods of
 
1128
<classname>QPixmap</classname>, which we add instead. Other documents may open a
 
1129
file and read in its contents such as text lines or whatever, so the
 
1130
<classname>QFile</classname> methods are already present in the codeframe. As
 
1131
<function>save()</function> and <function>load()</function> return a boolean
 
1132
value if the operation was successful, we're returning <varname>false</varname>
 
1133
if not, so the rest of the framework gets a return value and can give out
 
1134
warnings if the operation was not successful.</para>
 
1135
 
 
1136
<para>The <function>load()</function> and <function>save()</function> methods
 
1137
now are already provided in <classname>QPixmap</classname>. They require the
 
1138
filename and the format as argument. The source framework on the other hand
 
1139
<emphasis>does not</emphasis> call the document methods with the format yet. If
 
1140
only one format is used, it sets the format here. Other methods could detect the
 
1141
format, but we will turn to this later. For now, we're using "PNG" as
 
1142
format. See <classname>QImageIO</classname> for more details about the image
 
1143
formats that can be opened.</para>
 
1144
 
 
1145
<para>Now we're already finished defining our document structure. The
 
1146
<classname>QPixmap</classname> buffer serves us as a buffer, storing the
 
1147
original picture contents while we're working on it. The pen is a valid pen for
 
1148
all views connected to the document. Note that the initialization of the pen is
 
1149
done in <function>newDocument()</function>. This method is always called after
 
1150
the constructor within the framework internally, so you should add document
 
1151
instances initializations there as we did with the pen.</para>
 
1152
 
 
1153
<para>In the next chapter we will turn to the view class to define how the view
 
1154
shall cooperate with the user as well as how it accesses the 
 
1155
document - and then we'll be ready to paint!</para>
 
1156
</sect1>
 
1157
</chapter>
 
1158
 
 
1159
<chapter id="defining-the-view">
 
1160
<title>Defining the View</title>
 
1161
 
 
1162
<sect1 id="interactivity-with-the-user">
 
1163
<title>Interactivity with the User</title>
 
1164
 
 
1165
<para>In this chapter we'll turn to the view class of
 
1166
<application>KScribble</application> to define how the child windows shall
 
1167
work. First of all, we notice that <classname>KScribbleView</classname> is
 
1168
derived from <classname>QWidget</classname> by default. That is the minimum
 
1169
requirement for a child window, but it already fulfils our needs.</para>
 
1170
 
 
1171
<para>When it comes to defining a new
 
1172
widget's behaviour, we need to know how the user shall interact with the
 
1173
window. In our example, this would be obviously the mouse. Therefore, we have to
 
1174
overwrite some virtual methods from <classname>QWidget</classname> that process
 
1175
mouse events the widget receives. What we need is to know when the user presses
 
1176
a mouse button, because the drawing shall only take place 
 
1177
when the mouse is pressed. Then we need to know when the mouse is moved (to know
 
1178
where it moves to) as well as when it is released-to 
 
1179
finish the stroke the user has drawn. Further we want our picture to be painted
 
1180
on the window and resized if the user decides to resize 
 
1181
the window he draws into. As members we will also add a
 
1182
<classname>QPointArray</classname> polyline and a boolean value
 
1183
<varname>mousePressed</varname>. Add the code with the 
 
1184
arrow to your include file for the class <classname>KScribbleView</classname>:</para>
 
1185
 
 
1186
<programlisting>   kscribbleview.h
 
1187
 
 
1188
-&gt;   #include &lt;qpointarray.h&gt;
 
1189
 
 
1190
    class KScribbleView
 
1191
    {
 
1192
    .
 
1193
    .
 
1194
     protected:
 
1195
        virtual void closeEvent(QCloseEvent* );
 
1196
 
 
1197
-&gt;           virtual void mousePressEvent( QMouseEvent * );
 
1198
-&gt;           virtual void mouseReleaseEvent( QMouseEvent * );
 
1199
-&gt;           virtual void mouseMoveEvent( QMouseEvent * );
 
1200
-&gt;           virtual void resizeEvent( QResizeEvent * );
 
1201
-&gt;           virtual void paintEvent( QPaintEvent * );
 
1202
        
 
1203
          KScribbleDoc *doc;
 
1204
                
 
1205
-&gt;     private:
 
1206
-&gt;                   bool mousePressed;
 
1207
-&gt;                   QPointArray polyline;
 
1208
 
 
1209
     }</programlisting>
 
1210
</sect1>
 
1211
 
 
1212
<sect1 id="reimplementing-event-handlers">
 
1213
<title>Reimplementing Event Handlers</title>
 
1214
 
 
1215
<para>Now we're coming to the actual implementation of the event handlers. As
 
1216
explained in <ulink url="../kde_libref/index.html">The KDE Library Reference
 
1217
Guide</ulink>, Qt has a good way of handling user events, especially when they
 
1218
target on to widgets. <classname>QWidget</classname> as a baseclass preselects
 
1219
the events, and provides basic event handlers which, as they are declared as
 
1220
virtual, we can overwrite to define how our widget shall react on user
 
1221
actions. One is already overwritten: the <function>closeEvent()</function>
 
1222
method. This is needed because our main window, represented in the App class,
 
1223
already preselects closing child windows and handles this.  Therefore the default
 
1224
event handler, which just accepts the closing, must be overwritten to prevent
 
1225
that happening, and let the App class do the job.</para>
 
1226
 
 
1227
<para>First of all, we have to declare the widget default behavoir in the
 
1228
constructor, by initializing members and setting predefined values:</para>
 
1229
 
 
1230
<programlisting>    kscribbleview.cpp
 
1231
 
 
1232
 
 
1233
    KScribbleView::KScribbleView(KScribbleDoc* pDoc, QWidget *parent, const char* name, int wflags)
 
1234
     : QWidget(parent, name, wflags)
 
1235
    {
 
1236
        doc=pDoc;
 
1237
 
 
1238
-&gt;      setBackgroundMode( QWidget::NoBackground );
 
1239
-&gt;      setCursor( Qt::crossCursor );
 
1240
-&gt;           mousePressed=false;
 
1241
-&gt;      polyline=QPointArray(3);
 
1242
    }</programlisting>
 
1243
 
 
1244
<para>We're setting the background to <constant>NoBackground</constant>, a cursor
 
1245
<constant>(crossCursor)</constant>, and initialize <varname>mousePressed</varname>
 
1246
and <varname>polyline</varname>. Then we'll start implementing our first event
 
1247
handler, <function>mousePressEvent()</function>, to recognize when the user
 
1248
presses the mouse and where:</para>
 
1249
      
 
1250
<note><para>Note: the following implementations have to be inserted completely, so the
 
1251
lines to add are not marked with an arrow!</para></note>
 
1252
 
 
1253
<programlisting>void KScribbleView::mousePressEvent( QMouseEvent *e )
 
1254
{
 
1255
  mousePressed = TRUE;
 
1256
  polyline[2] = polyline[1] = polyline[0] = e-&gt;pos();
 
1257
}</programlisting>
 
1258
 
 
1259
<para>Here, we're setting <varname>mousePressed</varname> to true, so we have
 
1260
stored this event somehow. The second line is not so obvious: we're storing the
 
1261
position where the mouse was pressed into our array's first three elements. As
 
1262
the array is a <classname>QPointArray</classname>, it can store values of the
 
1263
type <classname>QPoint</classname> (which contain an x and y value
 
1264
themselves). What we will do with this array is to store positions of the mouse
 
1265
and create the drawing routine from there in the mouseMoveEvent:</para>
 
1266
 
 
1267
<programlisting>void KScribbleView::mouseMoveEvent( QMouseEvent *e )
 
1268
{
 
1269
  if ( mousePressed ) {
 
1270
                
 
1271
    QPainter painter;
 
1272
    painter.begin( &amp;doc-&gt;buffer );
 
1273
    painter.setPen( doc-&gt;currentPen() );
 
1274
    polyline[2] = polyline[1];
 
1275
    polyline[1] = polyline[0];
 
1276
    polyline[0] = e-&gt;pos();
 
1277
    painter.drawPolyline( polyline );
 
1278
    painter.end();
 
1279
 
 
1280
    QRect r = polyline.boundingRect();
 
1281
    r = r.normalize();
 
1282
    r.setLeft( r.left() - doc-&gt;penWidth() );
 
1283
    r.setTop( r.top() - doc-&gt;penWidth() );
 
1284
    r.setRight( r.right() + doc-&gt;penWidth() );
 
1285
    r.setBottom( r.bottom() + doc-&gt;penWidth() );
 
1286
 
 
1287
          doc-&gt;setModified();
 
1288
    bitBlt( this, r.x(), r.y(), &amp;doc-&gt;buffer, r.x(), r.y(), r.width(), r.height() );
 
1289
  }
 
1290
}</programlisting>
 
1291
 
 
1292
<para>This event handler is probably the most difficult, so we will do a
 
1293
step-by-step walkthrough to understand what's been done.</para>
 
1294
 
 
1295
<para>First of all, the event handler receives all mouse movements over the
 
1296
widget. But as we're only interested in the move if the mouse is pressed,
 
1297
because that is the time to draw, we have to ask if mousePressed is true. That
 
1298
has been done by the <function>mousePressEvent()</function> event handler before,
 
1299
so we don't have to take care of it anymore.</para>
 
1300
 
 
1301
<para> Now we're starting the painting action. First we create a
 
1302
<classname>QPainter</classname> and let it draw into the buffer of the
 
1303
document. This is important, because the document's buffer contains the real
 
1304
contents, the view only acts as a communicator between the document and the
 
1305
user. We get the pen from the document instance as well by calling
 
1306
<function>currentPen()</function>.</para>
 
1307
 
 
1308
<para> The next three lines assign the values inside the polyline
 
1309
<classname>QPoint</classname> array, setting point 2 to 1, 1 to 0 and 0 to the
 
1310
point to where the move went (this is the contents of the event we're interested
 
1311
in). Assuming we've just pressed the mouse (so all three values of the array
 
1312
contain the pressing position) and the first mouse move event appears that
 
1313
contains the first position to draw a line to; this value is moved into the
 
1314
first position in the array again. You may wonder why we need three points in
 
1315
the array then, if we're only interested to draw a line from one position to the
 
1316
next.</para>
 
1317
 
 
1318
<para> The following lines explain that: after drawing into our buffer is
 
1319
finished (with <function>drawPolyline()</function> and
 
1320
<function>painter.end()</function>), we create a rectangle <literal>r</literal>
 
1321
and use <function>boundingRect()</function> from
 
1322
<classname>QPointArray</classname> to get a <classname>QRect</classname> that
 
1323
contains all three points. Therefore we need three values to have a
 
1324
most-complete rectangle.</para>
 
1325
      
 
1326
<para> Then we use <function>normalize()</function> to have the leftmost and
 
1327
topmost values the smallest (as coordinates are counted from top-&gt;bottom and
 
1328
left-&gt;right). The next thing to do is adapt the size of the rectangle by the
 
1329
size of the pen, because the pen has a thickness we get with
 
1330
<function>penWidth()</function> and widen the rectangle by the width of the
 
1331
pen. (Imagine the mouse movement was only two pixels away but the pen thickness
 
1332
is set to ten- then the rectangle wouldn't contain the whole painted
 
1333
area).</para>
 
1334
 
 
1335
<para>Finally, we set the document modified, and use the
 
1336
<function>bitBlt()</function> function to copy the rectangle out of the buffer
 
1337
into the widget. <function>bitBlt</function> operates bitwise, and is very fast,
 
1338
so that it is a good method to copy the painted area from the buffer on the
 
1339
widget instead of repainting the whole window. It's arguments are: first the
 
1340
object to draw to (the destination), here it is our widget, so we have to use
 
1341
the pointer <symbol>this</symbol>.</para>
 
1342
 
 
1343
<para>The next two arguments give the destination topleft position to start
 
1344
copying to, then follows the source to draw from with it's coordinates now
 
1345
including the width and height. As the pixmap coordinates are the same as the
 
1346
coordinates that the widget uses (because our pixmap is drawn into the topleft
 
1347
corner), the coordinates for the source and destination topleft point are the
 
1348
same. This is something to watch out for in some of the next step, so it may be
 
1349
mentioned here already.</para>
 
1350
 
 
1351
<para>Next comes what happens if we release the mouse button. Then the drawing
 
1352
has to stop when we move the mouse again, so we set mousePressed to false here:</para>
 
1353
 
 
1354
<programlisting>void KScribbleView::mouseReleaseEvent( QMouseEvent * ) {
 
1355
        mousePressed = FALSE;
 
1356
}</programlisting>
 
1357
 
 
1358
<para>Now we have finished implementing the user interaction when it comes to
 
1359
the actual drawing operations. The example shows it's not too complicated to use
 
1360
a document-view model. Just create your document instance so that it contains
 
1361
the contents and copy the contents to your view.</para>
 
1362
</sect1>
 
1363
 
 
1364
<sect1 id="painting-and-resizing-the-document">
 
1365
<title>Painting and Resizing the Document</title>
 
1366
 
 
1367
<para>What is left to do are two other virtual event handlers that need a
 
1368
reimplementation. First of all, we have to take care that our picture gets
 
1369
painted into the window when something else happens: when you open another
 
1370
window that obscures the painting - then you change to your painting again, but
 
1371
it won't be there, unless your paint event gets processed to redraw the
 
1372
picture:</para>
 
1373
 
 
1374
<programlisting>void KScribbleView::paintEvent( QPaintEvent *e )
 
1375
{
 
1376
  QWidget::paintEvent( e );
 
1377
 
 
1378
  QRect r = e-&gt;rect();
 
1379
 
 
1380
  bitBlt( this, r.x(), r.y(), &amp;doc-&gt;buffer, r.x(), r.y(), r.width(), r.height() );
 
1381
}</programlisting>
 
1382
 
 
1383
<para>This method also uses <function>bitBlt()</function> to draw the picture from
 
1384
the buffer into the widget.  Here, we only need the rectangle that gets
 
1385
repainted, so we retrieve the geometry from the event (
 
1386
<function>e-&gt;rect()</function> ) and use the coordinates for
 
1387
<function>bitBlt()</function>, just as we did in the
 
1388
<function>mouseMoveEvent()</function>.</para>
 
1389
 
 
1390
<para>The only thing where we didn't do anything about is the size of the
 
1391
pixmap. We didn't set it anywhere - we did not even use the pixmap in the
 
1392
document class except for loading and saving - but these methods aren't called
 
1393
when creating a new picture. So it seems our pixmap doesn't have a size nor a
 
1394
predefined background at all (even if we would have set the size, the contents
 
1395
would be random colors because it is uninitialized).  On the other hand we have
 
1396
the fact that the <classname>KScribbleView</classname> instances get resized
 
1397
when they show up - at least with the minimum size. This is the point where we
 
1398
can add the initialization as well, because the user can change the size
 
1399
manually and the widget will receive a resize event as well. For reasons of
 
1400
simplicity, we want to set the pixmap size the same size the widget has. All
 
1401
this is done in the event handler <function>resizeEvent()</function>:</para>
 
1402
 
 
1403
<programlisting>void KScribbleView::resizeEvent( QResizeEvent *e )
 
1404
{
 
1405
  QWidget::resizeEvent( e );
 
1406
 
 
1407
  int w = width() &gt; doc-&gt;buffer.width() ?
 
1408
  width() : doc-&gt;buffer.width();
 
1409
  int h = height() &gt; doc-&gt;buffer.height() ?
 
1410
  height() : doc-&gt;buffer.height();
 
1411
 
 
1412
  QPixmap tmp( doc-&gt;buffer );
 
1413
  doc-&gt;buffer.resize( w, h );
 
1414
  doc-&gt;buffer.fill( Qt::white );
 
1415
  bitBlt( &amp;doc-&gt;buffer, 0, 0, &amp;tmp, 0, 0, tmp.width(), tmp.height() );
 
1416
}</programlisting>
 
1417
 
 
1418
<para>Here, we first call the <function>resizeEvent</function> handler of
 
1419
<classname>QWidget</classname>. Then we calculate the size of our picture -
 
1420
because we can resize a window to make it smaller or bigger, we have to separate
 
1421
these two cases: if we resize to a smaller geometry, the picture shall still
 
1422
contain it's contents. On the other hand, if we resize to a bigger widget, we
 
1423
have to resize the pixmap as well to that bigger size. The calculated values are
 
1424
stored in w and h. But before the resize takes place, we create a copy of our
 
1425
pixmap, in the document in tmp. Then we resize the buffer (the document), fill it
 
1426
with white color and then copy back the contents from tmp into buffer. This
 
1427
resizes our pixmap always syncronous with the widget that displays it but
 
1428
doesn't lose contents which are outside the visible area, if the resizing 
 
1429
makes the widget smaller.</para>
 
1430
 
 
1431
<para>Now our first application has gained a step where we can test it's
 
1432
functionality. Just hit <guimenuitem>"Run"</guimenuitem> in &kdevelop; and after
 
1433
<application>KScribble</application> shows up, you're ready to paint your first
 
1434
picture with it!</para>
 
1435
 
 
1436
</sect1>
 
1437
</chapter>
 
1438
 
 
1439
<chapter id="extending-the-gui">
 
1440
<title>Extending the GUI</title>
 
1441
 
 
1442
<para>As we have seen, we have already provided
 
1443
<application>KScribble</application> the ability to open and save pictures with
 
1444
the document class, and enabled user interaction by overwriting virtual methods
 
1445
in the view class.  Next we gained the first functionaliy - we can draw
 
1446
pictures. But when we created the <classname>QPen</classname> instance in the
 
1447
document class, we set some pre-defined values for the pen; the color is black
 
1448
and the pen width set to 3 pixels. As you usually want to change these values in
 
1449
a drawing application, we have to enhance the main <abbrev>GUI</abbrev> by
 
1450
providing ways to set these, according to the currently active window and
 
1451
document connected to it. This chapter will therefore introduce you to:</para>
 
1452
 
 
1453
<itemizedlist>
 
1454
<listitem>
 
1455
<para>adding a new menu to the menubar</para>
 
1456
</listitem>
 
1457
<listitem>
 
1458
<para>extending the toolbar with icons for the actions defined in the menubar</para>
 
1459
</listitem>
 
1460
<listitem>
 
1461
<para>creating a new dialog with the &kdevelop; Dialogeditor</para>
 
1462
</listitem>
 
1463
<listitem>
 
1464
<para>connecting the new commands of the menubar and toolbar to calling the dialogs</para>
 
1465
</listitem>
 
1466
<listitem>
 
1467
<para>enabling the document class to let us change the pen values</para>
 
1468
</listitem>
 
1469
</itemizedlist>
 
1470
 
 
1471
<para>Further, we also add a method to delete the document contents at all with
 
1472
a menubar command.</para>
 
1473
 
 
1474
<sect1 id="adding-the-pen-menu">
 
1475
<title>Adding the "Pen" Menu</title>
 
1476
 
 
1477
<para>As the title of this section says, we will add a menu for setting the pen
 
1478
values of the documents here. Menus that are inserted into 
 
1479
the menubar are instances of <classname>QPopupMenu</classname>, and you can have
 
1480
a look at how the current menubar is created when you switch to the 
 
1481
<classname>KScribbleApp</classname> class, method
 
1482
<function>initMenubar()</function>.</para>
 
1483
 
 
1484
<para> You will see that the menubar items are created in the order they appear
 
1485
on the menubar - but this isn't necessary. There are two things important to how
 
1486
the menubar will look like:</para>
 
1487
 
 
1488
<itemizedlist>
 
1489
<listitem>
 
1490
<para>in the menus the order of the menu-items</para>
 
1491
</listitem>
 
1492
<listitem>
 
1493
<para>in the menubar the order of inserting the popup menus.</para>
 
1494
</listitem>
 
1495
</itemizedlist>
 
1496
 
 
1497
<para>Last but not least you have to create menus by calling the
 
1498
constructor. The class declaration already contains the pointers to 
 
1499
the popup menus, so we will have to add our <guimenu>"Pen"</guimenu> menu here first:</para>
 
1500
 
 
1501
<programlisting>kscribbleapp.h
 
1502
 
 
1503
class KScribbleApp
 
1504
{
 
1505
.
 
1506
.
 
1507
  private:
 
1508
    QPopupMenu* pPenMenu;
 
1509
 
 
1510
}</programlisting>
 
1511
 
 
1512
<para>Now we are going to create the menu itself. Change to the implementation
 
1513
of the method <literal>KScribbleApp::initMenuBar()</literal> and add the 
 
1514
lines marked with an arrow:</para>
 
1515
 
 
1516
<programlisting>void KScribbleApp::initMenuBar()
 
1517
{
 
1518
..
 
1519
 
 
1520
-&gt;  ///////////////////////////////////////////////////////////////////
 
1521
-&gt;  // menuBar entry pen-Menu
 
1522
-&gt;  pPenMenu = new QPopupMenu();
 
1523
-&gt;  pPenMenu-&gt;insertItem(i18n("&amp;Color"), ID_PEN_COLOR);
 
1524
-&gt;  pPenMenu-&gt;insertItem(i18n("&amp;Brush"), ID_PEN_BRUSH);
 
1525
 
 
1526
    menuBar()-&gt;insertItem(i18n("&amp;Edit"), pEditMenu);
 
1527
-&gt;  menuBar()-&gt;insertItem(i18n("&amp;Pen"), pPenMenu);
 
1528
    menuBar()-&gt;insertItem(i18n("&amp;View"), pViewMenu);
 
1529
 
 
1530
 
 
1531
-&gt;  connect(pPenMenu, SIGNAL(activated(int)), SLOT(commandCallback(int)));
 
1532
-&gt;  connect(pPenMenu, SIGNAL(highlighted(int)), SLOT(statusCallback(int)));
 
1533
}</programlisting>
 
1534
 
 
1535
<para>You see that we first create the menu with <literal>new
 
1536
QPopupMenu()</literal>. Then we use the <function>insertItem</function> methods
 
1537
to add two menu entries, <guimenuitem>Color</guimenuitem> and
 
1538
<guimenuitem>Brush</guimenuitem>. The visible commands are inserted with the
 
1539
method <function>i18n()</function>, which ensures that you can internationalize
 
1540
your appliction. So as a general rule, you would declare all visual text that
 
1541
will appear later by the method <function>i18n()</function>. Qt-only programs using Qt &gt; 2.0 would use the corresponding method <function>tr()</function> instead of <function>i18n()</function>, as Qt has it's own ways of
 
1542
internationalizing applications.</para>
 
1543
 
 
1544
<para>The second argument is a macro, the <abbrev>ID</abbrev> of the
 
1545
menubar item. This <abbrev>ID</abbrev> is a number that we have to set 
 
1546
using <literal>#define</literal> in the file <filename>resource.h</filename>, where you will see all other already
 
1547
used ID's declared. There are also other ways to insert menus by directly
 
1548
connecting a slot to the inserted entry, but the application framework uses <abbrev>ID</abbrev>'s
 
1549
to select which action has been activated - and highlighted. Therefore each menu
 
1550
entry, independent of the popup menu it appears, has to be a unique number, and
 
1551
as we can hardly remember numbers later, setting a #define for the <abbrev>ID</abbrev> is a 
 
1552
nice solution. The popup menu is now inserted into the menubar with
 
1553
<function>insertItem()</function> as well, and with the pointer to the menu as
 
1554
second argument.</para>
 
1555
 
 
1556
<para>Note that we inserted the popup menu after the <guimenu>"Edit"</guimenu>
 
1557
menu and before the <guimenu>"View"</guimenu> menu, so it will appear between
 
1558
those menus later in the menubar. What is also important when creating menus is
 
1559
that they should be available to the user with shortcuts; ususally in menus you
 
1560
will see underlined characters that the user can jump to directly by pressing
 
1561
<keycap>Alt</keycap>and the appropriate underlined letter of the menuitem. As a
 
1562
programmer, you have to set this character by a leading ampersand, so the
 
1563
<guimenu>"Pen"</guimenu> menu will later be accessible via the keyboard by
 
1564
pressing <keycombo><keycap>Alt</keycap><keycap>P</keycap></keycombo>. Within the
 
1565
menu, the user can press another button to go directly to the command he wants
 
1566
to, so in the menu all items should have this kind of shortcuts as well.</para>
 
1567
 
 
1568
<note><para>Note that you should write item insertions together in groups that
 
1569
have the same visible access, so you can keep a better overview of the
 
1570
characters you already used so that there are no menu accelerators used
 
1571
twice. (this is also important for your translators: in other languages the used
 
1572
accelerator may not be available in the translated word, so they have to set
 
1573
some accelerators again.)</para></note>
 
1574
 
 
1575
<para>In the last two lines we're connecting the pen menu with two slots: one
 
1576
for when the menu signals that it is activated and the action should be
 
1577
executed, and one for when it is highlighted. That allows making a statusbar
 
1578
help message available for the user. You can have a look at the methods the menu
 
1579
is connected to, they contain switch statements where the sent menu
 
1580
<abbrev>ID</abbrev> is compared and the following action called.</para>
 
1581
      
 
1582
<para>What is left to do is to add the #define statements to the file
 
1583
<filename>resource.h</filename>:</para>
 
1584
 
 
1585
<programlisting>resource.h
 
1586
 
 
1587
///////////////////////////////////////////////////////////////////
 
1588
// Pen-menu entries
 
1589
#define ID_PEN_COLOR                14010
 
1590
#define ID_PEN_BRUSH                14020</programlisting>
 
1591
 
 
1592
<para>You will see that the numbers are unique for these entries - you have to
 
1593
watch out not to set the same number for two entries.  If it happens by
 
1594
accident, there's still the compiler to inform you about redefining.</para>
 
1595
      
 
1596
<para>This is currently all you have to do to add a new menu for your
 
1597
menubar. The actions they will execute are: "Color" will call a color 
 
1598
selection dialog, "Brush" will call a dialog (which we still have to create) to
 
1599
select the brush width.</para>
 
1600
 
 
1601
<para>But first we'll extend the toolbar as well by two icons for these actions
 
1602
in the next section.</para>
 
1603
</sect1>
 
1604
 
 
1605
<sect1 id="adding-toolbar-buttons">
 
1606
<title>Adding Toolbar Buttons</title>
 
1607
 
 
1608
<para>Whenever you think that some new commands should be made available by
 
1609
toolbar buttons as well because they are often used and you want to offer
 
1610
additional functionality, you can easily do that by adding buttons in the
 
1611
framework's <function>initToolBar()</function> method of the
 
1612
<classname>App</classname> class. Here, we decide to add a button for both menu
 
1613
entries in the <guimenu>Pen</guimenu> menu, but those need icons - which you can
 
1614
either find in the KDE directory <filename>/toolbar</filename> or, when you
 
1615
don't find an icon that matches your action, have to create yourself.</para>
 
1616
 
 
1617
<para><application>KIconEdit</application> is very suitable to paint icons, so
 
1618
we will first create them. Choose <guimenuitem>"New"</guimenuitem> from the
 
1619
<application>KDevelop</application><guimenu>"File"</guimenu> menu and select
 
1620
<guilabel>"Icon"</guilabel> as the filetype.</para> <para>The first icon will be
 
1621
named "<filename>pencolor.xpm</filename>". Now we have to select where we want
 
1622
to have the icon created in our project directory. Press the directory selection
 
1623
button and change to your project directory containing the
 
1624
<application>KScribble</application> sources. Then create a new directory
 
1625
"<filename>toolbar</filename>". Change to that directory and press
 
1626
<guilabel>"OK"</guilabel>. The new icon will then be created in the new
 
1627
directory "<filename>toolbar</filename>" and will be opened by
 
1628
<application>KIconEdit</application> within &kdevelop; automatically. Paint
 
1629
something that will signalize the user what the button is intended to do, save
 
1630
the pixmap and then switch to the <abbrev>RFV</abbrev> / <abbrev>LFV</abbrev> in
 
1631
&kdevelop;. Select the icon by a <mousebutton>right</mousebutton> mouse button
 
1632
press and select <guimenuitem>"Properties"</guimenuitem> from the popup
 
1633
menu. You will see that the icon is included in the distribution, but for your
 
1634
program to find the icon again later, you have to set the installation
 
1635
destination as well. Check the <guilabel>"install"</guilabel> option and enter
 
1636
into the line now active below:</para>
 
1637
      
 
1638
<para><userinput>$(kde_datadir)/kscribble/toolbar/pencolor.xpm</userinput></para>
 
1639
      
 
1640
<para>This will install the pixmap in the KDE file system hierarchy's data
 
1641
directory, where each application has its subdirectory containing additional
 
1642
files needed by the application. Icons have to be installed into another
 
1643
subdirectory "<filename>toolbar</filename>", so the application's icon loader
 
1644
can find the pixmaps for your program.</para>
 
1645
 
 
1646
<para>After you're finished, repeat all these above steps with the second icon
 
1647
for selecting the pen width. Name this pixmap
 
1648
"<filename>penwidth.xpm</filename>".</para>
 
1649
 
 
1650
<para>Now we only have to insert the buttons into the toolbar; add the lines
 
1651
marked with the arrow into your code:</para>
 
1652
 
 
1653
<programlisting>void KScribbleApp::initToolBar()
 
1654
{
 
1655
..
 
1656
    toolBar()-&gt;insertButton(BarIcon("editcopy"), ID_EDIT_COPY, true, i18n("Copy"));
 
1657
    toolBar()-&gt;insertButton(BarIcon("editpaste"), ID_EDIT_PASTE, true, i18n("Paste"));
 
1658
    toolBar()-&gt;insertSeparator();
 
1659
-&gt;  toolBar()-&gt;insertButton(BarIcon("pencolor"), ID_PEN_COLOR, true, i18n("Color") );
 
1660
-&gt;  toolBar()-&gt;insertButton(BarIcon("penwidth"), ID_PEN_BRUSH, true, i18n("Width") );
 
1661
-&gt;  toolBar()-&gt;insertSeparator();
 
1662
    toolBar()-&gt;insertButton(BarIcon("help"), ID_HELP_CONTENTS, SIGNAL(clicked()),
 
1663
..
 
1664
}</programlisting>
 
1665
 
 
1666
<para>Here, we use the methods of <classname>KToolBar</classname> to insert
 
1667
buttons. The first argument, <function>BarIcon()</function>, tells the method to
 
1668
load the icon for the button. What seems unusual is that we don't have to care
 
1669
for the file extension. The preferred format for KDE 2 is
 
1670
<filename>*.PNG</filename>, but it works with xpm's as well. (You could use
 
1671
<application>ImageMagick</application> for that as well which can do that- or
 
1672
use <application>KScribble</application> in a later step to convert your icons
 
1673
to PNG!)</para>
 
1674
 
 
1675
<para>The second argument is again the <abbrev>ID</abbrev>. The commands are
 
1676
then automatically activated, as the <function>toolBar()</function> is already
 
1677
connected to the same methods as the menubar is for signal
 
1678
<function>activated()</function>. The third argument stands for "available" when
 
1679
true, "deactivated" when false; as we want to have these available, we set this
 
1680
to true. At last, we add a tooltip for the the buttons, which we also embrace
 
1681
with <function>i18n()</function> to allow internationalization.</para>
 
1682
 
 
1683
<para>You're done for now, the <abbrev>GUI</abbrev> is extended at least
 
1684
visually. You can compile and run <application>KScribble</application> again and
 
1685
see how it looks.  Of course the new items in the menubar and toolbar can't
 
1686
execute any action, that is what we're going to add in the next section.  You
 
1687
will also note that the toolbar icons we added are not displayed - which is
 
1688
because we didn't install <application>KScribble</application> and so they can't
 
1689
be found. All other used icons are already shipped with the KDE libraries, so
 
1690
these are already visible.</para>
 
1691
 
 
1692
</sect1>
 
1693
 
 
1694
<sect1 id="creating-the-pen-width-dialog">
 
1695
<title>Creating the Pen Width Dialog</title>
 
1696
 
 
1697
<para>As we�ve already created the according menubar and toolbar commands, we
 
1698
now have to build the first dialog to set the pen width. For this, select
 
1699
<guimenuitem>"New"</guimenuitem> from the KDevelop <guimenu>"File"</guimenu>
 
1700
menu and select <guilabel>"Qt/KDE Dialog"</guilabel>. Then enter the dialog file
 
1701
name as <filename>kpenbrushdlg</filename>.  The extension will be automatically
 
1702
added. Enter <guilabel>"OK"</guilabel> and the dialogeditor opens an empty
 
1703
widget that will be our dialog background.</para>
 
1704
 
 
1705
<para>When constructing a dialog, we have to think about what is really needed
 
1706
by the user.  Here, we need a label to display what will be set, a spinbox with
 
1707
up and down buttons to set the pen width value, and three buttons: one for
 
1708
resetting the pen width to the default value, one to cancel the dialog, and one
 
1709
for taking over the new value - the <guibutton>OK</guibutton> button. In this
 
1710
order we will add the items to the dialog - which is important because the
 
1711
tab-focus follows the order by which the widgets are created. So if you�re
 
1712
starting with the <guibutton>OK</guibutton> button, then the spinbox and then
 
1713
the <guibutton>cancel</guibutton> button, the input focus will change from the
 
1714
<guibutton>ok</guibutton> button to the spinbox, and then to the
 
1715
<guibutton>cancel</guibutton> button - which is not what the user
 
1716
expects.</para>
 
1717
 
 
1718
<para>The tab focus should follow the widget�s items top down, from left to
 
1719
right, so we have to construct the dialog in this order as well. To add items to
 
1720
the dialog, select the <guilabel>"Widgets"</guilabel> tab on the left
 
1721
pane. There you have all available widgets present as icons to construct your
 
1722
dialog. Pressing a widget button will create the new item and place it at the
 
1723
top-left corner of the widget. From there, you can place it with the mouse to
 
1724
the position you would like it to show up. Further, when a widget item is
 
1725
selected, you can set the according values in the <guilabel>"Widget
 
1726
Properties"</guilabel> pane on the right.</para>
 
1727
 
 
1728
<variablelist>
 
1729
<varlistentry>
 
1730
<term>The Label</term> <listitem><para>press the <guilabel>"QLabel"</guilabel>
 
1731
button on the <guilabel>"Widgets"</guilabel> tab and place it at position x:50,
 
1732
y:20. Then select the <guilabel>"General"</guilabel> section in the widget
 
1733
properties pane. Change the text in properity <guilabel>"Text"</guilabel> from
 
1734
<guilabel>"Label"</guilabel> to <guilabel>"Pen Width:"</guilabel>. Adjust the
 
1735
width of the label to a width that matches the label contents in x-direction; a
 
1736
width of 120 should be fine. You can do this either by using the mouse or set
 
1737
the value in the <guilabel>"Geometry"</guilabel> section of the
 
1738
properties.</para>
 
1739
</listitem>
 
1740
</varlistentry>
 
1741
 
 
1742
<varlistentry>
 
1743
<term>The Spinbox</term> 
 
1744
<listitem><para>Press the
 
1745
<guilabel>"QSpinBox"</guilabel> button on the <guilabel>"Widgets"</guilabel> tab
 
1746
and place it at the right of the label we created in the last step. Now set the
 
1747
variable name in section <guilabel>"C++Code"</guilabel> to
 
1748
<guilabel>"width_spbox"</guilabel>. The minimum and maximum values are 1 and
 
1749
100, which should be fine for setting the brush width.</para>
 
1750
</listitem>
 
1751
</varlistentry>
 
1752
 
 
1753
<varlistentry>
 
1754
<term>The Buttons</term> 
 
1755
<listitem><para>Finally, we need the mentioned three
 
1756
buttons. The leftmost button will be the default button. Create a
 
1757
<classname>QPushbutton</classname> and place it somewhere nicely on the bottom of
 
1758
the dialog, set the variable name to <varname>"default_btn"</varname> and the
 
1759
button text to <guilabel>"Default"</guilabel>. Proceed with the
 
1760
<guibutton>OK</guibutton> button with variable name
 
1761
<guibutton>"ok_btn"</guibutton> and the cancel button with variable name
 
1762
<guilabel>"cancel_btn"</guilabel> and set the button text to
 
1763
<guilabel>"&amp;OK"</guilabel> and <guilabel>"&amp;Cancel"</guilabel>.</para>
 
1764
</listitem>
 
1765
</varlistentry>
 
1766
</variablelist>
 
1767
 
 
1768
<para>If you�re fine with the layout of the dialog, choose <guilabel>"Generate
 
1769
complete sources"</guilabel> from the Build menu and set the classname to 
 
1770
"<classname>KPenBrushDlg</classname>", the inheritance to
 
1771
<classname>QDialog</classname>. After pressing <guibutton>"OK"</guibutton>, the
 
1772
sources for the dialog are created and added to the project. Now 
 
1773
you can return to the editor view in &kdevelop; and we can add the code needed
 
1774
to give the dialog some execution purpose.</para>
 
1775
 
 
1776
</sect1>
 
1777
 
 
1778
<sect1 id="connections-and-setting-up">
 
1779
<title>Connections and Setting Up</title>
 
1780
 
 
1781
<para>After we have created the <abbrev>GUI</abbrev> of the dialog, we have to
 
1782
add some functionality to the buttons and provide ways to set and retrieve the 
 
1783
selected value of the spinbox - because we want the dialog to display the
 
1784
current value when it gets called, and to access the selected value when the user
 
1785
pressed the <guibutton>OK</guibutton> button to quit the dialog.</para>
 
1786
 
 
1787
<para>In the generated class for the dialog,
 
1788
<classname>KPenBrushDlg</classname>, you can see one method besides the
 
1789
constructor and the destructor, <function>initDialog()</function>. This method implements the whole
 
1790
<abbrev>GUI</abbrev> construction, so we don�t have to care for that anymore and
 
1791
we can go directly to add the usual connections for the push buttons first. Add
 
1792
the lines marked by arrows to the constructor of the dialog:</para>
 
1793
 
 
1794
<programlisting>KPenBrushDlg::KPenBrushDlg(int curr, QWidget *parent, const char *name) : QDialog(parent,name,true){
 
1795
        initDialog();
 
1796
 
 
1797
-&gt;   connect(default_btn, SIGNAL(clicked()), this, SLOT(slotDefault()));
 
1798
-&gt;   connect(ok_btn, SIGNAL(clicked()), this, SLOT(accept()));
 
1799
-&gt;   connect(cancel_btn, SIGNAL(clicked()), this, SLOT(reject()));
 
1800
}</programlisting>
 
1801
 
 
1802
<para>This provides the functionality for the buttons on the bottom of the
 
1803
dialog when the user clicks the button. First, we set the default button to
 
1804
execute a slot called <function>slotDefault()</function>. This slot is still to be
 
1805
implemented below, where we will set the default value of the spinbox
 
1806
directly.</para>
 
1807
 
 
1808
<para>The second <function>connect()</function> call connects the ok button to
 
1809
call the slot <function>accept()</function> provided by
 
1810
<classname>QDialog</classname>, as well as the <guibutton>cancel</guibutton> 
 
1811
button gets connected to <classname>QDialog</classname>�s slot
 
1812
<function>reject()</function>. This will both close the dialog and will set the
 
1813
result value which we will use later when we implement the method that calls the
 
1814
dialog to determine if we want to use the value set or to ignore any
 
1815
changes.</para>
 
1816
 
 
1817
<para>Now we have to add two methods to set and retrieve the spinbox value:</para>
 
1818
 
 
1819
<programlisting>void setCurrent(int curr){ width_spbox-&gt;setValue(curr); }
 
1820
int width() { return width_spbox-&gt;value(); };</programlisting>
 
1821
 
 
1822
<para>Add these methods to the class declaration with the modifier "public", as
 
1823
we want to set and retrieve the values when we call the dialog to show up. The
 
1824
<function>setCurrent()</function> method will be used to set the current value the
 
1825
pen has, the <function>width()</function> method returns us the selected with when
 
1826
the user presses OK and we want to know which value has been chosen.</para>
 
1827
 
 
1828
<para>Last but not least, we need to implement the <function>slotDefault()</function> method:</para>
 
1829
 
 
1830
<programlisting>//kpenbrushdlg.h:
 
1831
//method declaration:
 
1832
 
 
1833
public slots:
 
1834
  void slotDefault();
 
1835
 
 
1836
//kpenbrushdlg.cpp:
 
1837
//method implementation:
 
1838
 
 
1839
void KPenBrushDlg::slotDefault()
 
1840
{
 
1841
  width_spbox-&gt;setValue(3);
 
1842
}</programlisting>
 
1843
 
 
1844
<para>This will set the default value to 3 pixels for the pen.</para>
 
1845
 
 
1846
<para>Now we�re ready with our first dialog and we can turn to over to the other
 
1847
application classes to adapt some things and add the method calls to invoke the
 
1848
dialog.</para>
 
1849
</sect1>
 
1850
 
 
1851
<sect1 id="calling-the-dialogs">
 
1852
<title>Calling the Dialogs</title>
 
1853
 
 
1854
<para>As you may guess, calling the dialogs means that we will not only
 
1855
implement calling our width selection dialog but also add the method for
 
1856
selecting the pen color, but one after another. First, create a method
 
1857
<function>slotPenBrush()</function> in the class
 
1858
<classname>KScribbleApp</classname>:</para>
 
1859
 
 
1860
<programlisting>void KScribbleApp::slotPenBrush()
 
1861
{
 
1862
  slotStatusMsg(i18n("Setting brush width..."));
 
1863
 
 
1864
  // get one window with document for a current pen width
 
1865
  QWidgetList windows = pWorkspace-&gt;windowList();
 
1866
  KScribbleView* m = (KScribbleView*)windows.at(0);
 
1867
        KScribbleDoc* pDoc = m-&gt;getDocument();
 
1868
  int curr_width=pDoc-&gt;penWidth();
 
1869
 
 
1870
  // create the dialog, get the new width and set the pen width for all documents
 
1871
  KPenBrushDlg* dlg= new KPenBrushDlg(this);
 
1872
  dlg-&gt;setCurrent(curr_width);
 
1873
  if(dlg-&gt;exec()){
 
1874
    int width=dlg-&gt;width();
 
1875
        for ( int i = 0; i &lt; int(windows.count()); ++i )
 
1876
        {
 
1877
        m = (KScribbleView*)windows.at(i);
 
1878
        if ( m )
 
1879
        {
 
1880
                pDoc = m-&gt;getDocument();
 
1881
        pDoc-&gt;setPenWidth(width);
 
1882
        }
 
1883
        }
 
1884
  }
 
1885
  slotStatusMsg(i18n("Ready."));
 
1886
}</programlisting>
 
1887
 
 
1888
<para>Here, we first have to access the window list and retrieve a pointer to a
 
1889
document - which can be a document of any window, because all documents should
 
1890
have the same current pen width. Then we create an integer variable
 
1891
<varname>curr_width</varname> that stores the current pen width.</para>
 
1892
 
 
1893
<para>Now we can call the dialog by creating the dlg instance of
 
1894
<classname>KPenBrushDlg</classname>. Then we set the current pen width by
 
1895
calling <function>dlg-&gt;setCurrent()</function>, which method we added to the
 
1896
dialog.  By calling <function>dlg-&gt;exec()</function> we invoke the dialog. The
 
1897
<literal>if(<varname>m</varname>)</literal> statement ensures that the following code is only
 
1898
executed when the result code of the dialog has the accept flag set - which
 
1899
means, the code is executed if the user pressed the <guibutton>OK</guibutton>
 
1900
button on the dialog.</para>
 
1901
 
 
1902
<para>Assuming the user changed the value and pressed <guibutton>OK</guibutton>,
 
1903
we have to set all documents to use the new pen width. For that we use the
 
1904
<function>for()</function> loop and set every document�s pen width to the width
 
1905
variable we retrieved before with <function>dlg-&gt;width()</function>.</para>
 
1906
 
 
1907
<para>We don�t have implemented the method <function>setPenWidth()</function> in
 
1908
the document class, so we�ll do this right now:</para>
 
1909
 
 
1910
<programlisting>
 
1911
kscribbledoc.h:
 
1912
 
 
1913
public:
 
1914
  void setPenWidth( int w ){ pen.setWidth( w ); }</programlisting>
 
1915
 
 
1916
 
 
1917
<para>What is missing to execute any action is to add the methods that shall be
 
1918
called when the menu items are activated or the toolbar buttons pressed. For
 
1919
this, we have to add the <abbrev>ID</abbrev>�s to the slot
 
1920
<function>commandCallback()</function>, which selects and executes the according
 
1921
methods we want to call if a menu or toolbar item was chosen:</para>
 
1922
 
 
1923
<programlisting>void KScribbleApp::commandCallback(int id_)
 
1924
{
 
1925
  switch (id_)
 
1926
  {
 
1927
    case ID_PEN_BRUSH:
 
1928
      slotPenBrush();
 
1929
      break;
 
1930
 
 
1931
    case ID_PEN_COLOR:
 
1932
      slotPenColor();
 
1933
      break;
 
1934
....
 
1935
  }
 
1936
}</programlisting>
 
1937
 
 
1938
<para>This addition also adds the <literal>slotPenColor()</literal> method to
 
1939
the execution list to set the pen color, which we will implement now:</para>
 
1940
 
 
1941
<programlisting>void KScribbleApp::slotPenColor()
 
1942
{
 
1943
  slotStatusMsg(i18n("Selecting pen color..."));
 
1944
 
 
1945
  QColor myColor;
 
1946
  int result = KColorDialog::getColor( myColor, this );
 
1947
  if ( result == KColorDialog::Accepted )
 
1948
  {
 
1949
    QWidgetList windows = pWorkspace-&gt;windowList();
 
1950
    KScribbleDoc* pDoc;
 
1951
    KScribbleView* m;
 
1952
    for ( int i = 0; i &lt; int(windows.count()); ++i )
 
1953
    {
 
1954
      m = (KScribbleView*)windows.at(i);
 
1955
      if ( m )
 
1956
      {
 
1957
        pDoc = m-&gt;getDocument();
 
1958
        pDoc-&gt;setPenColor(myColor);
 
1959
      }
 
1960
    }
 
1961
  }
 
1962
  slotStatusMsg(i18n("Ready."));
 
1963
}</programlisting>
 
1964
 
 
1965
<para>When looking at the code, we see that we use another new method of
 
1966
<classname>KScribbleDoc</classname> to set the pen color. This one has to be
 
1967
implemented as well:</para>
 
1968
 
 
1969
 
 
1970
<programlisting>kscribbledoc.h:
 
1971
 
 
1972
    /** sets the pen color */
 
1973
    void setPenColor( const QColor &amp;c ){ pen.setColor( c ); }</programlisting>
 
1974
 
 
1975
<para>Watch out for adding the declaration of the two new methods
 
1976
<function>slotPenBrush()</function> and <function>slotPenColor()</function> to the
 
1977
class <classname>KScribbleApp</classname>, so our class knows about these
 
1978
methods.</para>
 
1979
 
 
1980
<para>Now you�re ready! Let�s summarize what we�ve done in this chapter:</para>
 
1981
 
 
1982
<procedure>
 
1983
<step><para> we first added menubar and toolbar commands/items for two dialogs
 
1984
that we want to call;</para></step>
 
1985
<step><para> then we created the first dialog to set the pen width with the
 
1986
KDevelop dialogeditor</para></step>
 
1987
<step><para> after that we created the methods we want to call by the
 
1988
menubar/toolbar items which invoke the dialogs and set the poperties we 
 
1989
wanted to change</para></step>
 
1990
<step><para> finally, we added the needed set functions to the document so we
 
1991
are able to change the values after the dialogs get executed.</para></step>
 
1992
</procedure>
 
1993
 
 
1994
<para>By this structure, you are provided the general way how to extend your
 
1995
application with more functionality and manipulating settings 
 
1996
that influence the behavoir of the document and view interaction.</para>
 
1997
</sect1>
 
1998
</chapter>
 
1999
 
 
2000
<chapter id="extended-views">
 
2001
<title>Extended Views</title>
 
2002
 
 
2003
<para>In this chapter we�re going to extend the functionality of our view widget
 
2004
by two enhancements: syncronized views and scrollviews.</para>
 
2005
 
 
2006
<sect1 id="syncronizing-views">
 
2007
<title>Syncronizing Views</title>
 
2008
 
 
2009
<para>Let�s first explain what this will bring us, and then how we�re going to
 
2010
do it. While playing with <application>KScribble</application>, you may have
 
2011
noticed, that if you open another view of a document by calling
 
2012
<menuchoice><guimenu>"Window"</guimenu><guimenuitem>"New
 
2013
Window"</guimenuitem></menuchoice>, this new view works with the same data as
 
2014
the first view, and does like any other view you create with that command. But
 
2015
when it comes to painting into the document, you can only do that in one view -
 
2016
the other views are not displaying the document contents at the same time. If
 
2017
you obscure one view that doesn�t contain the actual contents with another
 
2018
window and then bring it up to the front again, it will display the acutal
 
2019
contents. That comes because after a widget has been obscured and then activated
 
2020
again, it receives a paint event from the window system, which will call
 
2021
<literal>KScribbleView::paintEvent()</literal> again and that finally redraws
 
2022
the contents of the area that has been obscured. What we want to achieve is that
 
2023
all views should paint syncronous with the one the user actually paints to. In
 
2024
fact, you will see that this enhancement is a really easy task. The document
 
2025
class already provides us a method <function>updateAllViews()</function>, which
 
2026
calls the <function>update()</function> method on each view in the document�s
 
2027
view list. This makes it very easy to syncronize the document contents - every
 
2028
time the contents is changed, here by mouse movements (where we copy the
 
2029
changings to the buffer with <function>bitBlt()</function>), we just have to
 
2030
call updateAllViews(this). The this pointer is needed, because the calling view
 
2031
doesn�t need a repaint and the <function>update()</function> method is only
 
2032
executed if the sender view is not the same as it�s own.</para>
 
2033
      
 
2034
<para>What you�ve got to do here is only to call updateAllViews(this) at the end
 
2035
of the virtual methods <function>mousePressEvent()</function>,
 
2036
<function>mouseMoveEvent()</function> and
 
2037
<function>mouseReleaseEvent()</function> - and you�re done!  Take this as a
 
2038
general rule in your applications: each time the contents of the document is
 
2039
changed by a view, call <function>updateAllViews()</function>. How the update
 
2040
has to be executed has to be implemented in the widget�s
 
2041
<function>update()</function> method; one may be content by setting e.g. the
 
2042
changed text in an editor, in our application we just call
 
2043
<function>repaint()</function>, which generates a paint event and copies the
 
2044
contents of the document into the view again.</para>
 
2045
</sect1>
 
2046
    
 
2047
<sect1 id="scrolled-views">
 
2048
<title>Scrolled Views</title>
 
2049
 
 
2050
<para>In this section we will add a functionality that is most often a thread to
 
2051
developers - if you can�t use an already implemented widget that provides the
 
2052
scrolling already. What does scrolling mean? In our context, the problem begins
 
2053
where we want to open a picture that is bigger than a view can
 
2054
display. therefore, the result will be that you can only see as much as the view
 
2055
provides, beginning from the topleft corner; the rest will be cut away from the
 
2056
user�s view. A scrollview on the other hand is a widget that provides a
 
2057
scrollbar on the right side and on the bottom of the widget by which the user
 
2058
can "move" the contents. In fact, it shows the same size of the document
 
2059
contents, but the view area can be moved within the document, so each part can
 
2060
be displayed if the user wants to by moving the scrollbar sliders up and down,
 
2061
left and right. Fortunately, Qt provides a class
 
2062
<classname>QScrollView</classname> that itself inherits from
 
2063
<classname>QWidget</classname> and offers the same base functionality as an
 
2064
ordinary widget but manages the contents by scrollbars automatically - with the
 
2065
additional option that the programmer can either just use an instance of the
 
2066
<classname>QScrollView</classname>, create the child widgets to manage with the
 
2067
scrollview as parent and add them to the scrollview with
 
2068
<function>addChild()</function> or create a view by inheriting
 
2069
<classname>QScrollView</classname> and draw into the viewport, which is a
 
2070
defined area inside the scrollview, instead of directly to the widget. The
 
2071
difference here is that <classname>QScrollView</classname> provides a set of
 
2072
event handlers similar to the <classname>QWidget</classname> event handlers
 
2073
especially for the viewport. So what was formerly a
 
2074
<function>mousePressEvent()</function> in our view will become a
 
2075
viewportMousePressEvent, a <function>paintEvent()</function> will become a
 
2076
viewportPaintEvent etc. The second possibility will suite our needs to make
 
2077
<application>KScribbleView</application> a scrollable widget and so we will have
 
2078
to make the following modifications:</para>
 
2079
      
 
2080
<procedure>
 
2081
<step><para>first we have to make the document use a size of its contents. This
 
2082
can be done by getting the size for an opened picture, for a 
 
2083
new picture we have to define a default start size. In other painting
 
2084
applications, this size can be changed most often by a command 
 
2085
provided by the user interface, <abbrev>e.g.</abbrev> a dialog that asks for the new width and
 
2086
height as well as a method to shrink the picture 
 
2087
contents to fit into that new size.</para></step>
 
2088
<step><para>changing the inheritance of <classname>KScribbleView</classname>
 
2089
from <classname>QWidget</classname> to
 
2090
<classname>QScrollView</classname></para></step>
 
2091
<step><para>renaming the virtual methods to the according viewport methods of
 
2092
<classname>QScrollView</classname></para></step>
 
2093
<step><para>adapt the virtual event handlers to act on the geometry of the
 
2094
viewport. This means that the old implementation relies on the 
 
2095
geometries of <classname>QWidget</classname> starting at the topleft corner of a
 
2096
widget. If the view is scrolled and the topleft corner is not visible, we 
 
2097
have to ensure the positions retrieved from the <classname>QWidget</classname>
 
2098
coordinates are translated to viewport coordinates</para></step>
 
2099
</procedure>
 
2100
 
 
2101
<sect2 id="sizing-the-document-contents">
 
2102
<title>Sizing the Document Contents</title>
 
2103
 
 
2104
<para>As already mentioned, we have to set a size to the document contents as
 
2105
well as to initialize this size and provide a method to 
 
2106
retrieve the size by the views. For this, we add a variable <varname>QSize
 
2107
size</varname> to <classname>KScribbleDoc</classname> as well as the method 
 
2108
<function>docSize()</function>:</para>
 
2109
 
 
2110
<programlisting>kscribbledoc.h:
 
2111
 
 
2112
#include &lt;qsize.h&gt;
 
2113
 
 
2114
...
 
2115
public:
 
2116
  const QSize docSize(){ return size;};
 
2117
 
 
2118
private:
 
2119
  QSize size;
 
2120
</programlisting>
 
2121
 
 
2122
<para>Now we have to modify all methods that deal with initializing and opening
 
2123
the document contents - <function>newDocument()</function> and
 
2124
<function>openDocument()</function>:</para>
 
2125
 
 
2126
<programlisting>  bool KScribbleDoc::newDocument()
 
2127
  {
 
2128
    /////////////////////////////////////////////////
 
2129
    // TODO: Add your document initialization code here
 
2130
-&gt;  size=QSize(300,200 );
 
2131
        pen=QPen( Qt::black, 3 );
 
2132
-&gt;  buffer.resize(size);
 
2133
-&gt;  buffer.fill( Qt::white );
 
2134
    /////////////////////////////////////////////////
 
2135
    modified=false;
 
2136
    return true;
 
2137
  }
 
2138
 
 
2139
  bool KScribbleDoc::openDocument(const QString &amp;filename, const char *format /*=0*/)
 
2140
  {
 
2141
 
 
2142
        QFile f( filename );
 
2143
  //    if ( !f.open( IO_ReadOnly ) )
 
2144
  //            return false;
 
2145
    /////////////////////////////////////////////////
 
2146
    // TODO: Add your document opening code here
 
2147
        if(!buffer.load( filename, format ))
 
2148
                return false;
 
2149
-&gt;  size=buffer.size();
 
2150
    /////////////////////////////////////////////////
 
2151
  //    f.close();
 
2152
        
 
2153
    modified=false;
 
2154
    m_filename=filename;
 
2155
        m_title=QFileInfo(f).fileName();
 
2156
    return true;
 
2157
  }</programlisting>
 
2158
 
 
2159
<para>In <function>newDocument()</function>, we initialize the size with a default
 
2160
value of 300 pixels wide and 200 pixels high. This is enough for a 
 
2161
small picture for now and we could add a dialog for resizing as well if we want.
 
2162
When it comes to opening a picture, we have to set the size to the size of the picture. This can be done by calling
 
2163
<literal>QPixmap::size()</literal>, which we used in <function>openDocument()</function>. Then we�re done with setting the sizes and we can move on to reimplementing <classname>KScribbleView</classname> and make it a scrollview.</para>
 
2164
</sect2>
 
2165
</sect1>
 
2166
 
 
2167
<sect1 id="adapting-the-view">
 
2168
<title>Adapting the View</title>
 
2169
 
 
2170
<para>As said above, we first have to change some things in the interface of
 
2171
<classname>KScribbleView</classname>. The following code shows these
 
2172
changings:</para>
 
2173
 
 
2174
<programlisting>#include &lt;qscrollview.h&gt;
 
2175
 
 
2176
class KScribbleView : public QScrollView
 
2177
{
 
2178
  Q_OBJECT
 
2179
 
 
2180
  protected:
 
2181
    /** changed from mousePressEvent() overwriting QScrollView method */
 
2182
    virtual void viewportMousePressEvent( QMouseEvent* );
 
2183
    /** changed from mouseReleaseEvent() overwriting QScrollView method */
 
2184
    virtual void viewportMouseReleaseEvent( QMouseEvent* );
 
2185
    /** changed from mouseMoveEvent() overwriting QScrollView method */
 
2186
    virtual void viewportMouseMoveEvent( QMouseEvent* );
 
2187
 
 
2188
    /** commeted out because we have a document size defined */
 
2189
//    resizeEvent( QResizeEvent* );
 
2190
 
 
2191
    /** changed from paintEvent() overwriting QScrollView method */
 
2192
    virtual void viewportPaintEvent( QPaintEvent* );
 
2193
}</programlisting>
 
2194
 
 
2195
<para>Here, we changed the inheritance from <classname>QWidget</classname> to
 
2196
<classname>QScrollView</classname> first and added the according include file we
 
2197
need. Also we changed all implemented event handlers that deal with interaction
 
2198
on the contents of the scrollview to the according methods
 
2199
<classname>QScrollView</classname> provides for this purpose and commented out
 
2200
the resizeEvent. Now we can go over to the implementation of these methods and
 
2201
make use of the size our picture has. As a view is always created after the
 
2202
document exists, we can resize the widget directly in the constructor to fit 
 
2203
this size and as well resize the contents (which is the viewport size):</para>
 
2204
 
 
2205
<programlisting>#include &lt;qsize.h&gt;
 
2206
 
 
2207
KScribbleView::KScribbleView(KScribbleDoc* pDoc, QWidget *parent, const char* name, int wflags)
 
2208
 : QScrollView(parent, name, wflags | WPaintClever | WNorthWestGravity | WRepaintNoErase)
 
2209
{
 
2210
    doc=pDoc;
 
2211
                mousePressed=false;
 
2212
    polyline=QPointArray(3);
 
2213
 
 
2214
-&gt;  setResizePolicy ( QScrollView::ResizeOne );
 
2215
-&gt;  viewport()-&gt;setCursor( Qt::crossCursor );
 
2216
 
 
2217
-&gt;    QSize size=doc-&gt;docSize();
 
2218
      // resize the viewport - this makes the resizeEvent obsolete
 
2219
-&gt;    resizeContents(size.width(), size.height());
 
2220
      // resize the widget to show up with the document size
 
2221
-&gt;    resize(size);
 
2222
}</programlisting>
 
2223
 
 
2224
<para>Note that formerly, the <function>resizeEvent()</function> took
 
2225
care of resizing the drawing area to the same as the widget size. At the same
 
2226
time, this changed the document size as well, so the document picture had always
 
2227
the same size as the widget. With the already initialized size of the document (which we set in <function>newDocument()</function> and <function>openDocument()</function>), we just resize the contents by calling
 
2228
<function>resizeContents()</function> provided by
 
2229
<classname>QScrollView</classname> with the size of the document. You may also
 
2230
notice that we changed the cursor over the widget from the overall widget to the
 
2231
viewport widget, which we can retrieve with <function>viewport()</function>. Now
 
2232
we can reimplement the event handlers. At first, we should take care for the
 
2233
paintEvent, as this is one of the most important ones, because it gets called
 
2234
whenever the widget shows up or is resized.</para>
 
2235
 
 
2236
<important><para>Attention: take care to comment out the <function>resizeEvent()</function> implementation!</para></important>
 
2237
 
 
2238
<para>Now, the paint event will have to copy the pixmap in the buffer to the
 
2239
corresponding position in the view. For this, we have to change the 
 
2240
destination of <function>bitBlt()</function> from this to
 
2241
<function>viewport()</function>, set the topleft position to 0,0 and set the
 
2242
target (the buffer) to  copy from the contentsX and contentsY position on into
 
2243
the viewport:</para>
 
2244
 
 
2245
<programlisting>void KScribbleView::viewportPaintEvent( QPaintEvent *e )
 
2246
{
 
2247
  bitBlt( viewport(),0,0, &amp;doc-&gt;buffer,contentsX() ,contentsY() );
 
2248
}</programlisting>
 
2249
 
 
2250
<para>The <function>contentsX()</function> is the position in the
 
2251
x-direction of the scrollview�s contents - which goes to position 0 in the 
 
2252
viewport�s absolute position, which is the topleft point visible in the
 
2253
scrollview. The same applies to the y-direction. This part is 
 
2254
sometimes hard to understand and you may have to do a bit "trial and error" when
 
2255
implementing your own scrollviews. The other possible 
 
2256
call of <function>bitBlt()</function> would be to switch the values of the
 
2257
positions and inverting the contents values:</para>
 
2258
 
 
2259
<para>bitBlt( viewport(), -contentsX(), -contentsY(), &amp;doc-&gt;buffer, 0, 0 );</para>
 
2260
 
 
2261
<para>The last changes we need to do are changing the mouse event
 
2262
handlers. First, the <function>mouseMoveEvent()</function>, which
 
2263
changes to <function>viewportMouseMoveEvent()</function>, has a
 
2264
<function>bitBlt()</function> call as well. Here, we have to apply the same chages
 
2265
as in the paint event.</para>
 
2266
 
 
2267
<para>Further, in the <function>mousePressEvent()</function> and the
 
2268
<function>mouseMoveEvent()</function>, we have retrieved the position of the mouse
 
2269
events with <literal>e-&gt;pos()</literal>. This position now will deliver us a
 
2270
widget position - not the contents position, so we have to translate this to 
 
2271
draw into the correct position of the document with
 
2272
<function>viewportToContents()</function>:</para>
 
2273
 
 
2274
<programlisting>  void KScribbleView::viewportMousePressEvent( QMouseEvent *e )
 
2275
  {
 
2276
    mousePressed = TRUE;
 
2277
-&gt;  doc-&gt;polyline[2] = doc-&gt;polyline[1] = doc-&gt;polyline[0] = viewportToContents(e-&gt;pos());
 
2278
    doc-&gt;updateAllViews(this);
 
2279
  }
 
2280
 
 
2281
  void KScribbleView::viewportMouseMoveEvent( QMouseEvent *e )
 
2282
  {
 
2283
    if ( mousePressed ) {
 
2284
  ....
 
2285
      doc-&gt;polyline[1] = doc-&gt;polyline[0];
 
2286
-&gt;    doc-&gt;polyline[0] = viewportToContents(e-&gt;pos());
 
2287
      painter.drawPolyline( doc-&gt;polyline );
 
2288
  ....
 
2289
      r.setBottom( r.bottom() + doc-&gt;penWidth() );
 
2290
 
 
2291
          doc-&gt;setModified();
 
2292
-&gt;    bitBlt(viewport(), r.x()-contentsX(), r.y()-contentsY() ,
 
2293
-&gt;            &amp;doc-&gt;buffer, r.x(), r.y(), r.width(), r.height() );
 
2294
          doc-&gt;updateAllViews(this);
 
2295
    }
 
2296
  }</programlisting>
 
2297
 
 
2298
<para>In the <function>viewportMouseMoveEvent()</function>, we had to change the
 
2299
destination again from <literal>this</literal> to <function>viewport()</function>, and
 
2300
with that translate the positions. This time, we used the second version of the
 
2301
call we used in <function>viewportPaintEvent()</function>, with subtracting the
 
2302
contentsX and contentsY values to copy the rectangle containing the current
 
2303
painting into the correct position of the viewport.</para>
 
2304
 
 
2305
<para>At last, we will apply a small change in conjunction with the <function>update()</function> method: why should we repaint the whole widget every time?
 
2306
This will reduce performance and lead to a so-called "flicker"
 
2307
effect. This effect sometimes occurs with widgets, but there are some ways to reduce this behavior. Instead of calling <function>repaint()</function>, we could call <function>repaint(<constant>false</constant>)</function> as well. This
 
2308
will not erase the widget contents before redrawing it. As we copy the document
 
2309
contents directly into the widget, we don�t need to erase it anyway, because all
 
2310
the data will be overwritten anyway. In conjunction with
 
2311
<classname>QScrollView</classname>, we will reduce the painting  
 
2312
even more: we limit the update method to call <function>repaint()</function> on
 
2313
the <function>viewport()</function> widget, because that will call
 
2314
<function>viewportPaintEvent()</function>. On the other hand, the painting area we
 
2315
use is the rectangle containing the document contents, when the 
 
2316
document size is smaller than the viewport size. So we can limit the paint event
 
2317
to the rectangle of the viewport where the document  
 
2318
is displayed, whose visible width and height we can retrieve and compose to the
 
2319
rectangle. Additionally, we use the erase parameter with <literal>false</literal>, 
 
2320
so the document area does not get erased:</para>
 
2321
 
 
2322
<programlisting>void KScribbleView::update(KScribbleView* pSender){
 
2323
  if(pSender != this)
 
2324
    viewport()-&gt;repaint(0,0,visibleWidth(), visibleHeight(), false);
 
2325
}</programlisting>
 
2326
 
 
2327
<para>Now you�re ready!  This chapter has been one of the hardest to implement,
 
2328
and to understand, especially when it comes to the geometries that change. On
 
2329
the other hand, we gave our application a whole new functionality through the new
 
2330
scrollview, and the syncronized views.</para>
 
2331
 
 
2332
<para>With that, we�re moving on to the last chapter of our tutorial. There we 
 
2333
will apply only a few changes, making use of some new methods of the KDE2
 
2334
libraries, but as usual, this will bring us some interesting functionality.
 
2335
<application>KScribble</application> will soon be able to open and save a whole range
 
2336
of picture formats, as we will remove the restriction of operating only
 
2337
on the png file format.</para>
 
2338
 
 
2339
</sect1>
 
2340
</chapter>
 
2341
 
 
2342
<chapter id="using-kimageio-with-kscribble">
 
2343
<title>Using KImageIO with KScribble</title>
 
2344
 
 
2345
<para>When it comes to images, the Qt and KDE libraries offer a wide variety of
 
2346
operations. Besides actual drawing routines, the libraries support a whole set
 
2347
of image formats which they can read and write - all without any cost on our
 
2348
view. The main class for these operations is <classname>QImageIO</classname>,
 
2349
which has a support library by KDE: <classname>KImageIO</classname>. As a
 
2350
preparation before we can make use of these nice methods, we have to add the
 
2351
according library to <application>KScribble</application>:
 
2352
<literal>libkimgio</literal>.</para>
 
2353
 
 
2354
<para> Open
 
2355
<menuchoice><guimenu>"Project"</guimenu><guimenuitem>"Options"</guimenuitem></menuchoice>
 
2356
in &kdevelop; and add the line <userinput>-lkimgio</userinput> to the additional
 
2357
libraries to link <application>KScribble</application> with.</para>
 
2358
 
 
2359
<sect1 id="preparing-the-document">
 
2360
<title>Preparing the Document</title>
 
2361
 
 
2362
<para>Now we can go on and apply our changes. First, we have to remove the
 
2363
current restriction in the document class to only read and write 
 
2364
PNG files. Just replace "PNG" in the following methods with format, as given by
 
2365
the <function>openDocument()</function> and <function>saveDocument()</function> 
 
2366
methods:</para>
 
2367
 
 
2368
<para>In method <literal>KScribbleDoc::openDocument()</literal>:</para>
 
2369
 
 
2370
<para><literal> if(!buffer.load( filename, format ))</literal></para>
 
2371
 
 
2372
<para>In method <literal>KScribbleDoc:: saveDocument()</literal>:</para>
 
2373
 
 
2374
<para><literal> if(!buffer.save( filename, format ))</literal></para>
 
2375
 
 
2376
<para>Then we have a default behavior of these methods. For now we don�t
 
2377
have all available file formats. This will be our next task, together with
 
2378
adapting the slots in <application>KScribble</application> that deliver us
 
2379
filenames.</para>
 
2380
 
 
2381
</sect1>
 
2382
 
 
2383
<sect1 id="registering-file-formats">
 
2384
<title>Registering File Formats</title>
 
2385
 
 
2386
<para>To use <classname>KImageIO</classname>, we have to initialize the library
 
2387
first. For this, we add a call for <function>registerFormats()</function> in our 
 
2388
<function>main()</function> function:</para>
 
2389
 
 
2390
<programlisting>        
 
2391
main.cpp:
 
2392
 
 
2393
............
 
2394
  KApplication app;
 
2395
  KImageIO::registerFormats();
 
2396
 
 
2397
  if (app.isRestored())
 
2398
............</programlisting>
 
2399
 
 
2400
<para>Note that this call is after the application is instanciated with
 
2401
<application>KApplication</application> app - without the application instance, our program will 
 
2402
not run, as <classname>KImageIO</classname> then doen�t know on which
 
2403
application to register the formats. The include file for this call will be
 
2404
added to <filename>kscribble.h</filename>, as we�re going to use some of its methods in <classname>KScribbleApp</classname>:</para>
 
2405
 
 
2406
<programlisting>
 
2407
kscribble.h:
 
2408
 
 
2409
#include &lt;kimgio.h&gt;</programlisting>
 
2410
</sect1>
 
2411
 
 
2412
<sect1 id="opening-images">
 
2413
<title>Opening Images</title>
 
2414
 
 
2415
<para>Now that we can make use of <classname>KImageIO</classname>, we have to
 
2416
apply the first change to the most important method of <classname>KScribbleApp</classname>: 
 
2417
<function>openDocumentFile()</function>. This method opens us any
 
2418
document, but until now only with a filename. It just leaves out the 
 
2419
extension, as the format is not required by the document class by default. But
 
2420
as we have changed that, we just need a format - and have to adapt the call for
 
2421
<literal>KScribbleDoc::openDocument()</literal> in the method <function>openDocumentFile()</function>:</para>
 
2422
 
 
2423
<programlisting>kscribble.cpp:
 
2424
 
 
2425
  void KScribbleApp::openDocumentFile(const char* file)
 
2426
  {
 
2427
        ...........
 
2428
        
 
2429
        else
 
2430
    {
 
2431
-&gt;    QString format=KImageIO::type(file);
 
2432
-&gt;     if(!doc-&gt;openDocument(file,format))
 
2433
                KMessageBox::error (this,i18n("Could not open document !"), i18n("Error !"));
 
2434
                addRecentFile(file);
 
2435
        }
 
2436
    ............
 
2437
  }</programlisting>
 
2438
 
 
2439
<para>Of course, this works the same as using <literal>QString
 
2440
format=QImageIO::imageFormat(file);</literal>. Here, <classname>KImageIO</classname>
 
2441
delivers us the format of the image, and we can call the document to open the
 
2442
file by filename and format. Another possiblity would be to detect the format
 
2443
in the document class as well.</para>
 
2444
 
 
2445
</sect1>
 
2446
 
 
2447
<sect1 id="setting-file-filters-with-kimageio">
 
2448
<title>Setting File Filters with KImageIO</title>
 
2449
 
 
2450
<para>Here, we are finishing our tutorial with the last section - we will adapt
 
2451
the file dialogs of <application>KScribble</application> to make use of file filters. 
 
2452
For these, <classname>KImageIO</classname> provides nice methods to give us the
 
2453
needed strings for all image file formats that are available for opening and 
 
2454
saving. The following implementation replaces the default file filter (which is
 
2455
in fact none - you have to change your own applications� file filter to your
 
2456
mime type accordingly) with the <function>pattern()</function> method
 
2457
of <classname>KImageIO</classname>:</para>
 
2458
 
 
2459
<programlisting>  void KScribbleApp::slotFileOpen()
 
2460
  {
 
2461
    slotStatusMsg(i18n("Opening file..."));
 
2462
        
 
2463
-&gt;    QString fileToOpen=KFileDialog::getOpenFileName(QDir::currentDirPath(),
 
2464
-&gt;              KImageIO::pattern(KImageIO::Reading), this, i18n("Open File..."));
 
2465
    if(!fileToOpen.isEmpty())
 
2466
    {
 
2467
                openDocumentFile(fileToOpen);           
 
2468
    }
 
2469
 
 
2470
    slotStatusMsg(i18n("Ready."));
 
2471
  }</programlisting>
 
2472
 
 
2473
<para>Here, the mode in <function>pattern()</function> is set to Reading - which
 
2474
may differ from the patterns that are retrieved when set to writing. Now 
 
2475
we have finished opening files by its filename and format completely. What is
 
2476
missing to complete this structure, is setting the patterns as well for saving a
 
2477
file. For that, the <function>slotFileSaveAs()</function> is called,
 
2478
which itself invokes the file dialog that retrieves a file name. There, we will
 
2479
set the pattern mode to Writing:</para>
 
2480
 
 
2481
<programlisting>void KScribbleApp::slotFileSaveAs()
 
2482
{
 
2483
  slotStatusMsg(i18n("Saving file with a new filename..."));
 
2484
 
 
2485
-&gt;  QString newName=KFileDialog::getSaveFileName(QDir::currentDirPath(),
 
2486
-&gt;                               KImageIO::pattern(KImageIO::Writing), this, i18n("Save as..."));
 
2487
  if(!newName.isEmpty())
 
2488
  {
 
2489
    KScribbleView* m = (KScribbleView*)pWorkspace-&gt;activeWindow();
 
2490
    if( m )
 
2491
    {
 
2492
      KScribbleDoc* doc =       m-&gt;getDocument();
 
2493
          QString format=QFileInfo(newName).extension();
 
2494
          format=format.upper();
 
2495
                  if(!doc-&gt;saveDocument(newName,format))
 
2496
          {
 
2497
                  KMessageBox::error (this,i18n("Could not save the current document !"), i18n("I/O Error !"));
 
2498
                                return;
 
2499
                        }
 
2500
      doc-&gt;changedViewList();
 
2501
      setWndTitle(m);
 
2502
    }
 
2503
  }
 
2504
  slotStatusMsg(i18n("Ready."));
 
2505
}</programlisting>
 
2506
 
 
2507
</sect1>
 
2508
</chapter>
 
2509
 
 
2510
<chapter id="adding-printing-functionality">
 
2511
<title>Adding Printing Functionality</title>
 
2512
 
 
2513
<para>In this chapter we will show you how easy it is to implement printing
 
2514
functions using Qt. It�s actually just one line of code for us to 
 
2515
do here, but we will start understanding who is actually doing the printing
 
2516
job. When the user presses the print button in <application>KScribble</application> or chooses <guimenuitem>"Print"</guimenuitem> from the <guimenu>"File"</guimenu> menu, the <function>slotFilePrint()</function> method is called in <classname>KScribbleApp</classname>.</para>
 
2517
 
 
2518
<para>
 
2519
This method detects which child window is currently active, and creates a printer
 
2520
instance of the class <classname>QPrinter</classname>. Then it calls the widget�s
 
2521
printing method, <literal>KScribbleView::print()</literal>. Here, the framework
 
2522
already contains the base implementation - which already shows you that for
 
2523
printing you just have to use <classname>QPainter</classname> which then
 
2524
draws on the printer. This method also calls the printing dialog.</para>
 
2525
 
 
2526
<para>What we have to do here is to use <classname>QPainter</classname> methods
 
2527
to draw the pixmap of the document connected to the view. As 
 
2528
<classname>QPainter</classname> already offers a whole set of methods
 
2529
<function>drawPixmap()</function>, we will of course use one of them:</para>
 
2530
 
 
2531
<programlisting>void KScribbleView::print(QPrinter *pPrinter)
 
2532
{
 
2533
  if (pPrinter-&gt;setup(this))
 
2534
  {
 
2535
    QPainter p;
 
2536
    p.begin(pPrinter);
 
2537
                
 
2538
    ///////////////////////////////
 
2539
    // TODO: add your printing code here
 
2540
-&gt;   p.drawPixmap(0,0,doc-&gt;buffer);
 
2541
    ///////////////////////////////
 
2542
    p.end();
 
2543
  }
 
2544
}</programlisting>
 
2545
 
 
2546
<para>Here, we paint into the offset of the printer page at 0,0 with our buffer pixmap of the document. That�s all!</para>
 
2547
 
 
2548
<para>You can just go ahead and test it - now you can print any graphics file that
 
2549
<application>KScribble</application> is able to open.</para>
 
2550
 
 
2551
<para>This is now the end of our tour through creating a KDE 2 application. You
 
2552
can find the source package of <application>KScribble</application> complete with an extension that adds cut, copy, paste, and undo functions, as well as drag�n drop here:</para>
 
2553
 
 
2554
<para><filename>$(KDEDIR)/share/apps/kdevelop/examples/kscribble-1.0.tar.gz</filename></para>
 
2555
 
 
2556
<para>The example tarball is locally installed and can be downloaded to your
 
2557
home directory, where you can untar it and test it.  After untarring the tarball with <command>tar <option>zxvf</option> kscribble-1.0.tar.gz</command>, load the project and call <guimenuitem>"Automake and autoconf"</guimenuitem> from the
 
2558
<guimenu>"Build"</guimenu> menu in &kdevelop;, then call
 
2559
<guimenuitem>"./configure"</guimenuitem> from the same menu. The configure
 
2560
options are those of my installtion of the KDE 2 and Qt 2.1, so you have to
 
2561
change them manually to match your installation path for these options.</para> 
 
2562
 
 
2563
<para>The appendix also contains the complete sourcecode for this package to read through online.</para>
 
2564
</chapter>
 
2565
 
 
2566
<chapter id="copyright">
 
2567
<title>Copyright </title>
 
2568
 
 
2569
<para> <screen>KDevelop Copyright 1998,1999,2000 The KDevelop Team.
 
2570
 
 
2571
This program is free software; you can redistribute it and/or modify
 
2572
it under the terms of the GNU General Public License as published by
 
2573
the Free Software Foundation; either version 2 of the License, or
 
2574
(at your option) any later version.
 
2575
 
 
2576
This program is distributed in the hope that it will be useful,
 
2577
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
2578
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
2579
GNU General Public License for more details.
 
2580
 
 
2581
You should have received a copy of the GNU General Public License
 
2582
along with this program; if not, write to the Free Software
 
2583
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
2584
 
 
2585
<!-- note to self: insert link to GPL -->
 
2586
 
 
2587
</screen>
 
2588
</para>
 
2589
</chapter>
 
2590
 
 
2591
<appendix id="kscribble-1.0-example-sourcecode">
 
2592
<title>KScribble-1.0 Example Sourcecode</title>
 
2593
 
 
2594
<sect1 id="project-tarball">
 
2595
<title>Project Tarball</title>
 
2596
 
 
2597
<para>The example tarball is locally installed and can be downloaded to your
 
2598
home directory, where you can untar it and test it. 
 
2599
After untarring the tarball with <command>tar <option>zxvf</option>
 
2600
kscribble-1.0.tar.gz</command>, load the project and call <guimenuitem>"Automake and
 
2601
autoconf"</guimenuitem> from the 
 
2602
<guimenu>"Build"</guimenu> menu in &kdevelop;, then call
 
2603
<guimenuitem>"./configure"</guimenuitem> from the same menu. The configure
 
2604
options are those of my installtion of the KDE 2 and Qt 2.1, so you have to
 
2605
change them manually to match your installation path for these options.</para>
 
2606
 
 
2607
<para><filename>$(KDEDIR)/share/apps/kdevelop/examples/kscribble-1.0.tar.gz</filename></para>
 
2608
</sect1>
 
2609
 
 
2610
<sect1 id="main.cpp">
 
2611
<title>main.cpp</title>
 
2612
 
 
2613
<programlisting>
 
2614
/***************************************************************************
 
2615
                          main.cpp  -  description
 
2616
                             -------------------
 
2617
    begin                : Mon Jan 31 11:05:05 CET 2000
 
2618
    copyright            : (C) 2000 by Ralf Nolden
 
2619
    email                : Ralf.Nolden@post.rwth-aachen.de
 
2620
 ***************************************************************************/
 
2621
 
 
2622
/***************************************************************************
 
2623
 *                                                                         *
 
2624
 *   This program is free software; you can redistribute it and/or modify  *
 
2625
 *   it under the terms of the GNU General Public License as published by  *
 
2626
 *   the Free Software Foundation; either version 2 of the License, or     *
 
2627
 *   (at your option) any later version.                                   *
 
2628
 *                                                                         *
 
2629
 ***************************************************************************/
 
2630
#include &lt;kcmdlineargs.h&gt;
 
2631
#include &lt;kaboutdata.h&gt;
 
2632
#include &lt;klocale.h&gt;
 
2633
 
 
2634
#include "kscribble.h"
 
2635
 
 
2636
static const char *description =
 
2637
   I18N_NOOP("KDE 2 example application");
 
2638
 
 
2639
static KCmdLineOptions options[] =
 
2640
{
 
2641
   {  "+[File]", I18N_NOOP("image file to open"), 0  },
 
2642
   {  0, 0, 0  }
 
2643
};
 
2644
 
 
2645
 
 
2646
int main(int argc, char *argv[])
 
2647
{
 
2648
   KAboutData aboutData( "kscribble", I18N_NOOP("KScribble"),
 
2649
      VERSION, description, KAboutData::License_GPL,
 
2650
      "(c) 2000, Ralf Nolden");
 
2651
   aboutData.addAuthor("Ralf Nolden",0, "rnolden@kdevelop.de");
 
2652
   KCmdLineArgs::init( argc, argv, &amp;aboutData );
 
2653
   KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
 
2654
 
 
2655
   KApplication app;
 
2656
   KImageIO::registerFormats();
 
2657
 
 
2658
   if (app.isRestored())
 
2659
   {
 
2660
      RESTORE(KScribbleApp);
 
2661
   }
 
2662
   else
 
2663
   {
 
2664
      KScribbleApp *kscribble = new KScribbleApp();
 
2665
      kscribble-&gt;show();
 
2666
 
 
2667
      KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
 
2668
 
 
2669
      if (args-&gt;count())
 
2670
        for(int i=0;i&lt;args-&gt;count();i++)
 
2671
          kscribble-&gt;openDocumentFile(args-&gt;arg(i));
 
2672
      else
 
2673
        kscribble-&gt;openDocumentFile();
 
2674
 
 
2675
      args-&gt;clear();
 
2676
   }
 
2677
 
 
2678
   return app.exec();
 
2679
}</programlisting>
 
2680
</sect1>
 
2681
 
 
2682
<sect1 id="kscribble.h">
 
2683
<title>kscribble.h</title>
 
2684
 
 
2685
<para><programlisting>/***************************************************************************
 
2686
                          kscribble.h  -  description
 
2687
                             -------------------
 
2688
    begin                : Mon Jan 31 11:05:05 CET 2000
 
2689
    copyright            : (C) 2000 by Ralf Nolden
 
2690
    email                : Ralf.Nolden@post.rwth-aachen.de
 
2691
 ***************************************************************************/
 
2692
 
 
2693
/***************************************************************************
 
2694
 *                                                                         *
 
2695
 *   This program is free software; you can redistribute it and/or modify  *
 
2696
 *   it under the terms of the GNU General Public License as published by  *
 
2697
 *   the Free Software Foundation; either version 2 of the License, or     *
 
2698
 *   (at your option) any later version.                                   *
 
2699
 *                                                                         *
 
2700
 ***************************************************************************/
 
2701
 
 
2702
#ifndef KSCRIBBLE_H
 
2703
#define KSCRIBBLE_H
 
2704
 
 
2705
 
 
2706
#ifdef HAVE_CONFIG_H
 
2707
#include &lt;config.h&gt;
 
2708
#endif
 
2709
 
 
2710
// include files for Qt
 
2711
#include &lt;qstrlist.h&gt;
 
2712
#include &lt;qworkspace.h&gt;
 
2713
 
 
2714
// include files for KDE
 
2715
#include &lt;kapp.h&gt;
 
2716
#include &lt;ktmainwindow.h&gt;
 
2717
#include &lt;kaccel.h&gt;
 
2718
#include &lt;kimgio.h&gt;
 
2719
 
 
2720
// forward declaration of the KScribble classes
 
2721
class KScribbleDoc;
 
2722
class KScribbleView;
 
2723
 
 
2724
/**
 
2725
  * The base class for KScribble application windows. It sets up the main
 
2726
  * window and reads the config file as well as providing a menubar, toolbar
 
2727
  * and statusbar. In initView(), your main view is created as the MDI child window manager.
 
2728
  * Child windows are created in createClient(), which gets a document instance as it's document to
 
2729
  * display whereby one document can have several views.The MDI child is an instance of KScribbleView,
 
2730
  * the document an instance of KScribbleDoc.
 
2731
  * KScribbleApp reimplements the methods that KTMainWindow provides for main window handling and supports
 
2732
  * full session management as well as keyboard accelerator configuration by using KAccel.
 
2733
  * @see KTMainWindow
 
2734
  * @see KApplication
 
2735
  * @see KConfig
 
2736
  * @see KAccel
 
2737
  *
 
2738
  * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team.
 
2739
  * @version KDevelop version 1.1 code generation
 
2740
  */
 
2741
class KScribbleApp : public KTMainWindow
 
2742
{
 
2743
  Q_OBJECT
 
2744
 
 
2745
  public:
 
2746
    /** construtor of KScribbleApp, calls all init functions to create the application.
 
2747
     *  @see initMenuBar initToolBar
 
2748
     */
 
2749
    KScribbleApp();
 
2750
    ~KScribbleApp();
 
2751
    /** enables menuentries/toolbar items
 
2752
     */
 
2753
    void enableCommand(int id_);
 
2754
    /** disables menuentries/toolbar items
 
2755
     */
 
2756
    void disableCommand(int id_);
 
2757
    /** opens a file specified by commandline option
 
2758
     */
 
2759
    void openDocumentFile(const char *file=0);
 
2760
 
 
2761
  protected:
 
2762
    /** queryClose is called by KTMainWindow on each closeEvent of a window. Against the
 
2763
     *  default implementation (only returns true), this overridden function retrieves all modified documents
 
2764
     *  from the open document list and asks the user to select which files to save before exiting the application.
 
2765
     *  @see KTMainWindow#queryClose
 
2766
     *  @see KTMainWindow#closeEvent
 
2767
     */
 
2768
    virtual bool queryClose();
 
2769
    /** queryExit is called by KTMainWindow when the last window of the application is going to be closed
 
2770
     *  during the closeEvent().
 
2771
     *  Against the default implementation that just returns true, this calls saveOptions() to save the
 
2772
     *  settings of the last window's properties.
 
2773
     *  @see KTMainWindow#queryExit
 
2774
     *  @see KTMainWindow#closeEvent
 
2775
     */
 
2776
    virtual bool queryExit();
 
2777
    /** saves the window properties for each open window during session end to the session config file,
 
2778
     *  including saving the currently opened file by a temporary filename provided by KApplication.
 
2779
     *  @see KTMainWindow#saveProperties
 
2780
     */
 
2781
    virtual void saveProperties(KConfig *_cfg);
 
2782
    /** reads the session config file and restores the application's state including the last
 
2783
     *  opened files and documents by reading the temporary files saved by saveProperties()
 
2784
     *  @see KTMainWindow#readProperties
 
2785
     */
 
2786
    virtual void readProperties(KConfig *_cfg);
 
2787
    /** event filter to catch close events for MDI child windows and is installed in createClient() on every
 
2788
      * child window. Closing a window calls the eventFilter first which removes the view from the connected
 
2789
      * documents' view list. If the last view is going to be closed, the eventFilter() tests if the document
 
2790
      * is modified; if yes, it asks the user to save the document. If the document title contains "Untitled",
 
2791
      * slotFileSaveAs() gets called to get a save name and path.
 
2792
      */
 
2793
    virtual bool eventFilter(QObject* object, QEvent* event);
 
2794
    /** creates a new child window. The document that will be connected to it
 
2795
     *  has to be created before and the instances filled, with e.g. openDocument().
 
2796
     *  Then call createClient() to get a new MDI child window.
 
2797
     *  @see KScribbleDoc#addView
 
2798
     *  @see KScribbleDoc#openDocument
 
2799
     *  @param doc pointer to the document instance that the view will
 
2800
     *  be connected to.
 
2801
     */
 
2802
    void createClient(KScribbleDoc* doc);
 
2803
    /** accepts drag events for images */
 
2804
    virtual void dragEnterEvent( QDragEnterEvent* );
 
2805
    /** accepts drops and opens a new document
 
2806
     *  for each drop */
 
2807
    virtual void dropEvent( QDropEvent* );
 
2808
 
 
2809
  private slots:
 
2810
    /** sets the main application window title each time the active MDI child window changes. */
 
2811
    void setWndTitle(QWidget*);
 
2812
    /** switch argument for slot selection by menu or toolbar ID */
 
2813
    void commandCallback(int id_);
 
2814
    /** switch argument for Statusbar help entries on slot selection. Add your ID's help
 
2815
     *  here for toolbars and menubar entries. */
 
2816
    void statusCallback(int id_);
 
2817
    /** add a opened file to the recent file list and update recent file menu*/
 
2818
    void addRecentFile(const QString &amp;file);
 
2819
    /** clears the document in the actual view to reuse it as the new document */
 
2820
    void slotFileNew();
 
2821
    /** open a file and load it into the document*/
 
2822
    void slotFileOpen();
 
2823
    /** opens a file from the recent files menu */
 
2824
    void slotFileOpenRecent(int id_);
 
2825
    /** save a document */
 
2826
    void slotFileSave();
 
2827
    /** save a document by a new filename*/
 
2828
    void slotFileSaveAs();
 
2829
    /** asks for saving if the file is modified, then closes the actual file and window*/
 
2830
    void slotFileClose();
 
2831
    /** print the actual file */
 
2832
    void slotFilePrint();
 
2833
    /** closes all documents and quits the application.*/
 
2834
    void slotFileQuit();
 
2835
    /** reverts the last user action for the active window */
 
2836
    void slotEditUndo();
 
2837
    /** put the marked text/object into the clipboard and remove
 
2838
     *  it from the document
 
2839
     */
 
2840
    void slotEditCut();
 
2841
    /** put the marked text/object into the clipboard
 
2842
     */
 
2843
    void slotEditCopy();
 
2844
    /** paste the clipboard into the document
 
2845
     */
 
2846
    void slotEditPaste();
 
2847
    /** clears the current document */
 
2848
    void slotEditClearAll();
 
2849
    /** sets the pen width */
 
2850
    void slotPenBrush();
 
2851
    /** sets the pen color */
 
2852
    void slotPenColor();
 
2853
    /** toggles the toolbar
 
2854
     */
 
2855
    void slotViewToolBar();
 
2856
    /** toggles the statusbar
 
2857
     */
 
2858
    void slotViewStatusBar();
 
2859
    /** creates a new view for the document in the active child window and adds the new view to the
 
2860
     * list of views the document maintains.
 
2861
     */
 
2862
    void slotWindowNewWindow();
 
2863
    /** changes the statusbar contents for the standard label permanently, used to indicate current actions.
 
2864
     * @param text the text that is displayed in the statusbar
 
2865
     */
 
2866
    void slotStatusMsg(const QString &amp;text);
 
2867
    /** changes the status message of the whole statusbar for two seconds, then restores the last status.
 
2868
     * This is used to display statusbar messages that give information about actions for
 
2869
     * toolbar icons and menuentries.
 
2870
     * @param text the text that is displayed in the statusbar
 
2871
     */
 
2872
    void slotStatusHelpMsg(const QString &amp;text);
 
2873
    /** gets called when the window menu is activated; recreates the window menu with all opened window titles. */
 
2874
    void windowMenuAboutToShow();
 
2875
    /** activates the MDI child widget when it gets selected from the window menu. */
 
2876
    void windowMenuActivated( int id );
 
2877
 
 
2878
  private:
 
2879
    /** save general Options like all bar positions and status as well as the geometry and
 
2880
     * the recent file list to the configuration file
 
2881
     */   
 
2882
    void saveOptions();
 
2883
    /** read general Options again and initialize all variables like the recent file list
 
2884
     */
 
2885
    void readOptions();
 
2886
    /** initKeyAccel creates the keyboard accelerator items for the available slots and changes the menu accelerators.
 
2887
     * @see KAccel
 
2888
     */
 
2889
    void initKeyAccel();
 
2890
    /** initMenuBar creates the menubar and inserts the menupopups as well as creating the helpMenu.
 
2891
     */
 
2892
    void initMenuBar();
 
2893
    /** this creates the toolbars.
 
2894
     */
 
2895
    void initToolBar();
 
2896
    /** sets up the statusbar for the main window by initialzing a statuslabel.
 
2897
     */
 
2898
    void initStatusBar();
 
2899
 
 
2900
    /** Creates the main view of the KTMainWindow instance and initializes the MDI view area including any needed
 
2901
     *  connections.
 
2902
     */
 
2903
    void initView();
 
2904
 
 
2905
    /** contains the recently used filenames */
 
2906
    QStrList recentFiles;
 
2907
 
 
2908
    /** the configuration object of the application */
 
2909
    KConfig *config;
 
2910
    /** the key accelerator container */
 
2911
    KAccel *keyAccel;
 
2912
    /** the recent file menu containing the last five opened files */
 
2913
    QPopupMenu *pRecentFileMenu;
 
2914
    /** the file menu */
 
2915
    QPopupMenu* pFileMenu;
 
2916
    /** the edit menu */
 
2917
    QPopupMenu* pEditMenu;
 
2918
    /** the pen menu */
 
2919
    QPopupMenu* pPenMenu;    
 
2920
    /** the view menu */
 
2921
    QPopupMenu* pViewMenu;
 
2922
    /** the window menu */
 
2923
    QPopupMenu *pWindowMenu;
 
2924
    /** pWorkspace is the MDI frame widget that handles MDI child widgets. Inititalized in
 
2925
     * initView()
 
2926
     */
 
2927
    QWorkspace *pWorkspace;
 
2928
    /** the printer instance */
 
2929
    QPrinter *printer;
 
2930
    /** a counter that gets increased each time the user creates a new document with "File"-&gt;"New" */
 
2931
    int untitledCount;
 
2932
    /** a list of all open documents. If the last window of a document gets closed, the installed eventFilter
 
2933
     * removes this document from the list. The document list is checked for modified documents when the user
 
2934
     * is about to close the application. */
 
2935
    QList&lt;KScribbleDoc&gt; *pDocList;  
 
2936
 
 
2937
};
 
2938
 
 
2939
#endif // KSCRIBBLE_H</programlisting>
 
2940
</para>
 
2941
</sect1>
 
2942
 
 
2943
<sect1 id="kscribble.cpp">
 
2944
<title>kscribble.cpp</title>
 
2945
 
 
2946
<para><programlisting>/***************************************************************************
 
2947
                          kscribble.cpp  -  description
 
2948
                             -------------------
 
2949
    begin                : Mon Jan 31 11:05:05 CET 2000
 
2950
    copyright            : (C) 2000 by Ralf Nolden
 
2951
    email                : Ralf.Nolden@post.rwth-aachen.de
 
2952
 ***************************************************************************/
 
2953
 
 
2954
/***************************************************************************
 
2955
 *                                                                         *
 
2956
 *   This program is free software; you can redistribute it and/or modify  *
 
2957
 *   it under the terms of the GNU General Public License as published by  *
 
2958
 *   the Free Software Foundation; either version 2 of the License, or     *
 
2959
 *   (at your option) any later version.                                   *
 
2960
 *                                                                         *
 
2961
 ***************************************************************************/
 
2962
 
 
2963
// include files for QT
 
2964
#include &lt;qdir.h&gt;
 
2965
#include &lt;qprinter.h&gt;
 
2966
#include &lt;qvbox.h&gt;
 
2967
#include &lt;qwhatsthis.h&gt;
 
2968
#include &lt;qtooltip.h&gt;
 
2969
#include &lt;qtoolbutton.h&gt;
 
2970
#include &lt;qimage.h&gt;
 
2971
#include &lt;qdragobject.h&gt;
 
2972
 
 
2973
 
 
2974
// include files for KDE
 
2975
#include &lt;kiconloader.h&gt;
 
2976
#include &lt;kmessagebox.h&gt;
 
2977
#include &lt;kfiledialog.h&gt;
 
2978
#include &lt;kcolordlg.h&gt;
 
2979
#include &lt;kmenubar.h&gt;
 
2980
#include &lt;klocale.h&gt;
 
2981
#include &lt;kconfig.h&gt;
 
2982
 
 
2983
// application specific includes
 
2984
#include "kscribble.h"
 
2985
#include "kscribbleview.h"
 
2986
#include "kscribbledoc.h"
 
2987
#include "resource.h"
 
2988
#include "kpenbrushdlg.h"
 
2989
 
 
2990
 
 
2991
KScribbleApp::KScribbleApp()
 
2992
{
 
2993
  config=kapp-&gt;config();
 
2994
  printer = new QPrinter;
 
2995
  untitledCount=0;
 
2996
  pDocList = new QList&lt;KScribbleDoc&gt;();
 
2997
  pDocList-&gt;setAutoDelete(true);
 
2998
  setAcceptDrops(true);
 
2999
 
 
3000
  ///////////////////////////////////////////////////////////////////
 
3001
  // call inits to invoke all other construction parts
 
3002
  initMenuBar();
 
3003
  initToolBar();
 
3004
  initStatusBar();
 
3005
  initKeyAccel();
 
3006
  initView();
 
3007
  
 
3008
  readOptions();
 
3009
 
 
3010
  ///////////////////////////////////////////////////////////////////
 
3011
  // disable menu and toolbar items at startup
 
3012
  disableCommand(ID_EDIT_UNDO);
 
3013
}
 
3014
 
 
3015
KScribbleApp::~KScribbleApp()
 
3016
{
 
3017
  delete printer;
 
3018
}
 
3019
 
 
3020
void KScribbleApp::initKeyAccel()
 
3021
{
 
3022
  keyAccel = new KAccel(this);
 
3023
  
 
3024
  // fileMenu accelerators
 
3025
  keyAccel-&gt;connectItem(KStdAccel::New, this, SLOT(slotFileNew()));
 
3026
  keyAccel-&gt;connectItem(KStdAccel::Open, this, SLOT(slotFileOpen()));
 
3027
  keyAccel-&gt;connectItem(KStdAccel::Save, this, SLOT(slotFileSave()));
 
3028
  keyAccel-&gt;connectItem(KStdAccel::Close, this, SLOT(slotFileClose()));
 
3029
  keyAccel-&gt;connectItem(KStdAccel::Print, this, SLOT(slotFilePrint()));
 
3030
  keyAccel-&gt;connectItem(KStdAccel::Quit, this, SLOT(slotFileQuit()));
 
3031
  // editMenu accelerators
 
3032
  keyAccel-&gt;connectItem(KStdAccel::Cut, this, SLOT(slotEditCut()));
 
3033
  keyAccel-&gt;connectItem(KStdAccel::Copy, this, SLOT(slotEditCopy()));
 
3034
  keyAccel-&gt;connectItem(KStdAccel::Paste, this, SLOT(slotEditPaste()));
 
3035
 
 
3036
  keyAccel-&gt;connectItem(KStdAccel::Help, this, SLOT(appHelpActivated()));
 
3037
      
 
3038
  keyAccel-&gt;changeMenuAccel(pFileMenu, ID_FILE_NEW, KStdAccel::New);
 
3039
  keyAccel-&gt;changeMenuAccel(pFileMenu, ID_FILE_OPEN, KStdAccel::Open);
 
3040
  keyAccel-&gt;changeMenuAccel(pFileMenu, ID_FILE_SAVE, KStdAccel::Save);
 
3041
  keyAccel-&gt;changeMenuAccel(pFileMenu, ID_FILE_CLOSE, KStdAccel::Close);
 
3042
  keyAccel-&gt;changeMenuAccel(pFileMenu, ID_FILE_PRINT, KStdAccel::Print);
 
3043
  keyAccel-&gt;changeMenuAccel(pFileMenu, ID_FILE_QUIT, KStdAccel::Quit);
 
3044
 
 
3045
  keyAccel-&gt;changeMenuAccel(pEditMenu, ID_EDIT_CUT, KStdAccel::Cut);
 
3046
  keyAccel-&gt;changeMenuAccel(pEditMenu, ID_EDIT_COPY, KStdAccel::Copy);
 
3047
  keyAccel-&gt;changeMenuAccel(pEditMenu, ID_EDIT_PASTE, KStdAccel::Paste);
 
3048
 
 
3049
  keyAccel-&gt;readSettings();  
 
3050
}
 
3051
 
 
3052
void KScribbleApp::initMenuBar()
 
3053
{
 
3054
  ///////////////////////////////////////////////////////////////////
 
3055
  // MENUBAR
 
3056
  pRecentFileMenu = new QPopupMenu(this);
 
3057
  connect(pRecentFileMenu, SIGNAL(activated(int)), SLOT(slotFileOpenRecent(int)));
 
3058
 
 
3059
  ///////////////////////////////////////////////////////////////////
 
3060
  // menuBar entry file-Menu
 
3061
  pFileMenu = new QPopupMenu(this);
 
3062
  pFileMenu-&gt;insertItem(BarIcon("filenew"), i18n("&amp;New"), ID_FILE_NEW);
 
3063
  pFileMenu-&gt;insertItem(BarIcon("fileopen"), i18n("&amp;Open..."), ID_FILE_OPEN);
 
3064
  pFileMenu-&gt;insertItem(i18n("Open &amp;recent"), pRecentFileMenu, ID_FILE_OPEN_RECENT);
 
3065
 
 
3066
  pFileMenu-&gt;insertItem(i18n("&amp;Close"), ID_FILE_CLOSE);
 
3067
  pFileMenu-&gt;insertSeparator();
 
3068
  pFileMenu-&gt;insertItem(BarIcon("filefloppy") ,i18n("&amp;Save"), ID_FILE_SAVE);
 
3069
  pFileMenu-&gt;insertItem(i18n("Save &amp;As..."), ID_FILE_SAVE_AS);
 
3070
  pFileMenu-&gt;insertSeparator();
 
3071
  pFileMenu-&gt;insertItem(BarIcon("fileprint"), i18n("&amp;Print..."), ID_FILE_PRINT);
 
3072
  pFileMenu-&gt;insertSeparator();
 
3073
  pFileMenu-&gt;insertItem(i18n("E&amp;xit"), ID_FILE_QUIT);
 
3074
  
 
3075
  ///////////////////////////////////////////////////////////////////
 
3076
  // menuBar entry edit-Menu
 
3077
  pEditMenu = new QPopupMenu(this);
 
3078
  pEditMenu-&gt;insertItem(BarIcon("undo"), i18n("&amp;Undo"), ID_EDIT_UNDO);
 
3079
  pEditMenu-&gt;insertSeparator();
 
3080
  pEditMenu-&gt;insertItem(BarIcon("editcut"), i18n("Cu&amp;t"), ID_EDIT_CUT);
 
3081
  pEditMenu-&gt;insertItem(BarIcon("editcopy"), i18n("&amp;Copy"), ID_EDIT_COPY);
 
3082
  pEditMenu-&gt;insertItem(BarIcon("editpaste"), i18n("&amp;Paste"), ID_EDIT_PASTE);
 
3083
  pEditMenu-&gt;insertItem(BarIcon("delete"),i18n("&amp;Clear All"), ID_EDIT_CLEAR_ALL);
 
3084
 
 
3085
  ///////////////////////////////////////////////////////////////////
 
3086
  // menuBar entry pen-Menu
 
3087
  pPenMenu = new QPopupMenu();
 
3088
  pPenMenu-&gt;insertItem(i18n("&amp;Color"), ID_PEN_COLOR);
 
3089
  pPenMenu-&gt;insertItem(i18n("&amp;Brush"), ID_PEN_BRUSH);
 
3090
 
 
3091
  ///////////////////////////////////////////////////////////////////
 
3092
  // menuBar entry view-Menu
 
3093
  pViewMenu = new QPopupMenu(this);
 
3094
  pViewMenu-&gt;setCheckable(true);
 
3095
  pViewMenu-&gt;insertItem(i18n("&amp;Toolbar"), ID_VIEW_TOOLBAR);
 
3096
  pViewMenu-&gt;insertItem(i18n("&amp;Statusbar"), ID_VIEW_STATUSBAR);
 
3097
 
 
3098
  ///////////////////////////////////////////////////////////////////
 
3099
  // menuBar entry window-Menu
 
3100
  pWindowMenu = new QPopupMenu(this);
 
3101
  pWindowMenu-&gt;setCheckable(true);
 
3102
 
 
3103
 
 
3104
  ///////////////////////////////////////////////////////////////////
 
3105
  // menuBar entry helpMenu
 
3106
  QPopupMenu* pHelpMenu = helpMenu(i18n("KScribble" VERSION "\n\n(c) 2000 by\n"
 
3107
                                  "Ralf Nolden\nRalf.Nolden@post.rwth-aachen.de"));
 
3108
 
 
3109
  ///////////////////////////////////////////////////////////////////
 
3110
  // MENUBAR CONFIGURATION
 
3111
  // insert your popup menus with the according menubar entries in the order
 
3112
  // they will appear later from left to right
 
3113
  menuBar()-&gt;insertItem(i18n("&amp;File"), pFileMenu);
 
3114
  menuBar()-&gt;insertItem(i18n("&amp;Edit"), pEditMenu);
 
3115
  menuBar()-&gt;insertItem(i18n("&amp;Pen"), pPenMenu);
 
3116
  menuBar()-&gt;insertItem(i18n("&amp;View"), pViewMenu);
 
3117
  menuBar()-&gt;insertItem(i18n("&amp;Window"), pWindowMenu );
 
3118
  menuBar()-&gt;insertItem(i18n("&amp;Help"), pHelpMenu);
 
3119
 
 
3120
  ///////////////////////////////////////////////////////////////////
 
3121
  // CONNECT THE MENU SLOTS WITH SIGNALS
 
3122
  // for execution slots and statusbar messages
 
3123
  connect(pFileMenu, SIGNAL(activated(int)), SLOT(commandCallback(int)));
 
3124
  connect(pFileMenu, SIGNAL(highlighted(int)), SLOT(statusCallback(int)));
 
3125
 
 
3126
  connect(pEditMenu, SIGNAL(activated(int)), SLOT(commandCallback(int)));
 
3127
  connect(pEditMenu, SIGNAL(highlighted(int)), SLOT(statusCallback(int)));
 
3128
 
 
3129
  connect(pPenMenu, SIGNAL(activated(int)), SLOT(commandCallback(int)));
 
3130
  connect(pPenMenu, SIGNAL(highlighted(int)), SLOT(statusCallback(int)));
 
3131
 
 
3132
  connect(pViewMenu, SIGNAL(activated(int)), SLOT(commandCallback(int)));
 
3133
  connect(pViewMenu, SIGNAL(highlighted(int)), SLOT(statusCallback(int)));
 
3134
 
 
3135
  connect(pWindowMenu, SIGNAL(aboutToShow() ), SLOT( windowMenuAboutToShow() ) );
 
3136
  connect(pWindowMenu, SIGNAL(activated(int)), SLOT(commandCallback(int)));
 
3137
  connect(pWindowMenu, SIGNAL(highlighted(int)), SLOT(statusCallback(int)));
 
3138
 
 
3139
}
 
3140
 
 
3141
void KScribbleApp::initToolBar()
 
3142
{
 
3143
 
 
3144
  ///////////////////////////////////////////////////////////////////
 
3145
  // TOOLBAR
 
3146
  toolBar()-&gt;insertButton(BarIcon("filenew"), ID_FILE_NEW, true, i18n("New File"));
 
3147
  toolBar()-&gt;insertButton(BarIcon("fileopen"), ID_FILE_OPEN, true, i18n("Open File"));
 
3148
  toolBar()-&gt;insertButton(BarIcon("filefloppy"), ID_FILE_SAVE, true, i18n("Save File"));
 
3149
  toolBar()-&gt;insertButton(BarIcon("fileprint"), ID_FILE_PRINT, true, i18n("Print"));
 
3150
  toolBar()-&gt;insertSeparator();
 
3151
  toolBar()-&gt;insertButton(BarIcon("editcut"), ID_EDIT_CUT, true, i18n("Cut"));
 
3152
  toolBar()-&gt;insertButton(BarIcon("editcopy"), ID_EDIT_COPY, true, i18n("Copy"));
 
3153
  toolBar()-&gt;insertButton(BarIcon("editpaste"), ID_EDIT_PASTE, true, i18n("Paste"));
 
3154
  toolBar()-&gt;insertSeparator();
 
3155
  toolBar()-&gt;insertButton(BarIcon("pencolor"), ID_PEN_COLOR, true, i18n("Color") );
 
3156
  toolBar()-&gt;insertButton(BarIcon("penwidth"), ID_PEN_BRUSH, true, i18n("Width") );
 
3157
  toolBar()-&gt;insertSeparator();
 
3158
  toolBar()-&gt;insertButton(BarIcon("help"), ID_HELP_CONTENTS, SIGNAL(clicked()),
 
3159
          this, SLOT(appHelpActivated()), true,i18n("Help"));
 
3160
 
 
3161
  QToolButton *btnwhat = QWhatsThis::whatsThisButton(toolBar());
 
3162
  QToolTip::add(btnwhat, i18n("What's this...?"));
 
3163
  toolBar()-&gt;insertWidget(ID_HELP_WHATS_THIS, btnwhat-&gt;sizeHint().width(), btnwhat);
 
3164
 
 
3165
  ///////////////////////////////////////////////////////////////////
 
3166
  // INSERT YOUR APPLICATION SPECIFIC TOOLBARS HERE WITH toolBar(n)
 
3167
 
 
3168
 
 
3169
  ///////////////////////////////////////////////////////////////////
 
3170
  // CONNECT THE TOOLBAR SLOTS WITH SIGNALS - add new created toolbars by their according number
 
3171
  // connect for invoking the slot actions
 
3172
  connect(toolBar(), SIGNAL(clicked(int)), SLOT(commandCallback(int)));
 
3173
  // connect for the status help on holing icons pressed with the mouse button
 
3174
  connect(toolBar(), SIGNAL(pressed(int)), SLOT(statusCallback(int)));
 
3175
 
 
3176
}
 
3177
 
 
3178
void KScribbleApp::initStatusBar()
 
3179
{
 
3180
  ///////////////////////////////////////////////////////////////////
 
3181
  // STATUSBAR
 
3182
  // TODO: add your own items you need for displaying current application status.
 
3183
  statusBar()-&gt;insertItem(i18n("Ready."), ID_STATUS_MSG);
 
3184
}
 
3185
 
 
3186
 
 
3187
void KScribbleApp::initView()
 
3188
{
 
3189
  ////////////////////////////////////////////////////////////////////
 
3190
  // here the main view of the KTMainWindow is created by a background box and
 
3191
  // the QWorkspace instance for MDI view.
 
3192
  QVBox* view_back = new QVBox( this );
 
3193
  view_back-&gt;setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
 
3194
  pWorkspace = new QWorkspace( view_back );
 
3195
  connect(pWorkspace, SIGNAL(windowActivated(QWidget*)), this, SLOT(setWndTitle(QWidget*)));
 
3196
  setView(view_back);
 
3197
}
 
3198
 
 
3199
void KScribbleApp::setWndTitle(QWidget*){
 
3200
  setCaption(pWorkspace-&gt;activeWindow()-&gt;caption());
 
3201
}
 
3202
 
 
3203
void KScribbleApp::enableCommand(int id_)
 
3204
{
 
3205
  ///////////////////////////////////////////////////////////////////
 
3206
  // enable menu and toolbar functions by their ID's
 
3207
  menuBar()-&gt;setItemEnabled(id_, true);
 
3208
  toolBar()-&gt;setItemEnabled(id_, true);
 
3209
}
 
3210
 
 
3211
void KScribbleApp::disableCommand(int id_)
 
3212
{
 
3213
  ///////////////////////////////////////////////////////////////////
 
3214
  // disable menu and toolbar functions by their ID's
 
3215
  menuBar()-&gt;setItemEnabled(id_, false);
 
3216
  toolBar()-&gt;setItemEnabled(id_, false);
 
3217
}
 
3218
 
 
3219
void KScribbleApp::addRecentFile(const QString &amp;file)
 
3220
{
 
3221
  if(recentFiles.contains(file))
 
3222
    return; // it's already there
 
3223
 
 
3224
  if( recentFiles.count() &lt; 5)
 
3225
    recentFiles.prepend(file);
 
3226
  else{
 
3227
    recentFiles.remove(recentFiles.last());
 
3228
    recentFiles.prepend(file);
 
3229
  }
 
3230
 
 
3231
  pRecentFileMenu-&gt;clear();
 
3232
 
 
3233
  for ( int i =0 ; i &lt; (int)recentFiles.count(); i++){
 
3234
    pRecentFileMenu-&gt;insertItem(recentFiles.at(i));
 
3235
  }
 
3236
 
 
3237
}
 
3238
 
 
3239
void KScribbleApp::createClient(KScribbleDoc* doc)
 
3240
{
 
3241
  KScribbleView* w = new KScribbleView(doc, pWorkspace,0,WDestructiveClose);
 
3242
  w-&gt;installEventFilter(this);
 
3243
  doc-&gt;addView(w);
 
3244
  w-&gt;setIcon(kapp-&gt;miniIcon());
 
3245
  if ( pWorkspace-&gt;windowList().isEmpty() ) // show the very first window in maximized mode
 
3246
    w-&gt;showMaximized();
 
3247
  else
 
3248
    w-&gt;show();
 
3249
}
 
3250
 
 
3251
void KScribbleApp::openDocumentFile(const char* file)
 
3252
{
 
3253
  slotStatusMsg(i18n("Opening file..."));
 
3254
  KScribbleDoc* doc;
 
3255
  // check, if document already open. If yes, set the focus to the first view
 
3256
  for(doc=pDocList-&gt;first(); doc &gt; 0; doc=pDocList-&gt;next())
 
3257
  {
 
3258
    if(doc-&gt;pathName()==file)
 
3259
    {
 
3260
       KScribbleView* view=doc-&gt;firstView();  
 
3261
       view-&gt;setFocus();
 
3262
       return;
 
3263
     }
 
3264
  }
 
3265
  doc = new KScribbleDoc();
 
3266
  pDocList-&gt;append(doc);
 
3267
  doc-&gt;newDocument();
 
3268
  // Creates an untitled window if file is 0  
 
3269
  if(!file)
 
3270
  {
 
3271
    untitledCount+=1;
 
3272
    QString fileName=QString(i18n("Untitled%1")).arg(untitledCount);
 
3273
    doc-&gt;setPathName(fileName);
 
3274
    doc-&gt;setTitle(fileName);
 
3275
  }
 
3276
  // Open the file
 
3277
  else
 
3278
  {
 
3279
    QString format=QImageIO::imageFormat(file);
 
3280
    if(!doc-&gt;openDocument(file,format))
 
3281
      KMessageBox::error (this,i18n("Could not open document !"), i18n("Error !"));
 
3282
    addRecentFile(file);
 
3283
  }
 
3284
  // create the window
 
3285
  createClient(doc);
 
3286
 
 
3287
  slotStatusMsg(i18n("Ready."));
 
3288
}
 
3289
 
 
3290
 
 
3291
void KScribbleApp::saveOptions()
 
3292
{  
 
3293
  config-&gt;setGroup("General Options");
 
3294
  config-&gt;writeEntry("Geometry", size());
 
3295
  config-&gt;writeEntry("Show Toolbar", toolBar()-&gt;isVisible());
 
3296
  config-&gt;writeEntry("Show Statusbar",statusBar()-&gt;isVisible());
 
3297
  config-&gt;writeEntry("ToolBarPos", (int) toolBar()-&gt;barPos());
 
3298
  config-&gt;writeEntry("Recent Files", recentFiles);
 
3299
}
 
3300
 
 
3301
 
 
3302
void KScribbleApp::readOptions()
 
3303
{
 
3304
  
 
3305
  config-&gt;setGroup("General Options");
 
3306
 
 
3307
  // bar status settings
 
3308
  bool bViewToolbar = config-&gt;readBoolEntry("Show Toolbar", true);
 
3309
  menuBar()-&gt;setItemChecked(ID_VIEW_TOOLBAR, bViewToolbar);
 
3310
  if(!bViewToolbar)
 
3311
  {
 
3312
     enableToolBar(KToolBar::Hide);
 
3313
  }
 
3314
  
 
3315
  bool bViewStatusbar = config-&gt;readBoolEntry("Show Statusbar", true);
 
3316
  menuBar()-&gt;setItemChecked(ID_VIEW_STATUSBAR, bViewStatusbar);
 
3317
  if(!bViewStatusbar)
 
3318
  {
 
3319
    enableStatusBar(KStatusBar::Hide);
 
3320
  }
 
3321
 
 
3322
  // bar position settings
 
3323
  KToolBar::BarPosition toolBarPos;
 
3324
  toolBarPos=(KToolBar::BarPosition) config-&gt;readNumEntry("ToolBarPos", KToolBar::Top);
 
3325
  toolBar()-&gt;setBarPos(toolBarPos);
 
3326
 
 
3327
  // initialize the recent file list
 
3328
  config-&gt;readListEntry("Recent Files",recentFiles);
 
3329
 
 
3330
  for (int i=0; i &lt; (int) recentFiles.count(); i++)
 
3331
  {
 
3332
    pRecentFileMenu-&gt;insertItem(recentFiles.at(i));
 
3333
  }
 
3334
 
 
3335
  QSize size=config-&gt;readSizeEntry("Geometry");
 
3336
  if(!size.isEmpty())
 
3337
  {
 
3338
    resize(size);
 
3339
  }
 
3340
  else
 
3341
    resize(400,350);
 
3342
 
 
3343
}
 
3344
 
 
3345
void KScribbleApp::saveProperties(KConfig *_cfg)
 
3346
{
 
3347
 
 
3348
}
 
3349
 
 
3350
 
 
3351
void KScribbleApp::readProperties(KConfig* _cfg)
 
3352
{
 
3353
}    
 
3354
 
 
3355
bool KScribbleApp::queryClose()
 
3356
{
 
3357
 
 
3358
  QStringList saveFiles;
 
3359
  KScribbleDoc* doc;
 
3360
  if(pDocList-&gt;isEmpty())
 
3361
    return true;
 
3362
 
 
3363
  for(doc=pDocList-&gt;first(); doc!=0;doc=pDocList-&gt;next()){
 
3364
    if(doc-&gt;isModified())
 
3365
      saveFiles.append(doc-&gt;title());
 
3366
  }
 
3367
  if(saveFiles.isEmpty())
 
3368
    return true;
 
3369
        
 
3370
  switch (KMessageBox::questionYesNoList(this,
 
3371
      i18n("One or more documents have been modified.\nSave changes before exiting?"),saveFiles))     
 
3372
  {
 
3373
    case KMessageBox::Yes:
 
3374
      for(doc=pDocList-&gt;first(); doc!=0;doc=pDocList-&gt;next()){
 
3375
        if(doc-&gt;title().contains(i18n("Untitled")))
 
3376
          slotFileSaveAs();
 
3377
        else
 
3378
        {
 
3379
          if(!doc-&gt;saveDocument(doc-&gt;pathName())){
 
3380
            KMessageBox::error (this,i18n("Could not save the current document !"), i18n("I/O Error !"));
 
3381
            return false;
 
3382
          }
 
3383
        }
 
3384
       }
 
3385
      return true;
 
3386
    case KMessageBox::No:
 
3387
    default:
 
3388
      return true;
 
3389
  }
 
3390
}
 
3391
 
 
3392
bool KScribbleApp::queryExit()
 
3393
{
 
3394
  saveOptions();
 
3395
  return true;
 
3396
}
 
3397
 
 
3398
bool KScribbleApp::eventFilter(QObject* object, QEvent* event){
 
3399
  if(event-&gt;type() == QEvent::Close)
 
3400
  {
 
3401
    QCloseEvent* e=(QCloseEvent*)event;
 
3402
    KScribbleView* pView=(KScribbleView*)object;
 
3403
    KScribbleDoc* pDoc=pView-&gt;getDocument();
 
3404
    if(pDoc-&gt;canCloseFrame(pView))
 
3405
    {
 
3406
       pDoc-&gt;removeView(pView);
 
3407
       if(!pDoc-&gt;firstView())
 
3408
         pDocList-&gt;remove(pDoc);
 
3409
       
 
3410
      e-&gt;accept();
 
3411
      //////////////  
 
3412
      if(pWorkspace-&gt;windowList().count()==1)
 
3413
        setPlainCaption(kapp-&gt;caption());
 
3414
      else
 
3415
        setCaption(pWorkspace-&gt;activeWindow()-&gt;caption());      
 
3416
      //////////////
 
3417
    }
 
3418
    else
 
3419
      e-&gt;ignore();
 
3420
  }
 
3421
  return QWidget::eventFilter( object, event );    // standard event processing
 
3422
}
 
3423
 
 
3424
/////////////////////////////////////////////////////////////////////
 
3425
// SLOT IMPLEMENTATION
 
3426
/////////////////////////////////////////////////////////////////////
 
3427
 
 
3428
 
 
3429
void KScribbleApp::slotFileNew()
 
3430
{
 
3431
  slotStatusMsg(i18n("Creating new document..."));
 
3432
 
 
3433
  openDocumentFile();
 
3434
 
 
3435
  slotStatusMsg(i18n("Ready."));
 
3436
}
 
3437
 
 
3438
void KScribbleApp::slotFileOpen()
 
3439
{
 
3440
  slotStatusMsg(i18n("Opening file..."));
 
3441
  
 
3442
  QString fileToOpen=KFileDialog::getOpenFileName(QDir::currentDirPath(),
 
3443
            KImageIO::pattern(KImageIO::Reading), this, i18n("Open File..."));
 
3444
  if(!fileToOpen.isEmpty())
 
3445
  {
 
3446
    openDocumentFile(fileToOpen);    
 
3447
  }
 
3448
 
 
3449
  slotStatusMsg(i18n("Ready."));
 
3450
}
 
3451
 
 
3452
void KScribbleApp::slotFileOpenRecent(int id_)
 
3453
{
 
3454
  slotStatusMsg(i18n("Opening file..."));
 
3455
    
 
3456
  openDocumentFile(pRecentFileMenu-&gt;text(id_));
 
3457
  
 
3458
  slotStatusMsg(i18n("Ready."));
 
3459
}
 
3460
 
 
3461
void KScribbleApp::slotFileSave()
 
3462
{
 
3463
  slotStatusMsg(i18n("Saving file..."));
 
3464
  KScribbleView* m = (KScribbleView*)pWorkspace-&gt;activeWindow();
 
3465
  if( m )
 
3466
  {
 
3467
    KScribbleDoc* doc =  m-&gt;getDocument();
 
3468
    if(doc-&gt;title().contains(i18n("Untitled")))
 
3469
     slotFileSaveAs();
 
3470
    else
 
3471
      if(!doc-&gt;saveDocument(doc-&gt;pathName()))
 
3472
        KMessageBox::error (this,i18n("Could not save the current document !"), i18n("I/O Error !"));
 
3473
  }
 
3474
  
 
3475
 
 
3476
  slotStatusMsg(i18n("Ready."));
 
3477
}
 
3478
 
 
3479
void KScribbleApp::slotFileSaveAs()
 
3480
{
 
3481
  slotStatusMsg(i18n("Saving file with a new filename..."));
 
3482
 
 
3483
  QString newName=KFileDialog::getSaveFileName(QDir::currentDirPath(),
 
3484
                               KImageIO::pattern(KImageIO::Writing), this, i18n("Save as..."));
 
3485
  if(!newName.isEmpty())
 
3486
  {
 
3487
    KScribbleView* m = (KScribbleView*)pWorkspace-&gt;activeWindow();
 
3488
    if( m )
 
3489
    {
 
3490
      KScribbleDoc* doc =  m-&gt;getDocument();
 
3491
      QString format=QFileInfo(newName).extension();
 
3492
      format=format.upper();
 
3493
      if(!doc-&gt;saveDocument(newName,format))
 
3494
      {
 
3495
        KMessageBox::error (this,i18n("Could not save the current document !"), i18n("I/O Error !"));
 
3496
        return;
 
3497
      }
 
3498
      doc-&gt;changedViewList();
 
3499
      setWndTitle(m);
 
3500
    }
 
3501
    
 
3502
  }
 
3503
 
 
3504
  slotStatusMsg(i18n("Ready."));
 
3505
}
 
3506
 
 
3507
void KScribbleApp::slotFileClose()
 
3508
{
 
3509
  slotStatusMsg(i18n("Closing file..."));
 
3510
  
 
3511
  KScribbleView* m = (KScribbleView*)pWorkspace-&gt;activeWindow();
 
3512
  if( m )
 
3513
  {
 
3514
    KScribbleDoc* doc=m-&gt;getDocument();
 
3515
    doc-&gt;closeDocument();
 
3516
  }
 
3517
 
 
3518
  
 
3519
  slotStatusMsg(i18n("Ready."));
 
3520
}
 
3521
 
 
3522
void KScribbleApp::slotFilePrint()
 
3523
{
 
3524
  slotStatusMsg(i18n("Printing..."));
 
3525
  
 
3526
  KScribbleView* m = (KScribbleView*) pWorkspace-&gt;activeWindow();
 
3527
  if ( m )
 
3528
    m-&gt;print( printer );
 
3529
 
 
3530
  slotStatusMsg(i18n("Ready."));
 
3531
}
 
3532
 
 
3533
void KScribbleApp::slotFileQuit()
 
3534
{
 
3535
  slotStatusMsg(i18n("Exiting..."));
 
3536
  saveOptions();
 
3537
  // close the first window, the list makes the next one the first again.
 
3538
  // This ensures that queryClose() is called on each window to ask for closing
 
3539
  KTMainWindow* w;
 
3540
  if(memberList)
 
3541
  {
 
3542
    for(w=memberList-&gt;first(); w!=0; w=memberList-&gt;first())
 
3543
    {
 
3544
      // only close the window if the closeEvent is accepted. If the user
 
3545
      // presses Cancel on the saveModified() dialog,
 
3546
      // the window and the application stay open.
 
3547
      if(!w-&gt;close())
 
3548
      break;
 
3549
    }
 
3550
  }  
 
3551
  slotStatusMsg(i18n("Ready."));
 
3552
}
 
3553
 
 
3554
void KScribbleApp::slotEditUndo()
 
3555
{
 
3556
  slotStatusMsg(i18n("Reverting last action..."));
 
3557
  
 
3558
  KScribbleView* m = (KScribbleView*) pWorkspace-&gt;activeWindow();
 
3559
  if ( m )
 
3560
//    m-&gt;undo();
 
3561
 
 
3562
  slotStatusMsg(i18n("Ready."));
 
3563
}
 
3564
 
 
3565
void KScribbleApp::slotEditCut()
 
3566
{
 
3567
  slotStatusMsg(i18n("Cutting selection..."));
 
3568
  
 
3569
  KScribbleView* m = (KScribbleView*) pWorkspace-&gt;activeWindow();
 
3570
  if ( m )
 
3571
    m-&gt;cutSelection();  
 
3572
 
 
3573
  slotStatusMsg(i18n("Ready."));
 
3574
}
 
3575
 
 
3576
void KScribbleApp::slotEditCopy()
 
3577
{
 
3578
  slotStatusMsg(i18n("Copying selection to clipboard..."));
 
3579
  
 
3580
  KScribbleView* m = (KScribbleView*) pWorkspace-&gt;activeWindow();
 
3581
  if ( m )
 
3582
    m-&gt;copySelection();
 
3583
    
 
3584
  slotStatusMsg(i18n("Ready."));
 
3585
}
 
3586
 
 
3587
void KScribbleApp::slotEditPaste()
 
3588
{
 
3589
  slotStatusMsg(i18n("Inserting clipboard contents..."));
 
3590
  
 
3591
  KScribbleView* m = (KScribbleView*) pWorkspace-&gt;activeWindow();
 
3592
  if ( m )
 
3593
    m-&gt;pasteSelection();
 
3594
    
 
3595
  slotStatusMsg(i18n("Ready."));
 
3596
}
 
3597
 
 
3598
void KScribbleApp::slotEditClearAll()
 
3599
{
 
3600
  slotStatusMsg(i18n("Clearing the document contents..."));
 
3601
  
 
3602
  KScribbleView* m = (KScribbleView*) pWorkspace-&gt;activeWindow();
 
3603
  if ( m ){
 
3604
    KScribbleDoc* pDoc = m-&gt;getDocument();
 
3605
    pDoc-&gt;editClearAll();
 
3606
  }
 
3607
  slotStatusMsg(i18n("Ready."));
 
3608
}
 
3609
 
 
3610
void KScribbleApp::slotPenBrush()
 
3611
{
 
3612
  slotStatusMsg(i18n("Setting brush width..."));
 
3613
 
 
3614
  // get one window with document for a current pen width
 
3615
  QWidgetList windows = pWorkspace-&gt;windowList();
 
3616
  KScribbleView* m = (KScribbleView*)windows.at(0);
 
3617
  KScribbleDoc* pDoc = m-&gt;getDocument();
 
3618
  int curr_width=pDoc-&gt;penWidth();
 
3619
 
 
3620
  // create the dialog, get the new width and set the pen width for all documents
 
3621
  KPenBrushDlg* dlg= new KPenBrushDlg(curr_width,this);
 
3622
  if(dlg-&gt;exec()){
 
3623
    int width=dlg-&gt;width();
 
3624
    for ( int i = 0; i &lt; int(windows.count()); ++i )
 
3625
    {
 
3626
      m = (KScribbleView*)windows.at(i);
 
3627
      if ( m )
 
3628
      {
 
3629
        pDoc = m-&gt;getDocument();
 
3630
        pDoc-&gt;setPenWidth(width);
 
3631
      }
 
3632
    }
 
3633
  }
 
3634
  slotStatusMsg(i18n("Ready."));
 
3635
}
 
3636
 
 
3637
void KScribbleApp::slotPenColor()
 
3638
{
 
3639
  slotStatusMsg(i18n("Selecting pen color..."));
 
3640
 
 
3641
  QColor myColor;
 
3642
  int result = KColorDialog::getColor( myColor, this );
 
3643
  if ( result == KColorDialog::Accepted )
 
3644
  {
 
3645
    QWidgetList windows = pWorkspace-&gt;windowList();
 
3646
    KScribbleDoc* pDoc;
 
3647
    KScribbleView* m;
 
3648
    for ( int i = 0; i &lt; int(windows.count()); ++i )
 
3649
    {
 
3650
      m = (KScribbleView*)windows.at(i);
 
3651
      if ( m )
 
3652
      {
 
3653
        pDoc = m-&gt;getDocument();
 
3654
        pDoc-&gt;setPenColor(myColor);
 
3655
      }
 
3656
    }
 
3657
  }
 
3658
  slotStatusMsg(i18n("Ready."));
 
3659
}
 
3660
 
 
3661
 
 
3662
void KScribbleApp::slotViewToolBar()
 
3663
{
 
3664
  slotStatusMsg(i18n("Toggle the toolbar..."));
 
3665
  ///////////////////////////////////////////////////////////////////
 
3666
  // turn Toolbar on or off
 
3667
  if( menuBar()-&gt;isItemChecked(ID_VIEW_TOOLBAR))
 
3668
  {
 
3669
    menuBar()-&gt;setItemChecked(ID_VIEW_TOOLBAR, false);
 
3670
    enableToolBar(KToolBar::Hide);
 
3671
  }
 
3672
  else
 
3673
  {
 
3674
    menuBar()-&gt;setItemChecked(ID_VIEW_TOOLBAR, true);
 
3675
    enableToolBar(KToolBar::Show);
 
3676
  }    
 
3677
 
 
3678
  slotStatusMsg(i18n("Ready."));
 
3679
}
 
3680
 
 
3681
void KScribbleApp::slotViewStatusBar()
 
3682
{
 
3683
  slotStatusMsg(i18n("Toggle the statusbar..."));
 
3684
  ///////////////////////////////////////////////////////////////////
 
3685
  //turn Statusbar on or off
 
3686
  if( menuBar()-&gt;isItemChecked(ID_VIEW_STATUSBAR))
 
3687
  {
 
3688
    menuBar()-&gt;setItemChecked(ID_VIEW_STATUSBAR, false);
 
3689
    enableStatusBar(KStatusBar::Hide);
 
3690
  }
 
3691
  else
 
3692
  {
 
3693
    menuBar()-&gt;setItemChecked(ID_VIEW_STATUSBAR, true);
 
3694
    enableStatusBar(KStatusBar::Show);
 
3695
  }
 
3696
 
 
3697
  slotStatusMsg(i18n("Ready."));
 
3698
}
 
3699
 
 
3700
void KScribbleApp::slotWindowNewWindow()
 
3701
{
 
3702
  slotStatusMsg(i18n("Opening a new application window..."));
 
3703
  
 
3704
  KScribbleView* m = (KScribbleView*) pWorkspace-&gt;activeWindow();
 
3705
  if ( m ){
 
3706
     KScribbleDoc* doc = m-&gt;getDocument();
 
3707
    createClient(doc);
 
3708
  }
 
3709
 
 
3710
  slotStatusMsg(i18n("Ready."));
 
3711
}
 
3712
 
 
3713
void KScribbleApp::slotStatusMsg(const QString &amp;text)
 
3714
{
 
3715
  ///////////////////////////////////////////////////////////////////
 
3716
  // change status message permanently
 
3717
  statusBar()-&gt;clear();
 
3718
  statusBar()-&gt;changeItem(text, ID_STATUS_MSG);
 
3719
}
 
3720
 
 
3721
 
 
3722
void KScribbleApp::slotStatusHelpMsg(const QString &amp;text)
 
3723
{
 
3724
  ///////////////////////////////////////////////////////////////////
 
3725
  // change status message of whole statusbar temporary (text, msec)
 
3726
  statusBar()-&gt;message(text, 2000);
 
3727
}
 
3728
 
 
3729
void KScribbleApp::windowMenuAboutToShow()
 
3730
{
 
3731
  pWindowMenu-&gt;clear();
 
3732
  
 
3733
  pWindowMenu-&gt;insertItem(i18n("&amp;New Window"), ID_WINDOW_NEW_WINDOW);
 
3734
  pWindowMenu-&gt;insertItem(i18n("&amp;Cascade"),
 
3735
                          pWorkspace, SLOT(cascade() ),0 , ID_WINDOW_CASCADE );
 
3736
  pWindowMenu-&gt;insertItem(i18n("&amp;Tile"),
 
3737
                          pWorkspace, SLOT(tile() ),0 , ID_WINDOW_TILE );
 
3738
  
 
3739
  if ( pWorkspace-&gt;windowList().isEmpty() ) {
 
3740
    disableCommand(ID_WINDOW_NEW_WINDOW);
 
3741
    disableCommand(ID_WINDOW_CASCADE);
 
3742
    disableCommand(ID_WINDOW_TILE);
 
3743
  }
 
3744
  
 
3745
  pWindowMenu-&gt;insertSeparator();
 
3746
  
 
3747
  QWidgetList windows = pWorkspace-&gt;windowList();
 
3748
  for ( int i = 0; i &lt; int(windows.count()); ++i ) {
 
3749
    int id = pWindowMenu-&gt;insertItem(QString("&amp;%1 ").arg(i+1)+windows.at(i)-&gt;caption(),
 
3750
                                     this, SLOT( windowMenuActivated( int ) ) );
 
3751
    pWindowMenu-&gt;setItemParameter( id, i );
 
3752
    pWindowMenu-&gt;setItemChecked( id, pWorkspace-&gt;activeWindow() == windows.at(i) );
 
3753
  }
 
3754
}
 
3755
 
 
3756
void KScribbleApp::windowMenuActivated( int id )
 
3757
{
 
3758
  QWidget* w = pWorkspace-&gt;windowList().at( id );
 
3759
  if ( w )
 
3760
    w-&gt;setFocus();
 
3761
}
 
3762
 
 
3763
 
 
3764
void KScribbleApp::commandCallback(int id_)
 
3765
{
 
3766
  switch (id_)
 
3767
  {
 
3768
    case ID_FILE_NEW:
 
3769
       slotFileNew();
 
3770
         break;
 
3771
 
 
3772
    case ID_FILE_OPEN:
 
3773
         slotFileOpen();
 
3774
         break;
 
3775
 
 
3776
    case ID_FILE_SAVE:
 
3777
         slotFileSave();
 
3778
         break;
 
3779
 
 
3780
    case ID_FILE_SAVE_AS:
 
3781
         slotFileSaveAs();
 
3782
         break;
 
3783
 
 
3784
    case ID_FILE_CLOSE:
 
3785
         slotFileClose();
 
3786
         break;
 
3787
 
 
3788
    case ID_FILE_PRINT:
 
3789
         slotFilePrint();
 
3790
         break;
 
3791
 
 
3792
    case ID_FILE_QUIT:
 
3793
         slotFileQuit();
 
3794
         break;
 
3795
 
 
3796
    case ID_EDIT_CUT:
 
3797
         slotEditCut();
 
3798
         break;
 
3799
 
 
3800
    case ID_EDIT_COPY:
 
3801
         slotEditCopy();
 
3802
         break;
 
3803
 
 
3804
    case ID_EDIT_PASTE:
 
3805
         slotEditPaste();
 
3806
         break;
 
3807
 
 
3808
    case ID_EDIT_CLEAR_ALL:
 
3809
         slotEditClearAll();
 
3810
         break;
 
3811
 
 
3812
    case ID_PEN_BRUSH:
 
3813
         slotPenBrush();
 
3814
         break;
 
3815
 
 
3816
    case ID_PEN_COLOR:
 
3817
         slotPenColor();
 
3818
         break;
 
3819
 
 
3820
    case ID_VIEW_TOOLBAR:
 
3821
         slotViewToolBar();
 
3822
         break;
 
3823
 
 
3824
    case ID_VIEW_STATUSBAR:
 
3825
         slotViewStatusBar();
 
3826
         break;
 
3827
 
 
3828
    case ID_WINDOW_NEW_WINDOW:
 
3829
         slotWindowNewWindow();
 
3830
       break;
 
3831
 
 
3832
    default:
 
3833
         break;
 
3834
  }
 
3835
}
 
3836
 
 
3837
void KScribbleApp::statusCallback(int id_)
 
3838
{
 
3839
  switch (id_)
 
3840
  {
 
3841
    case ID_FILE_NEW:
 
3842
         slotStatusHelpMsg(i18n("Creates a new document"));
 
3843
         break;
 
3844
 
 
3845
    case ID_FILE_OPEN:
 
3846
         slotStatusHelpMsg(i18n("Opens an existing document"));
 
3847
         break;
 
3848
 
 
3849
    case ID_FILE_OPEN_RECENT:
 
3850
         slotStatusHelpMsg(i18n("Opens a recently used file"));
 
3851
         break;
 
3852
 
 
3853
    case ID_FILE_SAVE:
 
3854
         slotStatusHelpMsg(i18n("Saves the currently active document"));
 
3855
         break;
 
3856
 
 
3857
    case ID_FILE_SAVE_AS:
 
3858
         slotStatusHelpMsg(i18n("Saves the currently active document as under a new filename"));
 
3859
         break;
 
3860
 
 
3861
    case ID_FILE_CLOSE:
 
3862
         slotStatusHelpMsg(i18n("Closes the currently active document"));
 
3863
         break;
 
3864
 
 
3865
    case ID_FILE_PRINT:
 
3866
         slotStatusHelpMsg(i18n("Prints out the actual document"));
 
3867
         break;
 
3868
 
 
3869
    case ID_FILE_QUIT:
 
3870
         slotStatusHelpMsg(i18n("Quits the application"));
 
3871
         break;
 
3872
 
 
3873
    case ID_EDIT_UNDO:
 
3874
         slotStatusHelpMsg(i18n("Reverts the last editing action"));
 
3875
         break;
 
3876
 
 
3877
    case ID_EDIT_CUT:
 
3878
         slotStatusHelpMsg(i18n("Cuts the selected section and puts it to the clipboard"));
 
3879
         break;
 
3880
 
 
3881
    case ID_EDIT_COPY:
 
3882
         slotStatusHelpMsg(i18n("Copies the selected section to the clipboard"));
 
3883
         break;
 
3884
 
 
3885
    case ID_EDIT_PASTE:
 
3886
         slotStatusHelpMsg(i18n("Pastes the clipboard contents to actual position"));
 
3887
         break;
 
3888
 
 
3889
    case ID_EDIT_CLEAR_ALL:
 
3890
         slotStatusHelpMsg(i18n("Clears the document contents"));
 
3891
         break;
 
3892
 
 
3893
    case ID_PEN_BRUSH:
 
3894
         slotStatusHelpMsg(i18n("Sets the pen width"));
 
3895
         break;
 
3896
 
 
3897
    case ID_PEN_COLOR:
 
3898
         slotStatusHelpMsg(i18n("Sets the current pen color"));
 
3899
         break;
 
3900
 
 
3901
    case ID_VIEW_TOOLBAR:
 
3902
         slotStatusHelpMsg(i18n("Enables/disables the toolbar"));
 
3903
         break;
 
3904
 
 
3905
    case ID_VIEW_STATUSBAR:
 
3906
         slotStatusHelpMsg(i18n("Enables/disables the statusbar"));
 
3907
         break;
 
3908
 
 
3909
    case ID_WINDOW_NEW_WINDOW:
 
3910
         slotStatusHelpMsg(i18n("Opens a new view for the current document"));
 
3911
         break;
 
3912
 
 
3913
    case ID_WINDOW_CASCADE:
 
3914
         slotStatusHelpMsg(i18n("Cascades all windows"));
 
3915
         break;
 
3916
 
 
3917
    case ID_WINDOW_TILE:
 
3918
         slotStatusHelpMsg(i18n("Tiles all windows"));
 
3919
         break;
 
3920
 
 
3921
    default:
 
3922
         break;
 
3923
  }
 
3924
}
 
3925
/** accepts drops and opens a new document
 
3926
for each drop */
 
3927
void KScribbleApp::dropEvent( QDropEvent* e){
 
3928
 
 
3929
  QImage img;
 
3930
  if ( QImageDrag::decode(e, img) )
 
3931
  {
 
3932
    KScribbleDoc* doc = new KScribbleDoc();
 
3933
    untitledCount+=1;
 
3934
    QString fileName=QString(i18n("Untitled%1")).arg(untitledCount);
 
3935
    doc-&gt;setPathName(fileName);
 
3936
    doc-&gt;setTitle(fileName);
 
3937
    doc-&gt;newDocument();
 
3938
    pDocList-&gt;append(doc);
 
3939
    KPixmap tmp;
 
3940
    tmp.resize(img.size());
 
3941
    tmp.convertFromImage(img);
 
3942
    doc-&gt;setPixmap(tmp);
 
3943
    doc-&gt;resizeDocument(tmp.size());
 
3944
    doc-&gt;setModified();
 
3945
    createClient(doc);
 
3946
  }
 
3947
}
 
3948
/** accepts drag events for images */
 
3949
void KScribbleApp::dragEnterEvent( QDragEnterEvent* e){
 
3950
  e-&gt;accept(QImageDrag::canDecode(e));
 
3951
}</programlisting>
 
3952
</para>
 
3953
</sect1>
 
3954
 
 
3955
<sect1 id="kscribbledoc.h">
 
3956
<title>kscribbledoc.h</title>
 
3957
 
 
3958
<para><programlisting>/***************************************************************************
 
3959
                          kscribbledoc.h  -  description
 
3960
                             -------------------
 
3961
    begin                : Mon Jan 31 11:05:05 CET 2000
 
3962
    copyright            : (C) 2000 by Ralf Nolden
 
3963
    email                : Ralf.Nolden@post.rwth-aachen.de
 
3964
 ***************************************************************************/
 
3965
 
 
3966
/***************************************************************************
 
3967
 *                                                                         *
 
3968
 *   This program is free software; you can redistribute it and/or modify  *
 
3969
 *   it under the terms of the GNU General Public License as published by  *
 
3970
 *   the Free Software Foundation; either version 2 of the License, or     *
 
3971
 *   (at your option) any later version.                                   *
 
3972
 *                                                                         *
 
3973
 ***************************************************************************/
 
3974
 
 
3975
#ifndef KSCRIBBLEDOC_H
 
3976
#define KSCRIBBLEDOC_H
 
3977
 
 
3978
#ifdef HAVE_CONFIG_H
 
3979
#include &lt;config.h&gt;
 
3980
#endif
 
3981
 
 
3982
// include files for QT
 
3983
#include &lt;qobject.h&gt;
 
3984
#include &lt;qstring.h&gt;
 
3985
#include &lt;qlist.h&gt;
 
3986
 
 
3987
#include &lt;qsize.h&gt;
 
3988
#include &lt;qpen.h&gt;
 
3989
#include &lt;qpoint.h&gt;
 
3990
//#include &lt;qpixmap.h&gt;
 
3991
#include &lt;qpointarray.h&gt;
 
3992
 
 
3993
#include &lt;kpixmap.h&gt;
 
3994
 
 
3995
 
 
3996
// forward declaration of the KScribble classes
 
3997
class KScribbleView;
 
3998
 
 
3999
/**  KScribbleDoc provides a document object for a document-view model.
 
4000
  *
 
4001
  * The KScribbleDoc class provides a document object that can be used in conjunction with the classes
 
4002
  * KScribbleApp and KScribbleView to create a document-view model for MDI (Multiple Document Interface)
 
4003
  * KDE 2 applications based on KApplication and KTMainWindow as main classes and QWorkspace as MDI manager widget.
 
4004
  * Thereby, the document object is created by the KScribbleApp instance (and kept in a document list) and contains
 
4005
  * the document structure with the according methods for manipulating the document
 
4006
  * data by KScribbleView objects. Also, KScribbleDoc contains the methods for serialization of the document data
 
4007
  * from and to files.
 
4008
  * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team.   
 
4009
  * @version KDevelop version 1.1 code generation
 
4010
  */
 
4011
class KScribbleDoc : public QObject
 
4012
{
 
4013
  Q_OBJECT
 
4014
 
 
4015
  friend KScribbleView;
 
4016
 
 
4017
  public:
 
4018
    /** Constructor for the fileclass of the application */
 
4019
    KScribbleDoc();
 
4020
    /** Destructor for the fileclass of the application */
 
4021
    ~KScribbleDoc();
 
4022
 
 
4023
    /** adds a view to the document which represents the document contents. Usually this is your main view. */
 
4024
    void addView(KScribbleView *view);
 
4025
    /** removes a view from the list of currently connected views */
 
4026
    void removeView(KScribbleView *view);
 
4027
    /** gets called if a view is removed or added */
 
4028
    void changedViewList();
 
4029
    /** returns the first view instance */
 
4030
    KScribbleView* firstView(){ return pViewList-&gt;first(); };
 
4031
    /** returns true, if the requested view is the last view of the document */
 
4032
    bool isLastView();
 
4033
    /** This method gets called when the user is about to close a frame window. It checks, if more than one view
 
4034
     * is connected to the document (then the frame can be closed), if pFrame is the last view and the document is
 
4035
     * modified, the user gets asked if he wants to save the document.
 
4036
     */
 
4037
    bool canCloseFrame(KScribbleView* pFrame);
 
4038
    /** sets the modified flag for the document after a modifying action on the view connected to the document.*/
 
4039
    void setModified(bool _m=true){ modified=_m; };
 
4040
    /** returns if the document is modified or not. Use this to determine if your document needs
 
4041
     * saving by the user on closing.
 
4042
     */
 
4043
    bool isModified(){ return modified; };
 
4044
    /** deletes the document's contents */
 
4045
    void deleteContents();
 
4046
    /** initializes the document generally */
 
4047
    bool newDocument();
 
4048
    /** closes the acutal document */
 
4049
    void closeDocument();
 
4050
    /** loads the document by filename and format and emits the updateViews() signal */
 
4051
    bool openDocument(const QString &amp;filename, const char *format=0);
 
4052
    /** saves the document under filename and format.*/  
 
4053
    bool saveDocument(const QString &amp;filename, const char *format=0);
 
4054
    /** sets the path to the file connected with the document */
 
4055
    void setPathName(const QString &amp;name);
 
4056
    /** returns the pathname of the current document file*/
 
4057
    const QString&amp; pathName() const;
 
4058
 
 
4059
    /** sets the filename of the document */
 
4060
    void setTitle(const QString &amp;title);
 
4061
    /** returns the title of the document */
 
4062
    const QString&amp; title() const;
 
4063
    /** get the current Pen */
 
4064
    const QPen currentPen(){ return pen;};  
 
4065
    /** returns the pen width */
 
4066
    const int penWidth() { return pen.width(); }
 
4067
    /** returns the pen color */
 
4068
    const QColor penColor(){ return pen.color(); }
 
4069
    /** sets the pen width */
 
4070
    void setPenWidth( int w ){ pen.setWidth( w ); }
 
4071
    /** sets the pen color */
 
4072
    void setPenColor( const QColor &amp;c ){ pen.setColor( c ); }
 
4073
    /** sets the pen style by a second toolbar */
 
4074
    void setPenStyle( PenStyle s){ pen.setStyle(s);}
 
4075
    /** clears the document contents */
 
4076
    void editClearAll();
 
4077
 
 
4078
    /** get the document size */
 
4079
    const QSize docSize(){ return size;};
 
4080
    /** sets the pixmap contents. Used by KScribbleApp
 
4081
    to create a new document by drop events */
 
4082
    void setPixmap(KPixmap pix) { buffer=pix;};
 
4083
    void resizeDocument(QSize m_size) { size=m_size; };
 
4084
  public slots:
 
4085
    /** calls repaint() on all views connected to the document object and is called by the view by
 
4086
     * which the document has been changed.
 
4087
     * As this view normally repaints itself, it is excluded from the paintEvent.
 
4088
     */
 
4089
    void updateAllViews(KScribbleView *sender);
 
4090
  
 
4091
  protected:
 
4092
  
 
4093
    QPen pen;
 
4094
    QPointArray polyline;
 
4095
    KPixmap buffer;
 
4096
   
 
4097
  private:
 
4098
    /** the modified flag of the current document */
 
4099
    bool modified;
 
4100
    QString m_title;
 
4101
    QString m_filename;
 
4102
    /** the list of the views currently connected to the document */
 
4103
    QList&lt;KScribbleView&gt; *pViewList;  
 
4104
    QSize size;
 
4105
};
 
4106
 
 
4107
#endif // KSCRIBBLEDOC_H
 
4108
</programlisting>
 
4109
</para>
 
4110
</sect1>
 
4111
 
 
4112
<sect1 id="kscribbledoc.cpp">
 
4113
<title>kscribbledoc.cpp</title>
 
4114
 
 
4115
<para><programlisting>/***************************************************************************
 
4116
                          kscribbledoc.cpp  -  description
 
4117
                             -------------------
 
4118
    begin                : Mon Jan 31 11:05:05 CET 2000
 
4119
    copyright            : (C) 2000 by Ralf Nolden
 
4120
    email                : Ralf.Nolden@post.rwth-aachen.de
 
4121
 ***************************************************************************/
 
4122
 
 
4123
/***************************************************************************
 
4124
 *                                                                         *
 
4125
 *   This program is free software; you can redistribute it and/or modify  *
 
4126
 *   it under the terms of the GNU General Public License as published by  *
 
4127
 *   the Free Software Foundation; either version 2 of the License, or     *
 
4128
 *   (at your option) any later version.                                   *
 
4129
 *                                                                         *
 
4130
 ***************************************************************************/
 
4131
 
 
4132
// include files for Qt
 
4133
#include &lt;qdir.h&gt;
 
4134
#include &lt;qfileinfo.h&gt;
 
4135
#include &lt;qwidget.h&gt;
 
4136
 
 
4137
// include files for KDE
 
4138
#include &lt;klocale.h&gt;
 
4139
#include &lt;kmessagebox.h&gt;
 
4140
#include &lt;kfiledialog.h&gt;
 
4141
 
 
4142
// application specific includes
 
4143
#include "kscribbledoc.h"
 
4144
#include "kscribble.h"
 
4145
#include "kscribbleview.h"
 
4146
 
 
4147
 
 
4148
KScribbleDoc::KScribbleDoc()
 
4149
{
 
4150
  pViewList = new QList&lt;KScribbleView&gt;;
 
4151
  pViewList-&gt;setAutoDelete(false);
 
4152
}
 
4153
 
 
4154
KScribbleDoc::~KScribbleDoc()
 
4155
{
 
4156
  delete pViewList;
 
4157
}
 
4158
 
 
4159
void KScribbleDoc::addView(KScribbleView *view)
 
4160
{
 
4161
  pViewList-&gt;append(view);
 
4162
  changedViewList();
 
4163
}
 
4164
 
 
4165
void KScribbleDoc::removeView(KScribbleView *view)
 
4166
{
 
4167
    pViewList-&gt;remove(view);
 
4168
    if(!pViewList-&gt;isEmpty())
 
4169
      changedViewList();
 
4170
    else
 
4171
      deleteContents();
 
4172
}
 
4173
 
 
4174
void KScribbleDoc::changedViewList(){  
 
4175
  
 
4176
  KScribbleView *w;
 
4177
  if((int)pViewList-&gt;count() == 1){
 
4178
    w=pViewList-&gt;first();
 
4179
    w-&gt;setCaption(m_title);
 
4180
  }
 
4181
  else{  
 
4182
    int i;
 
4183
    for( i=1,w=pViewList-&gt;first(); w!=0; i++, w=pViewList-&gt;next())
 
4184
      w-&gt;setCaption(QString(m_title+":%1").arg(i));  
 
4185
  }
 
4186
}
 
4187
 
 
4188
bool KScribbleDoc::isLastView() {
 
4189
  return ((int) pViewList-&gt;count() == 1);
 
4190
}
 
4191
 
 
4192
 
 
4193
void KScribbleDoc::updateAllViews(KScribbleView *sender)
 
4194
{
 
4195
  KScribbleView *w;
 
4196
  for(w=pViewList-&gt;first(); w!=0; w=pViewList-&gt;next())
 
4197
  {
 
4198
      w-&gt;update(sender);
 
4199
  }
 
4200
 
 
4201
}
 
4202
 
 
4203
void KScribbleDoc::setPathName(const QString &amp;name)
 
4204
{
 
4205
  m_filename=name;
 
4206
  m_title=QFileInfo(name).fileName();
 
4207
}
 
4208
 
 
4209
const QString&amp; KScribbleDoc::pathName() const
 
4210
{
 
4211
  return m_filename;
 
4212
}
 
4213
 
 
4214
void KScribbleDoc::setTitle(const QString &amp;title)
 
4215
{
 
4216
  m_title=title;
 
4217
}
 
4218
 
 
4219
const QString &amp;KScribbleDoc::title() const
 
4220
{
 
4221
  return m_title;
 
4222
}
 
4223
 
 
4224
 
 
4225
void KScribbleDoc::closeDocument()
 
4226
{
 
4227
  KScribbleView *w;
 
4228
  if(!isLastView())
 
4229
  {
 
4230
    for(w=pViewList-&gt;first(); w!=0; w=pViewList-&gt;next())
 
4231
    {
 
4232
        if(!w-&gt;close())
 
4233
         break;
 
4234
    }
 
4235
  }
 
4236
  if(isLastView())
 
4237
  {
 
4238
    w=pViewList-&gt;first();
 
4239
    w-&gt;close();
 
4240
  }
 
4241
}
 
4242
 
 
4243
bool KScribbleDoc::newDocument()
 
4244
{
 
4245
  /////////////////////////////////////////////////
 
4246
  // TODO: Add your document initialization code here
 
4247
  size=QSize(300,200 );
 
4248
  pen=QPen( Qt::black, 3 );
 
4249
  polyline=QPointArray(3);
 
4250
  buffer.resize(size);
 
4251
  buffer.fill( Qt::white );
 
4252
  /////////////////////////////////////////////////
 
4253
  modified=false;
 
4254
  return true;
 
4255
}
 
4256
 
 
4257
bool KScribbleDoc::openDocument(const QString &amp;filename, const char *format /*=0*/)
 
4258
{
 
4259
 
 
4260
  QFile f( filename );
 
4261
//  if ( !f.open( IO_ReadOnly ) )
 
4262
//    return false;
 
4263
  /////////////////////////////////////////////////
 
4264
  // TODO: Add your document opening code here
 
4265
  if(!buffer.load( filename, format ))
 
4266
    return false;
 
4267
  size=buffer.size();
 
4268
  /////////////////////////////////////////////////
 
4269
//  f.close();
 
4270
  
 
4271
  modified=false;
 
4272
  m_filename=filename;
 
4273
  m_title=QFileInfo(f).fileName();
 
4274
  return true;
 
4275
}
 
4276
 
 
4277
bool KScribbleDoc::saveDocument(const QString &amp;filename, const char *format /*=0*/)
 
4278
{
 
4279
  QFile f( filename );
 
4280
//  if ( !f.open( IO_WriteOnly ) )
 
4281
//    return false;
 
4282
 
 
4283
  /////////////////////////////////////////////////
 
4284
  // TODO: Add your document saving code here
 
4285
  if(!buffer.save( filename, format ))
 
4286
    return false;
 
4287
  /////////////////////////////////////////////////
 
4288
 
 
4289
//  f.close();
 
4290
 
 
4291
  modified=false;
 
4292
  m_filename=filename;
 
4293
  m_title=QFileInfo(f).fileName();
 
4294
  return true;
 
4295
}
 
4296
 
 
4297
void KScribbleDoc::deleteContents()
 
4298
{
 
4299
  /////////////////////////////////////////////////
 
4300
  // TODO: Add implementation to delete the document contents
 
4301
  buffer.fill( Qt::white );
 
4302
  /////////////////////////////////////////////////
 
4303
 
 
4304
}
 
4305
 
 
4306
bool KScribbleDoc::canCloseFrame(KScribbleView* pFrame)
 
4307
{
 
4308
  if(!isLastView())
 
4309
    return true;
 
4310
      
 
4311
  bool ret=false;
 
4312
  if(isModified())
 
4313
  {
 
4314
    QString saveName;
 
4315
    switch(KMessageBox::warningYesNoCancel(pFrame, i18n("The current file has been modified.\n"
 
4316
    "Do you want to save it?"),title()))
 
4317
    {
 
4318
    case KMessageBox::Yes:
 
4319
      if(title().contains(i18n("Untitled")))
 
4320
      {
 
4321
        saveName=KFileDialog::getSaveFileName(QDir::currentDirPath(),
 
4322
                             i18n("*|All files"), pFrame, i18n("Save as..."));
 
4323
        if(saveName.isEmpty())
 
4324
        return false;
 
4325
      }
 
4326
      else
 
4327
       saveName=pathName();
 
4328
          
 
4329
      if(!saveDocument(saveName))
 
4330
      {
 
4331
        switch(KMessageBox::warningYesNo(pFrame,i18n("Could not save the current document !\n"
 
4332
                          "Close anyway ?"), i18n("I/O Error !")))
 
4333
        {
 
4334
          case KMessageBox::Yes:
 
4335
            ret=true;
 
4336
          case KMessageBox::No:
 
4337
            ret=false;
 
4338
        }                
 
4339
      }
 
4340
      else
 
4341
        ret=true;
 
4342
        break;
 
4343
    case KMessageBox::No:
 
4344
      ret=true;
 
4345
      break;
 
4346
    case KMessageBox::Cancel:
 
4347
    default:
 
4348
      ret=false;         
 
4349
      break;
 
4350
    }
 
4351
  }
 
4352
  else
 
4353
    ret=true;
 
4354
    
 
4355
  return ret;
 
4356
}
 
4357
 
 
4358
void KScribbleDoc::editClearAll()
 
4359
{
 
4360
  deleteContents();
 
4361
  setModified();
 
4362
  updateAllViews(0);
 
4363
}
 
4364
</programlisting>
 
4365
</para>
 
4366
</sect1>
 
4367
 
 
4368
<sect1 id="kscribbleview.h">
 
4369
<title>kscribbleview.h</title>
 
4370
 
 
4371
<para><programlisting>/***************************************************************************
 
4372
                          kscribbleview.h  -  description
 
4373
                             -------------------
 
4374
    begin                : Mon Jan 31 11:05:05 CET 2000
 
4375
    copyright            : (C) 2000 by Ralf Nolden
 
4376
    email                : Ralf.Nolden@post.rwth-aachen.de
 
4377
 ***************************************************************************/
 
4378
 
 
4379
/***************************************************************************
 
4380
 *                                                                         *
 
4381
 *   This program is free software; you can redistribute it and/or modify  *
 
4382
 *   it under the terms of the GNU General Public License as published by  *
 
4383
 *   the Free Software Foundation; either version 2 of the License, or     *
 
4384
 *   (at your option) any later version.                                   *
 
4385
 *                                                                         *
 
4386
 ***************************************************************************/
 
4387
 
 
4388
#ifndef KSCRIBBLEVIEW_H
 
4389
#define KSCRIBBLEVIEW_H
 
4390
 
 
4391
#ifdef HAVE_CONFIG_H
 
4392
#include &lt;config.h&gt;
 
4393
#endif
 
4394
 
 
4395
// include files for Qt
 
4396
#include &lt;qscrollview.h&gt;
 
4397
#include &lt;kpixmap.h&gt;
 
4398
 
 
4399
class KScribbleDoc;
 
4400
 
 
4401
/** The KScribbleView class provides the view widget for the document instance connected to it and is displayed
 
4402
 * as a MDI child window in the main view area of the KScribbleApp class instance. The KScribbleApp
 
4403
 * class also has an eventFilter()  method that gets installed on every KScribbleView instance to
 
4404
 * control events of the type QEvent::Close.The document connected to the view instance keeps a list
 
4405
 * of all view that represent the document contents as there can be more than one view. Views get created in
 
4406
 * KScribbleApp::createClient() and automatically added to the list of views.
 
4407
 * The KScribbleView class inherits QWidget as a base. Another possible inheritance besides specialized
 
4408
 + widgets could be QMainWindow so that you can easily set up the main area of your view by setting another view
 
4409
 * as main widget (QMainWindow::setMainWidget() ).
 
4410
 * NOTE: The close event always has to be empty (DON`T CALL QWidget::closeEvent(e) in closeEvent())
 
4411
 * because the installed event filter can only manage a forward implementation. If the QCloseEvent
 
4412
 * is received by the KScribbleView, the overwritten event handler has to do nothing as the eventFilter
 
4413
 * has set accept() or ignore() already. If QWidget::closeEvent() is called again, the default event
 
4414
 * handler will accept the close event and the window gets destroyed even if the installed eventFilter
 
4415
 * has set the event to be ignored.  
 
4416
 * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team.
 
4417
 * @version KDevelop version 1.1 code generation
 
4418
 */
 
4419
class KScribbleView : public QScrollView
 
4420
{
 
4421
  Q_OBJECT
 
4422
 
 
4423
  friend KScribbleDoc;
 
4424
 
 
4425
  public:
 
4426
    /** Constructor for the view
 
4427
      * @param pDoc  your document instance that the view represents. Create a document
 
4428
      * before calling the constructor or connect an already existing document to a new MDI child widget.*/
 
4429
    KScribbleView(KScribbleDoc* pDoc, QWidget* parent, const char *name, int wflags);
 
4430
    /** Destructor for the main view */
 
4431
    ~KScribbleView();
 
4432
    /** returns a pointer to the document connected to the view*/
 
4433
    KScribbleDoc *getDocument() const;
 
4434
    /** gets called to redraw the document contents if it has been modified */
 
4435
    void update(KScribbleView* pSender);
 
4436
    /** contains the implementation for printing functionality and gets called by KScribbleApp::slotFilePrint() */
 
4437
    void print(QPrinter *pPrinter);
 
4438
    /** cuts out a selection */
 
4439
    void cutSelection();
 
4440
    /** copies a selection to the clipboard */
 
4441
    void copySelection();
 
4442
    /** pastes the clipboard contents to a selection that can be inserted into the picture */
 
4443
    void pasteSelection();
 
4444
        
 
4445
  protected:
 
4446
  
 
4447
    /** overwritten QWidget::closeEvent() to catch closing views. Does nothing, as the closeEvents for
 
4448
    * KScribbleView's are processed by KScribbleApp::eventFilter(), so this overwitten closeEvent is necessary
 
4449
    * and has to be empty. Don't overwrite this method !
 
4450
    */
 
4451
    virtual void closeEvent(QCloseEvent* );
 
4452
    /** overwritten to interpret key events for scrollbars */
 
4453
    virtual void keyPressEvent( QKeyEvent* );
 
4454
    /** changed from mousePressEvent() overwriting QScrollView method */
 
4455
    virtual void viewportMousePressEvent( QMouseEvent* );
 
4456
    /** changed from mouseReleaseEvent() overwriting QScrollView method */
 
4457
    virtual void viewportMouseReleaseEvent( QMouseEvent* );
 
4458
    /** On paste actions inserts the pasted clipboard contents */
 
4459
    virtual void viewportMouseDoubleClickEvent(QMouseEvent* e);
 
4460
    /** changed from mouseMoveEvent() overwriting QScrollView method */
 
4461
    virtual void viewportMouseMoveEvent( QMouseEvent* );
 
4462
    /** changed from resizeEvent() overwriting QScrollView method */
 
4463
//    virtual void viewportResizeEvent( QResizeEvent* );
 
4464
    /** changed from paintEvent() overwriting QScrollView method */
 
4465
    virtual void viewportPaintEvent( QPaintEvent* );
 
4466
      
 
4467
    virtual void viewportDragEnterEvent ( QDragEnterEvent * );
 
4468
 
 
4469
    virtual void viewportDragMoveEvent ( QDragMoveEvent * );
 
4470
 
 
4471
    virtual void viewportDragLeaveEvent ( QDragLeaveEvent * );
 
4472
 
 
4473
    virtual void viewportDropEvent ( QDropEvent * );
 
4474
  
 
4475
    /** the document instance */
 
4476
    KScribbleDoc *doc;
 
4477
      
 
4478
  private:
 
4479
    KPixmap tmp;
 
4480
    QRect select;
 
4481
    QClipboard *cb;
 
4482
    enum Action{IDLE=0, DRAW, SELECT, PASTE, DRAG} action;
 
4483
};
 
4484
 
 
4485
#endif // KSCRIBBLEVIEW_H
 
4486
</programlisting>
 
4487
</para>
 
4488
</sect1>
 
4489
 
 
4490
<sect1 id="kscribbleview.cpp">
 
4491
<title>kscribbleview.cpp</title>
 
4492
 
 
4493
<para><programlisting>/***************************************************************************
 
4494
                          kscribbleview.cpp  -  description
 
4495
                             -------------------
 
4496
    begin                : Mon Jan 31 11:05:05 CET 2000
 
4497
    copyright            : (C) 2000 by Ralf Nolden
 
4498
    email                : Ralf.Nolden@post.rwth-aachen.de
 
4499
 ***************************************************************************/
 
4500
 
 
4501
/***************************************************************************
 
4502
 *                                                                         *
 
4503
 *   This program is free software; you can redistribute it and/or modify  *
 
4504
 *   it under the terms of the GNU General Public License as published by  *
 
4505
 *   the Free Software Foundation; either version 2 of the License, or     *
 
4506
 *   (at your option) any later version.                                   *
 
4507
 *                                                                         *
 
4508
 ***************************************************************************/
 
4509
#include &lt;iostream.h&gt;
 
4510
 
 
4511
// include files for Qt
 
4512
#include &lt;qprinter.h&gt;
 
4513
#include &lt;qpainter.h&gt;
 
4514
#include &lt;qdir.h&gt;
 
4515
#include &lt;qsize.h&gt;
 
4516
#include &lt;qclipboard.h&gt;
 
4517
#include &lt;qimage.h&gt;
 
4518
#include &lt;qdragobject.h&gt;
 
4519
 
 
4520
// include files for KDE
 
4521
#include &lt;kiconloader.h&gt;
 
4522
 
 
4523
// application specific includes
 
4524
#include "kscribbleview.h"
 
4525
#include "kscribbledoc.h"
 
4526
#include "kscribble.h"
 
4527
 
 
4528
 
 
4529
KScribbleView::KScribbleView(KScribbleDoc* pDoc, QWidget *parent, const char* name, int wflags)
 
4530
 : QScrollView(parent, name, wflags | WPaintClever | WNorthWestGravity | WRepaintNoErase)
 
4531
{
 
4532
  cb = QApplication::clipboard();
 
4533
  viewport()-&gt;setAcceptDrops(true);
 
4534
  setDragAutoScroll(true);
 
4535
  doc=pDoc;
 
4536
  action=IDLE;
 
4537
  viewport()-&gt;setCursor( Qt::crossCursor );
 
4538
  QSize size=doc-&gt;docSize();
 
4539
  resizeContents(size.width(), size.height());
 
4540
  resize(size);
 
4541
}
 
4542
 
 
4543
KScribbleView::~KScribbleView()
 
4544
{
 
4545
}
 
4546
 
 
4547
KScribbleDoc *KScribbleView::getDocument() const
 
4548
{
 
4549
  return doc;
 
4550
}
 
4551
 
 
4552
void KScribbleView::update(KScribbleView* pSender){
 
4553
  if(pSender != this)
 
4554
    viewport()-&gt;repaint(0,0,visibleWidth(), visibleHeight(), false);
 
4555
}
 
4556
 
 
4557
void KScribbleView::print(QPrinter *pPrinter)
 
4558
{
 
4559
  if (pPrinter-&gt;setup(this))
 
4560
  {
 
4561
    QPainter p;
 
4562
    p.begin(pPrinter);
 
4563
          
 
4564
    ///////////////////////////////
 
4565
    // TODO: add your printing code here
 
4566
    p.drawPixmap(0,0,doc-&gt;buffer);
 
4567
    ///////////////////////////////
 
4568
    p.end();
 
4569
  }
 
4570
}
 
4571
 
 
4572
/** cuts out a selection */
 
4573
void KScribbleView::cutSelection(){
 
4574
  select=select.normalize();
 
4575
  QPixmap cb_pix;
 
4576
  cb_pix.resize(select.size());
 
4577
  // copy selection to cb_pix and copy to clipboard
 
4578
  bitBlt(&amp;cb_pix, 0, 0,
 
4579
         &amp;doc-&gt;buffer, select.x()+contentsX(),  select.y()+contentsY(), cb_pix.width(), cb_pix.height());
 
4580
  cb-&gt;setPixmap(cb_pix);
 
4581
  // fill cb_pix with white and copy to selection area
 
4582
  cb_pix.fill(Qt::white);
 
4583
  bitBlt(&amp;doc-&gt;buffer, select.x()+contentsX(), select.y()+contentsY(),
 
4584
         &amp;cb_pix, 0, 0, cb_pix.width(), cb_pix.height());
 
4585
  action = IDLE;
 
4586
  doc-&gt;setModified();
 
4587
  doc-&gt;updateAllViews(this);
 
4588
  viewport()-&gt;repaint(0,0,visibleWidth(), visibleHeight(), false);
 
4589
}
 
4590
/** copies a selection to the clipboard */
 
4591
void KScribbleView::copySelection(){
 
4592
  select=select.normalize();
 
4593
  QPixmap cb_pix;
 
4594
  cb_pix.resize(select.size());
 
4595
  // copy selection to cb_pix and copy to clipboard
 
4596
  bitBlt(&amp;cb_pix, 0, 0,
 
4597
         &amp;doc-&gt;buffer, select.x()+contentsX(),  select.y()+contentsY(),cb_pix.width(), cb_pix.height());
 
4598
  cb-&gt;setPixmap(cb_pix);
 
4599
  action = IDLE;
 
4600
  viewport()-&gt;repaint(0,0,visibleWidth(), visibleHeight(), false);
 
4601
}
 
4602
/** pastes the clipboard contents to a selection that can be inserted into the picture */
 
4603
void KScribbleView::pasteSelection(){
 
4604
  select=cb-&gt;pixmap().rect();
 
4605
  action = PASTE;
 
4606
  viewport()-&gt;setCursor( Qt::sizeAllCursor );
 
4607
}
 
4608
 
 
4609
void KScribbleView::closeEvent(QCloseEvent* e){
 
4610
 
 
4611
// DO NOT CALL QWidget::closeEvent(e) here !!
 
4612
// This will accept the closing by QCloseEvent::accept() by default.
 
4613
// The installed eventFilter() in KScribbleApp takes care for closing the widget
 
4614
// or ignoring the close event
 
4615
    
 
4616
}
 
4617
 
 
4618
void KScribbleView::keyPressEvent( QKeyEvent *e )
 
4619
{
 
4620
  switch (e-&gt;key())
 
4621
  {
 
4622
    case Key_Right:
 
4623
      scrollBy( 10, 0 );
 
4624
      break;
 
4625
    case Key_Left:
 
4626
      scrollBy( -10,0);
 
4627
      break;
 
4628
    case Key_Up:
 
4629
      scrollBy( 0, -10 );
 
4630
      break;
 
4631
    case Key_Down:
 
4632
      scrollBy( 0, 10 );
 
4633
      break;
 
4634
    case Key_Home:
 
4635
      setContentsPos(0,0);
 
4636
      break;
 
4637
    case Key_End:
 
4638
      setContentsPos(0,viewport()-&gt;height()-viewport()-&gt;height());
 
4639
      break;
 
4640
    case Key_PageUp:
 
4641
      scrollBy( 0, -viewport()-&gt;height() );
 
4642
      break;
 
4643
    case Key_PageDown:
 
4644
      scrollBy( 0, viewport()-&gt;height() );
 
4645
      break;
 
4646
  }
 
4647
 
 
4648
}
 
4649
 
 
4650
void KScribbleView::viewportMousePressEvent( QMouseEvent *e )
 
4651
{
 
4652
  if ( e-&gt;button() == LeftButton &amp;&amp; action == IDLE)
 
4653
  {
 
4654
    action=DRAW;
 
4655
    doc-&gt;polyline[2] = doc-&gt;polyline[1] = doc-&gt;polyline[0] = viewportToContents(e-&gt;pos());
 
4656
    doc-&gt;updateAllViews(this);
 
4657
  }
 
4658
  else if ( e-&gt;button() == RightButton &amp;&amp; action == IDLE)
 
4659
  {
 
4660
    action = SELECT;
 
4661
    QPoint pt=e-&gt;pos();
 
4662
    int x = pt.x() &gt; contentsWidth() ? contentsWidth() : pt.x();
 
4663
    int y = pt.y() &gt; contentsHeight() ? contentsHeight() : pt.y();
 
4664
    select.setLeft(x-1);
 
4665
    select.setTop(y-1);
 
4666
    select.setRight(x-1);
 
4667
    select.setBottom(y-1);
 
4668
  }
 
4669
  else if( action == SELECT )
 
4670
  {
 
4671
    action = IDLE;
 
4672
    select=select.normalize();
 
4673
    // drag
 
4674
    if(select.contains(e-&gt;pos(), true)) // point inside the selection
 
4675
    {
 
4676
      tmp.resize(select.size());
 
4677
      bitBlt(&amp;tmp, 0, 0,
 
4678
             &amp;doc-&gt;buffer, select.x()+contentsX(),  select.y()+contentsY(), tmp.width(), tmp.height());
 
4679
      QImage img =tmp.convertToImage();
 
4680
      QDragObject *d = new QImageDrag( img, viewport() );
 
4681
      d-&gt;setPixmap(BarIcon("filenew"));
 
4682
      d-&gt;drag();
 
4683
    }
 
4684
    // remove selection
 
4685
    else
 
4686
      viewport()-&gt;repaint(0,0,visibleWidth(), visibleHeight(), false);
 
4687
  }
 
4688
  else if( action == PASTE )
 
4689
  {
 
4690
    if ( e-&gt;button() == RightButton )
 
4691
    {
 
4692
      action = IDLE;
 
4693
      viewport()-&gt;setCursor( Qt::crossCursor );
 
4694
    }
 
4695
    QPoint mv_pt (viewport()-&gt;height(), viewport()-&gt;width());
 
4696
    if(QRect(0,0,mv_pt.x(),mv_pt.y()).contains(e-&gt;pos()))
 
4697
      select.moveCenter(e-&gt;pos());
 
4698
    else
 
4699
    {
 
4700
      select.moveBottomRight(mv_pt);
 
4701
    }
 
4702
    viewport()-&gt;repaint(0,0,visibleWidth(), visibleHeight(), false);
 
4703
  }
 
4704
}
 
4705
 
 
4706
void KScribbleView::viewportMouseReleaseEvent( QMouseEvent *e )
 
4707
{
 
4708
  if ( action == DRAW )
 
4709
  {
 
4710
    action = IDLE;
 
4711
    doc-&gt;updateAllViews(this);
 
4712
  }
 
4713
  if ( action == SELECT)
 
4714
  {
 
4715
    QPoint pt=e-&gt;pos();
 
4716
    int x = pt.x() &gt; 0 ? pt.x() : 0;
 
4717
    int y = pt.y() &gt; 0 ? pt.y() : 0;
 
4718
    select.setRight(x);
 
4719
    select.setBottom(y);
 
4720
    QSize size=doc-&gt;docSize();
 
4721
    select = select.intersect(QRect(0,0,size.width(), size.height()));  
 
4722
  }
 
4723
}
 
4724
 
 
4725
/** On paste actions inserts the pasted clipboard contents
 
4726
 */
 
4727
void KScribbleView::viewportMouseDoubleClickEvent(QMouseEvent* e)
 
4728
{
 
4729
  if( action == PASTE )
 
4730
  {
 
4731
    action = IDLE;
 
4732
    select.moveCenter(e-&gt;pos());
 
4733
    viewport()-&gt;setCursor( Qt::crossCursor );
 
4734
    QPixmap cb_pix;
 
4735
    cb_pix.resize(cb-&gt;pixmap().size());
 
4736
    cb_pix=cb-&gt;pixmap();
 
4737
    bitBlt( &amp;doc-&gt;buffer, contentsX()+select.x(), contentsY()+select.y(),
 
4738
            &amp;cb_pix, 0,0 , select.width(),select.height() );
 
4739
    viewport()-&gt;repaint(0,0,visibleWidth(), visibleHeight(), false);
 
4740
    doc-&gt;setModified();
 
4741
    doc-&gt;updateAllViews(this);
 
4742
  }
 
4743
 
 
4744
}
 
4745
 
 
4746
void KScribbleView::viewportMouseMoveEvent( QMouseEvent *e )
 
4747
{
 
4748
  if ( action == DRAW )
 
4749
  {    
 
4750
    QPainter painter;
 
4751
    painter.begin( &amp;doc-&gt;buffer );
 
4752
    painter.setPen( doc-&gt;currentPen() );
 
4753
    doc-&gt;polyline[2] = doc-&gt;polyline[1];
 
4754
    doc-&gt;polyline[1] = doc-&gt;polyline[0];
 
4755
    doc-&gt;polyline[0] = viewportToContents(e-&gt;pos());
 
4756
    painter.drawPolyline( doc-&gt;polyline );
 
4757
    painter.end();
 
4758
 
 
4759
    QRect r = doc-&gt;polyline.boundingRect();
 
4760
    r = r.normalize();
 
4761
    r.setLeft( r.left() - doc-&gt;penWidth() );
 
4762
    r.setTop( r.top() - doc-&gt;penWidth() );
 
4763
    r.setRight( r.right() + doc-&gt;penWidth() );
 
4764
    r.setBottom( r.bottom() + doc-&gt;penWidth() );
 
4765
 
 
4766
    bitBlt(viewport(), r.x()-contentsX(), r.y()-contentsY() ,
 
4767
           &amp;doc-&gt;buffer, r.x(), r.y(), r.width(), r.height() );
 
4768
    doc-&gt;setModified();
 
4769
    doc-&gt;updateAllViews(this);
 
4770
  }
 
4771
  if ( action == SELECT )
 
4772
  {
 
4773
    QPoint pt=e-&gt;pos();
 
4774
    select.setWidth(select.x()+pt.x());
 
4775
    select.setHeight(select.y()+pt.y());
 
4776
    select.setRight(pt.x());
 
4777
    select.setBottom(pt.y());
 
4778
    QSize size=doc-&gt;docSize();
 
4779
    select = select.intersect(QRect(0,0,size.width(), size.height()));  
 
4780
    viewport()-&gt;repaint(0,0,visibleWidth(), visibleHeight(), false);
 
4781
  }
 
4782
  if( action == PASTE )
 
4783
  {
 
4784
    QPoint mv_pt (viewport()-&gt;height(), viewport()-&gt;width());
 
4785
    if(QRect(0,0,mv_pt.x(),mv_pt.y()).contains(e-&gt;pos()))
 
4786
      select.moveCenter(e-&gt;pos());
 
4787
    else
 
4788
    {
 
4789
      select.moveBottomRight(mv_pt);
 
4790
    }
 
4791
    QRect pm_rect=cb-&gt;pixmap().rect();
 
4792
    select.setWidth(pm_rect.width());
 
4793
    select.setHeight(pm_rect.height());
 
4794
    QSize size=doc-&gt;docSize();
 
4795
    select = select.intersect(QRect(0,0,size.width(), size.height()));  
 
4796
    viewport()-&gt;repaint(0,0,visibleWidth(), visibleHeight(), false);
 
4797
    doc-&gt;setModified();
 
4798
    doc-&gt;updateAllViews(this);
 
4799
  }
 
4800
}
 
4801
 
 
4802
//void KScribbleView::viewportResizeEvent( QResizeEvent *e )
 
4803
//{
 
4804
//}
 
4805
 
 
4806
void KScribbleView::viewportPaintEvent( QPaintEvent *e )
 
4807
{
 
4808
  bitBlt( viewport(),0,0, &amp;doc-&gt;buffer,contentsX() ,contentsY() );
 
4809
 
 
4810
  if( action == PASTE )
 
4811
  {
 
4812
    tmp.resize(cb-&gt;pixmap().size());
 
4813
    tmp=cb-&gt;pixmap();
 
4814
  }
 
4815
  if( action == PASTE || action == DRAG )
 
4816
  {
 
4817
    QSize size=doc-&gt;docSize();
 
4818
    select = select.intersect(QRect(0,0,size.width(), size.height()));  
 
4819
    if(select.intersects(e-&gt;rect()))
 
4820
      bitBlt(viewport(), select.x(), select.y(), &amp;tmp, 0, 0, select.width(), select.height());
 
4821
  }
 
4822
  if( action == PASTE || action == DRAG || action == SELECT )
 
4823
  {
 
4824
//    if(select.intersects(e-&gt;rect()))
 
4825
//    {
 
4826
      QPainter paint_area;
 
4827
      paint_area.begin(viewport());
 
4828
      paint_area.setPen(QPen(Qt::black, 0, DashLine));
 
4829
      paint_area.drawRect( select );
 
4830
      paint_area.end();
 
4831
//    }
 
4832
  }
 
4833
  QScrollView::viewportPaintEvent(e);
 
4834
}
 
4835
 
 
4836
void  KScribbleView::viewportDragEnterEvent ( QDragEnterEvent * e)
 
4837
{
 
4838
  e-&gt;accept(QImageDrag::canDecode(e));
 
4839
  action = DRAG;
 
4840
}
 
4841
 
 
4842
void  KScribbleView::viewportDragMoveEvent ( QDragMoveEvent * e)
 
4843
{
 
4844
  QImage img;
 
4845
  if ( QImageDrag::decode(e, img) ){
 
4846
    tmp.resize(img.size());
 
4847
    tmp.convertFromImage(img);
 
4848
    select.setWidth(tmp.width());
 
4849
    select.setHeight(tmp.height());
 
4850
    select.moveCenter(e-&gt;pos());
 
4851
    viewport()-&gt;repaint(0,0,visibleWidth(), visibleHeight(), false);
 
4852
  }
 
4853
}
 
4854
 
 
4855
void  KScribbleView::viewportDragLeaveEvent ( QDragLeaveEvent * )
 
4856
{
 
4857
  action = IDLE;
 
4858
  viewport()-&gt;repaint(0,0,visibleWidth(), visibleHeight(), false);
 
4859
}
 
4860
 
 
4861
void  KScribbleView::viewportDropEvent ( QDropEvent * e)
 
4862
{
 
4863
  QImage img;
 
4864
  if ( QImageDrag::decode(e, img) )
 
4865
  {
 
4866
    tmp.resize(img.size());
 
4867
    tmp.convertFromImage(img);
 
4868
    select.setWidth(tmp.width());
 
4869
    select.setHeight(tmp.height());
 
4870
    select.moveCenter(e-&gt;pos());
 
4871
    bitBlt(&amp;doc-&gt;buffer, select.x()+contentsX(), select.y()+contentsY(),
 
4872
           &amp;tmp, 0, 0, tmp.width(), tmp.height());
 
4873
    doc-&gt;setModified();
 
4874
    doc-&gt;updateAllViews(this);
 
4875
  }
 
4876
  action = IDLE;
 
4877
    viewport()-&gt;repaint(0,0,visibleWidth(), visibleHeight(), false);
 
4878
}
 
4879
</programlisting>
 
4880
</para>
 
4881
</sect1>
 
4882
 
 
4883
<sect1 id="kpenbrushdlg.h">
 
4884
<title>kpenbrushdlg.h</title>
 
4885
 
 
4886
<para><programlisting>/***************************************************************************
 
4887
                          kpenbrushdlg.h  -  description
 
4888
                             -------------------
 
4889
    begin                : Fri Jul 23 1999
 
4890
    copyright            : (C) 1999 by Ralf Nolden
 
4891
    email                : Ralf.Nolden@post.rwth-aachen.de
 
4892
 ***************************************************************************/
 
4893
 
 
4894
/***************************************************************************
 
4895
 *                                                                         *
 
4896
 *   This program is free software; you can redistribute it and/or modify  *
 
4897
 *   it under the terms of the GNU General Public License as published by  *
 
4898
 *   the Free Software Foundation; either version 2 of the License, or     *
 
4899
 *   (at your option) any later version.                                   *
 
4900
 *                                                                         *
 
4901
 ***************************************************************************/
 
4902
 
 
4903
 
 
4904
#ifndef KPENBRUSHDLG_H
 
4905
#define KPENBRUSHDLG_H
 
4906
 
 
4907
//Generated area. DO NOT EDIT!!!(begin)
 
4908
#include &lt;qwidget.h&gt;
 
4909
#include &lt;qspinbox.h&gt;
 
4910
#include &lt;qlabel.h&gt;
 
4911
#include &lt;qpushbutton.h&gt;
 
4912
//Generated area. DO NOT EDIT!!!(end)
 
4913
 
 
4914
#include &lt;qdialog.h&gt;
 
4915
#include &lt;klocale.h&gt;
 
4916
 
 
4917
/**
 
4918
  *@author Ralf Nolden
 
4919
  */
 
4920
 
 
4921
class KPenBrushDlg : public QDialog  {
 
4922
   Q_OBJECT
 
4923
public:
 
4924
  KPenBrushDlg(int curr, QWidget *parent=0, const char *name=0);
 
4925
  ~KPenBrushDlg();
 
4926
 
 
4927
  int width() { return width_spbox-&gt;value(); };
 
4928
  
 
4929
protected slots:
 
4930
  void slotDefault();
 
4931
 
 
4932
protected:
 
4933
  void initDialog();
 
4934
  //Generated area. DO NOT EDIT!!!(begin)
 
4935
  QSpinBox *width_spbox;
 
4936
  QLabel *width_label;
 
4937
  QPushButton *default_btn;
 
4938
  QPushButton *ok_btn;
 
4939
  QPushButton *cancel_btn;
 
4940
  //Generated area. DO NOT EDIT!!!(end)
 
4941
 
 
4942
private:
 
4943
};
 
4944
 
 
4945
#endif
 
4946
 
 
4947
</programlisting>
 
4948
</para>
 
4949
</sect1>
 
4950
 
 
4951
<sect1 id="kpenbrushdlg.cpp">
 
4952
<title>kpenbrushdlg.cpp</title>
 
4953
 
 
4954
<para><programlisting>/***************************************************************************
 
4955
                          kpenbrushdlg.cpp  -  description
 
4956
                             -------------------
 
4957
    begin                : Fri Jul 23 1999
 
4958
    copyright            : (C) 1999 by Ralf Nolden
 
4959
    email                : Ralf.Nolden@post.rwth-aachen.de
 
4960
 ***************************************************************************/
 
4961
 
 
4962
/***************************************************************************
 
4963
 *                                                                         *
 
4964
 *   This program is free software; you can redistribute it and/or modify  *
 
4965
 *   it under the terms of the GNU General Public License as published by  *
 
4966
 *   the Free Software Foundation; either version 2 of the License, or     *
 
4967
 *   (at your option) any later version.                                   *
 
4968
 *                                                                         *
 
4969
 ***************************************************************************/
 
4970
 
 
4971
#include "kpenbrushdlg.h"
 
4972
#include &lt;qwhatsthis.h&gt;
 
4973
#include &lt;kapp.h&gt;
 
4974
 
 
4975
KPenBrushDlg::KPenBrushDlg(int curr, QWidget *parent, const char *name)
 
4976
  : QDialog(parent,name,true,WStyle_ContextHelp)
 
4977
{
 
4978
  initDialog();
 
4979
  QWhatsThis::add(width_spbox,i18n("Select brush width"));
 
4980
 
 
4981
  width_spbox-&gt;setValue(curr);
 
4982
  connect(default_btn, SIGNAL(clicked()), this, SLOT(slotDefault()));
 
4983
  connect(ok_btn, SIGNAL(clicked()), this, SLOT(accept()));
 
4984
  connect(cancel_btn, SIGNAL(clicked()), this, SLOT(reject()));
 
4985
}
 
4986
 
 
4987
KPenBrushDlg::~KPenBrushDlg(){
 
4988
}
 
4989
 
 
4990
void KPenBrushDlg::slotDefault(){
 
4991
  width_spbox-&gt;setValue(3);
 
4992
}
 
4993
</programlisting>
 
4994
</para>
 
4995
</sect1>
 
4996
 
 
4997
<sect1 id="kpenbrushdlgdata.cpp">
 
4998
<title>kpenbrushdlgdata.cpp</title>
 
4999
 
 
5000
<para><programlisting>/**********************************************************************
 
5001
            --- KDevelop (KDlgEdit)  generated file ---
 
5002
 
 
5003
            Last generated: Fri Jul 23 10:43:10 1999
 
5004
 
 
5005
            DO NOT EDIT!!!  This file will be automatically
 
5006
            regenerated by KDevelop.  All changes will be lost.
 
5007
 
 
5008
**********************************************************************/
 
5009
#include &lt;kapp.h&gt;
 
5010
#include "kpenbrushdlg.h"
 
5011
 
 
5012
void  KPenBrushDlg::initDialog(){
 
5013
  this-&gt;resize(370,210);
 
5014
  this-&gt;setMinimumSize(0,0);
 
5015
  width_spbox= new QSpinBox(this,"width_spbox");
 
5016
  width_spbox-&gt;setGeometry(150,50,100,25);
 
5017
  width_spbox-&gt;setMinimumSize(0,0);
 
5018
  width_spbox-&gt;setValue(1);
 
5019
  width_spbox-&gt;setRange(1,99);
 
5020
 
 
5021
  width_label= new QLabel(this,"width_label");
 
5022
  width_label-&gt;setGeometry(20,50,120,25);
 
5023
  width_label-&gt;setMinimumSize(0,0);
 
5024
  width_label-&gt;setText(i18n("Pen Width:"));
 
5025
 
 
5026
  default_btn= new QPushButton(this,"default");
 
5027
  default_btn-&gt;setGeometry(30,160,100,30);
 
5028
  default_btn-&gt;setMinimumSize(0,0);
 
5029
  default_btn-&gt;setText(i18n("Default"));
 
5030
  default_btn-&gt;setAutoDefault(true);
 
5031
 
 
5032
  ok_btn= new QPushButton(this,"ok");
 
5033
  ok_btn-&gt;setGeometry(140,160,100,30);
 
5034
  ok_btn-&gt;setMinimumSize(0,0);
 
5035
  ok_btn-&gt;setText(i18n("OK"));
 
5036
  ok_btn-&gt;setAutoDefault(true);
 
5037
 
 
5038
  cancel_btn= new QPushButton(this,"cancel");
 
5039
  cancel_btn-&gt;setGeometry(250,160,100,30);
 
5040
  cancel_btn-&gt;setMinimumSize(0,0);
 
5041
  cancel_btn-&gt;setText(i18n("Cancel"));
 
5042
  cancel_btn-&gt;setAutoDefault(true);
 
5043
 
 
5044
}</programlisting>
 
5045
</para>
 
5046
</sect1>
 
5047
 
 
5048
<sect1 id="resource.h">
 
5049
<title>resource.h</title>
 
5050
 
 
5051
<para><programlisting>/***************************************************************************
 
5052
                          resource.h  -  description
 
5053
                             -------------------
 
5054
    begin                : Mon Jan 31 11:05:05 CET 2000
 
5055
    copyright            : (C) 2000 by Ralf Nolden
 
5056
    email                : Ralf.Nolden@post.rwth-aachen.de
 
5057
 ***************************************************************************/
 
5058
 
 
5059
/***************************************************************************
 
5060
 *                                                                         *
 
5061
 *   This program is free software; you can redistribute it and/or modify  *
 
5062
 *   it under the terms of the GNU General Public License as published by  *
 
5063
 *   the Free Software Foundation; either version 2 of the License, or     *
 
5064
 *   (at your option) any later version.                                   *
 
5065
 *                                                                         *
 
5066
 ***************************************************************************/
 
5067
 
 
5068
#ifndef RESOURCE_H
 
5069
#define RESOURCE_H
 
5070
 
 
5071
#ifdef HAVE_CONFIG_H
 
5072
#include &lt;config.h&gt;
 
5073
#endif
 
5074
 
 
5075
///////////////////////////////////////////////////////////////////
 
5076
// resource.h  -- contains macros used for commands
 
5077
 
 
5078
 
 
5079
///////////////////////////////////////////////////////////////////
 
5080
// COMMAND VALUES FOR MENUBAR AND TOOLBAR ENTRIES
 
5081
 
 
5082
 
 
5083
///////////////////////////////////////////////////////////////////
 
5084
// File-menu entries
 
5085
#define ID_FILE_NEW                 10010
 
5086
#define ID_FILE_OPEN                10020
 
5087
#define ID_FILE_OPEN_RECENT         10030
 
5088
#define ID_FILE_CLOSE               10040
 
5089
 
 
5090
#define ID_FILE_SAVE                10050
 
5091
#define ID_FILE_SAVE_AS             10060
 
5092
 
 
5093
#define ID_FILE_PRINT               10070
 
5094
 
 
5095
#define ID_FILE_QUIT                10080
 
5096
 
 
5097
///////////////////////////////////////////////////////////////////
 
5098
// Edit-menu entries
 
5099
#define ID_EDIT_UNDO                11010
 
5100
#define ID_EDIT_COPY                11020
 
5101
#define ID_EDIT_CUT                 11030
 
5102
#define ID_EDIT_PASTE               11040
 
5103
#define ID_EDIT_CLEAR_ALL           11050
 
5104
 
 
5105
///////////////////////////////////////////////////////////////////
 
5106
// Pen-menu entries
 
5107
#define ID_PEN_COLOR                14010
 
5108
#define ID_PEN_BRUSH                14020
 
5109
 
 
5110
///////////////////////////////////////////////////////////////////
 
5111
// Draw-menu entries
 
5112
#define ID_DRAW_FIND                15010
 
5113
#define ID_DRAW_FREEHAND            15020
 
5114
#define ID_DRAW_LINE                15030
 
5115
#define ID_DRAW_RECT                15040
 
5116
#define ID_DRAW_RECT_FILL           15050
 
5117
#define ID_DRAW_CIRCLE              15060
 
5118
#define ID_DRAW_CIRCLE_FILL         15070
 
5119
#define ID_DRAW_ELLIPSE             15080
 
5120
#define ID_DRAW_ELLIPSE_FILL        15090
 
5121
#define ID_DRAW_SPRAY               15100
 
5122
#define ID_DRAW_FILL                15110
 
5123
#define ID_DRAW_ERASE               15120
 
5124
 
 
5125
///////////////////////////////////////////////////////////////////
 
5126
// View-menu entries
 
5127
#define ID_VIEW_TOOLBAR             12010
 
5128
#define ID_VIEW_STATUSBAR           12020
 
5129
 
 
5130
///////////////////////////////////////////////////////////////////
 
5131
// Window-menu entries
 
5132
#define ID_WINDOW_NEW_WINDOW        13010
 
5133
#define ID_WINDOW_CASCADE           13020
 
5134
#define ID_WINDOW_TILE              13030
 
5135
 
 
5136
///////////////////////////////////////////////////////////////////
 
5137
// Help-menu entries
 
5138
#define ID_HELP_CONTENTS            1002
 
5139
#define ID_HELP_WHATS_THIS          1003
 
5140
///////////////////////////////////////////////////////////////////
 
5141
// General application values
 
5142
#define ID_STATUS_MSG               1001
 
5143
#define TOOLS_TOOLBAR               1
 
5144
#endif // RESOURCE_H
 
5145
</programlisting>
 
5146
</para>
 
5147
</sect1>
 
5148
  </appendix>
 
5149
 
 
5150
<![ %addindex; [ &docindex; ]]>
 
5151
</book>
 
5152
 
 
5153
<!--
 
5154
Local Variables:
 
5155
mode: sgml
 
5156
time-stamp-format:"%02d/%02m/%04y"
 
5157
time-stamp-line-limit:100
 
5158
time-stamp-start:"<date>"
 
5159
time-stamp-end:"</date>"
 
5160
sgml-namecase-general: t
 
5161
sgml-namecase-entity: nil
 
5162
sgml-minimize-attributes: nil
 
5163
sgml-omittag: nil
 
5164
sgml-shorttag: t
 
5165
sgml-general-insert-case: lower
 
5166
End:
 
5167
-->