1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
|
<?xml version="1.0" ?>
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
<!ENTITY % addindex "INCLUDE">
<!ENTITY % Portuguese "INCLUDE"> <!-- change language only here -->
]>
<book lang="&language;">
<bookinfo>
<title>Introdução à Arquitectura do KDE</title>
<date></date>
<releaseinfo></releaseinfo>
<authorgroup>
<author><firstname>Bernd</firstname> <surname>Gehrmann</surname> <affiliation><address><email>bernd@kdevelop.org</email></address></affiliation>
</author>
</authorgroup>
<copyright>
<year>2001</year>
<year>2002</year>
<holder>Bernd Gehrmann</holder>
</copyright>
<legalnotice>&FDLNotice;</legalnotice>
<abstract>
<para>Esta documentação dá uma ideia geral sobre a Plataforma de Desenvolvimento do KDE</para>
</abstract>
<keywordset>
<keyword>KDE</keyword>
<keyword>arquitectura</keyword>
<keyword>desenvolvimento</keyword>
<keyword>programação</keyword>
</keywordset>
</bookinfo>
<chapter id="structure">
<title>Estrutura da biblioteca</title>
<simplesect id="structure-byname">
<title>Bibliotecas por nome</title>
<variablelist>
<varlistentry>
<term><ulink url="kdeapi:tdecore/index.html">tdecore</ulink></term>
<listitem><para>A biblioteca 'tdecore' é a plataforma aplicacional básica para todos os programa baseados no KDE. Ela fornece o acesso ao sistema de configuração, ao tratamento da linha de comandos, o carregamento e manipulação de ícones, alguns itens básicos de comunicação entre processos, tratamento de ficheiros e muitos outros utilitários. </para></listitem>
</varlistentry>
<varlistentry>
<term><ulink url="kdeapi:tdeui/index.html">tdeui</ulink></term>
<listitem><para>A biblioteca <literal>tdeui</literal> fornece vários elementos gráficos e janelas que o Qt não tem ou que tem mas com menos funcionalidades. Inclui também vários elementos itens que são sub-classes das versões do Qt e que se integram melhor com o ambiente do KDE no que respeita às preferências do utilizador. </para></listitem>
</varlistentry>
<varlistentry>
<term><ulink url="kdeapi:tdeio/index.html">tdeio</ulink></term>
<listitem><para>A biblioteca <literal>tdeio</literal> contém funcionalidades para E/S assíncronas e transparentes na rede, assim como o tratamento de tipos MIME. Também contém a janela de ficheiros do KDE e as suas classes auxiliares. </para></listitem>
</varlistentry>
<varlistentry>
<term><ulink url="kdeapi:kjs/index.html">kjs</ulink></term>
<listitem><para>A biblioteca <literal>kjs</literal> contém uma implementação de JavaScript. </para></listitem>
</varlistentry>
<varlistentry>
<term><ulink url="kdeapi:tdehtml/index.html">tdehtml</ulink></term>
<listitem><para>A biblioteca <literal>tdehtml</literal> contém a componente TDEHTML, um elemento de navegação em HTML, com uma API e um processador de DOM e que inclui interfaces para Java e JavaScript. </para></listitem>
</varlistentry>
</variablelist>
</simplesect>
<simplesect id="structure-grouped">
<title>Classes agrupadas</title>
<para>Esqueleto de uma aplicação básica - classes necessárias por quase todas as aplicações. </para>
<itemizedlist>
<listitem><formalpara>
<title><ulink url="kdeapi:tdecore/TDEApplication">TDEApplication</ulink></title>
<para>Inicializa e controla uma aplicação do KDE. </para>
</formalpara></listitem>
<listitem><formalpara>
<title><ulink url="kdeapi:tdecore/KUniqueApplication">KUniqueApplication</ulink></title>
<para>Certifica-se que só uma instância de uma determinada aplicação poderá correr em simultâneo. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEAboutData">TDEAboutData</ulink></title>
<para>Contém as informações da janela Acerca. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDECmdLineArgs">TDECmdLineArgs</ulink></title>
<para>Processamento de argumentos da linha de comandos. </para>
</formalpara></listitem>
</itemizedlist>
<para>Gestão de configurações - acesso à base de dados hierárquica de configuração do KDE, as configurações globais e os recursos da aplicação. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEConfig">TDEConfig</ulink></title>
<para>Fornece o acesso à base de dados de configuração do KDE. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KSimpleConfig">KSimpleConfig</ulink></title>
<para>Acesso a ficheiros de configuração simples, não hierárquicos. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KDesktopFile">KDesktopFile</ulink></title>
<para>Acesso a ficheiros <literal>.desktop</literal>. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEGlobalSettings">TDEGlobalSettings</ulink></title>
<para>Um acesso conveniente a configurações não-específicas de uma aplicação. </para>
</formalpara></listitem>
</itemizedlist>
<para>Tratamento de ficheiros e URLs - descodificação de URLs, ficheiros temporário, etc. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KURL">KURL</ulink></title>
<para>Representa e processa os URLs. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KTempFile">KTempFile</ulink></title>
<para>Cria ficheiros únicos para dados temporários. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KSaveFile">KSaveFile</ulink></title>
<para>Permite gravar os ficheiros de forma atómica. </para>
</formalpara></listitem>
</itemizedlist>
<para>Comunicação inter-processos - classes auxiliares de DCOP e invocação de sub-processos. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEProcess">TDEProcess</ulink></title>
<para>Invoca e controla os processos-filhos. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KShellProcess">KShellProcess</ulink></title>
<para>Invoca os processos-filhos através de uma linha de comandos. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdesu/PtyProcess">PtyProcess</ulink></title>
<para>Comunicação com os processos-filhos através de um pseudo-terminal. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KIPC">KIPC</ulink></title>
<para>Mecanismo simples de IPC com ClientMessages do X11. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:dcop/DCOPClient">DCOPClient</ulink></title>
<para>Troca de mensagens DCOP. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KDCOPPropertyProxy">KDCOPPropertyProxy</ulink></title>
<para>Uma classe 'proxy' que publica as propriedades do Qt através do DCOP. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KDCOPActionProxy">KDCOPActionProxy</ulink></title>
<para>Uma classe 'proxy' que publica uma interface de DCOP para as acções. </para>
</formalpara></listitem>
</itemizedlist>
<para>Classes utilitárias - gestão de memória, expressões regulares, manipulação de cadeias de caracteres, números aleatórios </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KRegExp">KRegExp</ulink></title>
<para>Expressões regulares POSIX. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KStringHandler">KStringHandler</ulink></title>
<para>Uma interface extravagante para manipular cadeias de caracteres. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEZoneAllocator">TDEZoneAllocator</ulink></title>
<para>Um alocador de memória eficiente para grandes grupos de objectos pequenos. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KRandomSequence">KRandomSequence</ulink></title>
<para>Um gerador de números pseudo-aleatórios. </para>
</formalpara></listitem>
</itemizedlist>
<para>Aceleradores de teclado - classes que ajudam a estabelecer associações de teclas consistentes em todo o ambiente de trabalho. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEAccel">TDEAccel</ulink></title>
<para>Uma colecção de atalhos de teclado. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEStdAccel">TDEStdAccel</ulink></title>
<para>Um acesso fácil aos atalhos de teclado comuns. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEGlobalAccel"></ulink></title>
<para>Uma colecção de atalhos de teclado ao nível do sistema. </para>
</formalpara></listitem>
</itemizedlist>
<para>Processamento de imagens - leitura e manipulação de ícones. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEIconLoader">TDEIconLoader</ulink></title>
<para>Carrega os ícones de uma forma dependente do tema. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEIconTheme">TDEIconTheme</ulink></title>
<para>Classes auxiliares para o TDEIconLoader. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KPixmap">KPixmap</ulink></title>
<para>Uma classe de imagens com capacidades de gestão de tons extendidas. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KPixmapEffect">KPixmapEffect</ulink></title>
<para>Efeitos de imagens como gradientes e padrões. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KPixmapIO">KPixmapIO</ulink></title>
<para>Uma conversão rápida de <classname>TQImage</classname> para <classname>QPixmap</classname>. </para>
</formalpara></listitem>
</itemizedlist>
<para>'Drag and Drop' - arrastar objectos de cores e URLs. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KURLDrag">KURLDrag</ulink></title>
<para>Um objecto de arrastamento de URLs. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KColorDrag">KColorDrag</ulink></title>
<para>Um objecto de arrastamento para cores. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KMultipleDrag">KMultipleDrag</ulink></title>
<para>Permite construir objectos de arrastamento a partir de vários outros objectos. </para>
</formalpara></listitem>
</itemizedlist>
<para>Completação Automática </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDECompletion">TDECompletion</ulink></title>
<para>Auto-completação genérica de cadeias de caracteres. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KURLCompletion">KURLCompletion</ulink></title>
<para>Completação automática de URLs. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KShellCompletion">KShellCompletion</ulink></title>
<para>Completação automática de executáveis. </para>
</formalpara></listitem>
</itemizedlist>
<para>Elementos gráficos - classes de listas, réguas, selecção de cores, etc. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEListView">TDEListView</ulink></title>
<para>Uma variante da <classname>QListView</classname> que usa as configurações de sistema do KDE. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEListView">TDEListBox</ulink></title>
<para>Uma variante da <classname>QListBox</classname> que usa as configurações de sistema do KDE. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEListView">TDEIconView</ulink></title>
<para>Uma variante da <classname>QIconView</classname> que usa as configurações de sistema do KDE. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEListView">KLineEdit</ulink></title>
<para>Uma variante da <classname>QLineEdit</classname> com o suporte de completação. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KComboBox">KComboBox</ulink></title>
<para>Uma variante da <classname>QComboBox</classname> com o suporte de completação. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEFontCombo">TDEFontCombo</ulink></title>
<para>Uma lista para seleccionar tipos de letra. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KColorCombo">KColorCombo</ulink></title>
<para>Uma lista para seleccionar cores. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KColorButton">KColorButton</ulink></title>
<para>Um botão para seleccionar cores. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KURLCombo">KURLCombo</ulink></title>
<para>Uma lista para seleccionar nomes de ficheiros e URLs. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdefile/KURLRequester">KURLRequester</ulink></title>
<para>Um campo de texto para seleccionar nomes e URLs de ficheiros. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KRuler">KRuler</ulink></title>
<para>Uma régua. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink
url="kdeapi:tdeui/KAnimWidget">KAnimWidget</ulink></title>
<para>animações. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KNumInput">KNumInput</ulink></title>
<para>Um item para introduzir números. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KPasswordEdit">KPasswordEdit</ulink></title>
<para>Um item para introduzir senhas. </para>
</formalpara></listitem>
</itemizedlist>
<para>Janelas - janelas completas para seleccionar ficheiros, cores e tipos de letra. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdefile/KFileDialog">KFileDialog</ulink></title>
<para>Uma janela de selecção de ficheiros. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KColorDialog">KColorDialog</ulink></title>
<para>Uma janela de selecção de cores. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEFontDialog">TDEFontDialog</ulink></title>
<para>Uma janela de selecção de tipos de letra. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdefile/TDEIconDialog">TDEIconDialog</ulink></title>
<para>Uma janela de selecção de ícones. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KKeyDialog">KKeyDialog</ulink></title>
<para>Uma janela para editar combinações de teclas. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KEditToolBar">KEditToolBar</ulink></title>
<para>Um diálogo para editar barras de ferramentas. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KTipDialog">KTipDialog</ulink></title>
<para>Uma janela de Dica-do-Dia. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEAboutDialog">TDEAboutDialog</ulink></title>
<para>Uma janela Acerca. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KLineEditDlg">KLineEditDlg</ulink></title>
<para>Uma janela simples para introduzir texto. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdefile/KURLRequesterDlg">KURLRequesterDlg</ulink></title>
<para>Uma janela simples para introduzir URLs. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KMessageBox">KMessageBox</ulink></title>
<para>Uma janela para assinalar erros e avisos. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KPasswordDialog">KPasswordDialog</ulink></title>
<para>Uma janela para introduzir senhas. </para>
</formalpara></listitem>
</itemizedlist>
<para>Acções e GUI em XML </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEAction">TDEAction</ulink></title>
<para>Uma abstracção de uma acção que poderá ser associada a menus e barras de ferramentas. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEActionCollection">TDEActionCollection</ulink></title>
<para>Um conjunto de acções. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KXMLGUIClient">KXMLGUIClient</ulink></title>
<para>Um fragmento gráfico que consiste numa colecção de acções e uma árvore de DOM que representa a posição delas na GUI. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeparts/KPartManager">KPartManager</ulink></title>
<para>Faz a gestão da activação dos clientes XMLGUI. </para>
</formalpara></listitem>
</itemizedlist>
<para>'Plugins' e Componentes </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KLibrary">KLibrary</ulink></title>
<para>Representa uma biblioteca carregada dinamicamente. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KLibrary">KLibLoader</ulink></title>
<para>Carregamento de bibliotecas dinâmicas. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KLibFactory">KLibFactory</ulink></title>
<para>Uma fábrica de objectos para 'plugins'. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KServiceType">KServiceType</ulink></title>
<para>Representa um tipo de serviço. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KService">KService</ulink></title>
<para>Representa um serviço. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KMimeType">KMimeType</ulink></title>
<para>Representa um tipo MIME. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KServiceTypeProfile">KServiceTypeProfile</ulink></title>
<para>Preferências do utilizador para os mapeamentos dos tipos MIME. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KServiceTypeProfile">TDETrader</ulink></title>
<para>Pesquisa de serviços. </para>
</formalpara></listitem>
</itemizedlist>
</simplesect>
</chapter>
<chapter id="graphics">
<title>Gráficos</title>
<sect1 id="graphics-qpainter">
<title>Gráficos de baixo nível com o QPainter</title>
<simplesect id="qpainter-rendering">
<title>Desenhar no QPainter</title>
<para>O modelo de imagens de baixo nível do Qt é baseado nas capacidades oferecidas pelo X11 e por outros sistemas de janelas para os quais o Qt foi implementado. Mas também as extende, implementando funcionalidades adicionais como as transformações arbitrárias por afinidade para texto e imagens. </para>
<para>A classe gráfica central para o desenho 2D com o Qt é a <ulink url="kdeapi:qt/QPainter">QPainter</ulink>. Ela poderá desenhar num <ulink url="kdeapi:qt/QPaintDevice">QPaintDevice</ulink>. Existem três dispositivos de pintura implementados: um é o <ulink url="kdeapi:qt/TQWidget">TQWidget</ulink> que representa um elemento gráfico no ecrã. A outra é o <ulink url="kdeapi:qt/QPrinter">QPrinter</ulink> que representa uma impressora e que produz o resultado em &PostScript;. A terceira é a <ulink url="kdeapi:qt/QPicture">QPicture</ulink> que guarda os comandos de desenho e que poderá gravá-los em disco e reproduzi-los depois. Uma formato possível para os comandos de desenho é a norma SVG da W3C. </para>
<para>Como tal, é possível reaproveitar o código de desenho que você usa para mostrar num item gráfico ou para imprimir, usando as mesmas funcionalidades suportadas. Claro que, na prática, o código é usado num contexto ligeiramente diferente. Desenhar num item gráfico é quase exclusivamente feito no método <methodname>paintEvent()</methodname> da classe de um elemento gráfico. </para>
<programlisting>void ElementoXPTO::paintEvent()
{
QPainter p(this);
// Configurar o pintor
// Usar o pintor
}
</programlisting>
<para>Ao desenhar numa impressora, você terá de se certificar que usa o <methodname>QPrinter::newPage()</methodname> para terminar uma página e começar uma nova - algo que naturalmente não é relevante ao desenhar elementos gráficos. Também, durante a impressão, você poderá querer usar a classe de <ulink url="kdeapi:qt/QPaintDeviceMetrics">métricas do dispositivo</ulink> para poder calcular as coordenadas. </para>
</simplesect>
<simplesect id="qpainter-transformations">
<title>Transformações</title>
<para>Por omissão, ao usar o QPainter, ele desenha no sistema de coordenadas natural do dispositivo usado. Isto significa que, se você desenhar uma linha horizontal no eixo horizontal com um tamanho de 10 unidades, ele será pintado ao longo do ecrã com um tamanho de 10 pixels. Contudo, o QPainter pode aplicar várias transformações antes de desenhar propriamente as formas e as curvas. Uma transformação por afinidade mapeia as coordenadas X e Y linearmente em X' e Y' de acordo com </para>
<mediaobject>
<imageobject><imagedata fileref="affine-general.png"/></imageobject>
</mediaobject>
<para>A matriz 3x3 desta equação poderá ser configurada com o método <methodname>QPainter::setWorldMatrix()</methodname> e é do tipo <ulink url="kdeapi:qt/QWMatrix">QWMatrix</ulink>. Normalmente, esta é a matriz identidade, isto é, o m11 e o m22 are one, e os outros parâmetros são zero. Existem basicamente três grupos diferentes de transformações: </para>
<itemizedlist>
<listitem><formalpara>
<title>Translações</title>
<para>Estas movem todos os pontos de um objecto de uma determinada quantidade numa dada direcção. A matriz de translação poderá ser obtida, invocando o método 'm.translate(dx, dy)' para uma QWMatrix. Isto corresponde à matriz </para>
</formalpara>
<mediaobject>
<imageobject><imagedata fileref="affine-translate.png"/></imageobject>
</mediaobject>
</listitem>
<listitem><formalpara>
<title>Redimensionamento</title>
<para>Esta matriz aumenta ou encolhe as coordenadas de um objecto, tornando-o maior ou menor sem o distorcer. Uma transformação de escala poderá ser aplicada a uma QWMatrix se invocar o m.scale(sx, sy). Isto corresponde à matriz </para>
</formalpara>
<mediaobject>
<imageobject><imagedata fileref="affine-scale.png"/></imageobject>
</mediaobject>
<para>Configurando um dos parâmetros como negativo, uma pessoa poderá obter um espelho do sistema de coordenadas. </para>
</listitem>
<listitem><formalpara>
<title>Inclinação</title>
<para>Uma distorção do sistema de coordenadas com dois parâmetros. Uma transformação por inclinação poderá ser aplicada se chamar m.shear(sh, sv), correspondendo à matriz </para>
</formalpara>
<mediaobject>
<imageobject><imagedata fileref="affine-shear.png"/></imageobject>
</mediaobject>
</listitem>
<listitem><formalpara>
<title>Rotação</title>
<para>Isto roda um objecto. Uma transformação por rotação poderá ser aplicada se chamar m.rotate(alfa). Lembre-se que o ângulo tem de ser dado em graus, não como um ângulo matemático! A matriz correspondente é </para>
</formalpara>
<mediaobject>
<imageobject><imagedata fileref="affine-rotate.png"/></imageobject>
</mediaobject>
<para>Repare que uma rotação é equivalente a uma combinação de uma escala com uma inclinação. </para>
</listitem>
</itemizedlist>
<para>Aqui estão algumas imagens que mostram o efeito das transformações elementares à nossa mascote: </para>
<informaltable frame="none">
<tgroup cols="3">
<tbody>
<row>
<entry><mediaobject>
<imageobject><imagedata fileref="konqi-normal.png"/></imageobject>
</mediaobject></entry>
<entry><mediaobject>
<imageobject><imagedata fileref="konqi-rotated.png"/></imageobject>
</mediaobject></entry>
<entry><mediaobject>
<imageobject><imagedata fileref="konqi-sheared.png"/></imageobject>
</mediaobject></entry>
<entry><mediaobject>
<imageobject><imagedata fileref="konqi-mirrored.png"/></imageobject>
</mediaobject></entry>
</row>
<row>
<entry>a) Normal</entry>
<entry>b) Rodado em 30 graus</entry>
<entry>c) inclinado em 0,4</entry>
<entry>d) Espelhado</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>As transformações podem ser combinadas, multiplicando as matrizes elementares. Repare que as operações com matrizes não comutativas de um modo geral, como tal o efeito combinado de uma concatenação depende da ordem pela qual as matrizes são multiplicadas. </para>
</simplesect>
<simplesect id="qpainter-strokeattributes">
<title>Definir os atributos dos traços</title>
<para>O desenho das linhas, curvas e contornos dos polígonos pode ser modificado se aplicar um traço especial com o QPainter::setPen(). O argumento desta função é um objecto <ulink url="kdeapi:qt/QPen">QPen</ulink>. As propriedades gravadas nele são o estilo, a cor, o estilo da junção e o estilo dos extremos. </para>
<para>O estilo do traço é um membro do tipo enumerado <ulink url="kdeapi:qt/Qt#PenStyle-enum">TQt::PenStyle</ulink> e poderá ter um dos seguintes valores: </para>
<mediaobject>
<imageobject><imagedata fileref="penstyles.png"/></imageobject>
</mediaobject>
<para>O estilo da junção é um membro do tipo enumerado <ulink url="kdeapi:qt/Qt#PenJoinStyle-enum">TQt::PenJoinStyle</ulink>. Ele indica como é que a junção entre várias linhas anexadas umas às outras é desenhada. Ela poderá ter um dos seguintes valores: </para>
<informaltable frame="none">
<tgroup cols="3">
<tbody>
<row>
<entry><mediaobject>
<imageobject><imagedata fileref="joinmiter.png"/></imageobject>
</mediaobject></entry>
<entry><mediaobject>
<imageobject><imagedata fileref="joinbevel.png"/></imageobject>
</mediaobject></entry>
<entry><mediaobject>
<imageobject><imagedata fileref="joinround.png"/></imageobject>
</mediaobject></entry>
</row>
<row>
<entry>a) MiterJoin</entry>
<entry>c) BevelJoin</entry>
<entry>b) RoundJoin</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>O estilo dos extremos é um membro do tipo enumerado <ulink url="kdeapi:qt/Qt#PenCapStyle-enum">TQt::PenCapStyle</ulink> e corresponde à forma como os extremos das linhas são desenhados. Poderá ser igual a um dos valores da seguinte tabela: </para>
<informaltable frame="none">
<tgroup cols="3">
<tbody>
<row>
<entry><mediaobject>
<imageobject><imagedata fileref="capflat.png"/></imageobject>
</mediaobject></entry>
<entry><mediaobject>
<imageobject><imagedata fileref="capsquare.png"/></imageobject>
</mediaobject></entry>
<entry><mediaobject>
<imageobject><imagedata fileref="capround.png"/></imageobject>
</mediaobject></entry>
</row>
<row>
<entry>a) FlatCap</entry>
<entry>b) SquareCap</entry>
<entry>c) RoundCap</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</simplesect>
<simplesect id="qpainter-fillattributes">
<title>Definir os atributos do preenchimento</title>
<para>O estilo de preenchimento dos polígonos, dos círculos e dos rectângulo poderá ser modificado se definir um pincel especial com o QPainter::setBrush(). Esta função recebe um objecto <ulink url="kdeapi:qt/QBrush">QBrush</ulink> como argumento. Os pincéis podem ser construídos de quatro formas diferentes: </para>
<itemizedlist>
<listitem>
<para>QBrush::QBrush() - Isto cria um pincel que não preenche as formas geométricas.</para>
</listitem>
<listitem>
<para>QBrush::QBrush(BrushStyle) - Isto cria um pincel preto com um dos padrões predefinidos que são mostrados em baixo.</para>
</listitem>
<listitem>
<para>QBrush::QBrush(const TQColor &, BrushStyle) - Isto cria um pincel colorido com um dos seguinte padrões mostrados em baixo.</para>
</listitem>
<listitem>
<para>QBrush::QBrush(const TQColor &, const QPixmap) - Isto cria um pincel colorido com o padrão personalizado que você passar como segundo parâmetro.</para>
</listitem>
</itemizedlist>
<para>Um estilo de pincel predefinido pertence ao tipo enumerado <ulink url="kdeapi:qt/Qt#BrushStyle-enum">TQt::BrushStyle</ulink>. Aqui está uma imagem com todos os padrões predefinidos: </para>
<mediaobject>
<imageobject><imagedata fileref="brushstyles.png"/></imageobject>
</mediaobject>
<para>Uma outra forma de personalizar o comportamento do pincel é usando a função <methodname>QPainter::setBrushOrigin()</methodname>. </para>
</simplesect>
<simplesect id="qpainter-color">
<title>Cor</title>
<para>As cores têm um papel activo, quer a traçar as curvas, quer a preencher as formas geométricas. No Qt, as cores são representadas pela classe <ulink url="kdeapi:qt/TQColor">TQColor</ulink>. O Qt não suporta as funcionalidades gráficas avançadas, como os perfis de cores ICC e a correcção de cores. As cores são normalmente definidas, indicando os valores das componentes vermelha, verde e azul, dado que o modelo RGB é a forma como os pixels são compostos num monitor. </para>
<para>É também possível usar o matiz, a saturação e o valor. Esta representação HSV é a que você usa na janela de cores do Gtk, p.ex. no GIMP. Aí, o matiz corresponde ao ângulo na roda de cores, enquanto a saturação corresponde à distância ao centro do círculo. O valor pode ser escolhido com uma barra em separado. </para>
</simplesect>
<simplesect id="qpainter-paintsettings">
<title>Outras configurações</title>
<para>Normalmente, quando você desenha num dispositivo de pintura, os pixels que você desenho substituem os que lá estavam anteriormente. Isto significa que, se você pintar uma dada região com uma cor vermelho e pintar a mesma região com uma cor azul depois, só a cor azul ficará visível. O modelo de imagens do Qt não suporta a transparência, i.e., uma forma de misturar o fundo preenchido e os desenhos. Contudo, existe uma forma simples de combinar o desenho e o fundo com operadores booleanos. O método QPainter::setRasterOp() define o operador usado, que vem do tipo enumerado <ulink url="kdeapi:qt/Qt#RasterOp-enum">RasterOp</ulink>. </para>
<para>O valor por omissão é o CopyROP que ignora o fundo. Outra escolha normal é a XorROP. Se você pintar uma linha a preto com este operador numa imagem colorida, então a área coberta será invertida. Este efeito é usado, por exemplo, para criar as selecções tracejadas dos programas de manipulação de imagens que são conhecidas por "formigas a marchar". </para>
</simplesect>
<simplesect id="qpainter-primitives">
<title>Desenhar primitivas gráficas</title>
<para>Na secção seguinte iremos listar os elementos gráficos primitivos suportados pelo QPainter. A maioria deles existem em várias versões alternativas que recebem um conjunto diferente de argumentos. Por exemplo, os métodos que lidam com rectângulos normalmente recebem um <ulink url="kdeapi:qt/QRect">QRect</ulink> como argumento, ou então um conjunto de quatro inteiros. </para>
<itemizedlist>
<listitem>
<para>Desenhar um único ponto - drawPoint().</para>
</listitem>
<listitem>
<para>Desenhar linhas - drawLine(), drawLineSegments() e drawPolyLine().</para>
</listitem>
<listitem>
<para>Desenhar e preencher rectângulos - drawRect(), drawRoundRect(), fillRect() e eraseRect().</para>
</listitem>
<listitem>
<para>Desenhar e preencher círculos, elipses ou partes deles - drawEllipse(), drawArc(), drawPie e drawChord().</para>
</listitem>
<listitem>
<para>Desenhar e preencher polígonos gerais - drawPolygon().</para>
</listitem>
<listitem>
<para>Desenhar curvas Bezier - drawQuadBezier() [drawCubicBezier no Qt 3.0].</para>
</listitem>
</itemizedlist>
</simplesect>
<simplesect id="qpainter-pixmaps">
<title>Desenhar imagens</title>
<para>O Qt oferece duas classes muito diferentes para representar as imagens. </para>
<para>A <ulink url="kdeapi:qt/QPixmap">QPixmap</ulink> corresponde directamente aos objectos das imagens no X11. As imagens são objectos do lado do servidor e podem - numa placa gráfica moderna - até mesmo ser gravadas directamente na memória da placa. Isto torna <emphasis>bastante</emphasis> eficiente a transferência de imagens para o ecrã. As imagens também funcionam como um equivalente, fora do ecrã , dos elementos gráficos - a classe QPixmap é uma subclasse da QPaintDevice, por isso você poderá desenhar nela com um QPainter. As operações elementares de desenho são normalmente aceleradas pelos dispositivos gráficos modernos. Daí, um padrão de uso normal é usar as imagens para fazer duplo-'buffering'. Isto significa que, em vez de desenhar directamente num elemento gráfico, você desenha num objecto temporário de imagem e usa a função <ulink url="kdeapi:qt/QPaintDevice#bitBlt-1">bitBlt</ulink> para transferir a imagem para o elemento gráfico. Para os desenhos complexos, isto ajuda a evitar intermitências. </para>
<para>Em contraste, os objectos <ulink url="kdeapi:qt/TQImage">TQImage</ulink> residem do lado do cliente. A sua ênfase é na fornecer um acesso directo aos pixels da imagem. Isso torna-os úteis para manipular imagens e para coisas como a leitura e gravação em disco (o método load() da QPixmap recebe uma TQImage como passo intermédio). Por outro lado, desenhar uma imagem num elemento gráfico é uma operação relativamente dispendiosa, dado que implica uma transferência para o servidor X, o que ainda poderá levar algum tempo, especialmente para imagens grandes e para servidores remotos. Dependendo da profundidade de cor, a conversão de uma TQImage para uma QPixmap pode necessitar de ajuste de cores. </para>
</simplesect>
<simplesect id="qpainter-drawingtext">
<title>Desenhar texto</title>
<para>O texto poderá ser desenhado com uma das variantes do método QPainter::drawText(). Estas desenham uma TQString quer num dado ponto, quer num dado rectângulo, usando o tipo de letra definido pelo QPainter::setFont(). Existe também um parâmetro que recebe uma combinação do tipo OU de algumas opções dos tipos enumerados <ulink url="kdeapi:qt/Qt#AlignmentFlags-enum">TQt::AlignmentFlags</ulink> e <ulink url="kdeapi:qt/Qt#TextFlags-enum">TQt::TextFlags</ulink> </para>
<para>A partir da versão 3.0, o Qt toma conta da disposição completa do texto, mesmo para as línguas escritas da direita para a esquerda. </para>
<para>Uma forma mais avançada de mostrar o texto marcado é usando a classe <ulink url="kdeapi:qt/QSimpleRichText">QSimpleRichText</ulink>. Os objectos desta classe podem ser construídos com um pedaço de texto que usa um sub-conjunto das marcas de HTML, o qual é bastante rico e até fornece tabelas. O estilo do texto pode ser personalizado com uma <ulink url="kdeapi/qt/QStyleSheet">QStyleSheet</ulink> (a documentação das marcas pode também ser encontrada aqui). Logo que o objecto de texto formatado tenha sido construído, pode ser desenhado num elemento gráfico ou noutro dispositivo de pintura com o método QSimpleRichText::draw(). </para>
</simplesect>
</sect1>
<sect1 id="graphics-qcanvas">
<title>Imagens estruturadas com o QCanvas</title>
<para>A QPainter oferece um modelo de imagens poderosos para desenhar em elementos gráficos e imagens. Contudo, também poderá ser complicadíssimo de usar. De cada vez que o seu elemento gráfico recebe um evento de desenho, ele terá de analisar o QPaintEvent::region() ou o QPaintEvent::rect() que tem de ser desenhado de novo. Aí, ele terá de configurar um QPainter e desenhar todos os objectos que se sobrepõem com essa região. Por exemplo, imagine um programa de gráficos vectoriais que permita arrastar objectos como polígonos, círculos e grupos de outros objectos. De cada vez que esses objectos se movem um pouco, o tratador para os eventos do rato do elemento gráfico irá despoletar um evento para a área toda coberta pelos objectos na sua posição antiga e na sua posição nova. Descobrir quais são as actualizações necessárias e fazê-las de forma eficiente poderá ser difícil e poderá também entrar em conflito com a estrutura orientada por objectos do código-fonte do programa. </para>
<para>Como alternativa, o Qt contém a classe <ulink url="kdeapi:qt/QCanvas">QCanvas</ulink>, na qual você coloca os objectos gráficos, como os polígonos, o texto e as imagens. Você também poderá também fornecer itens adicionais se criar uma subclasse de <ulink url="kdeapi:qt/QCanvasItem">QCanvasItem</ulink> ou uma das suas subclasses especializadas. Uma área de desenho ('canvas') poderá ser mostrada no ecrã por um ou mais elementos gráficos da classe <ulink url="kdeapi:qt/QCanvas">QCanvasView</ulink>, a qual você terá de criar uma subclasse para tratar das interacções com o utilizador. O Qt tratará de todas as actualizações do desenho dos objectos na área visível, quer sejam provocadas pela exposição da janela, quer pela criação ou modificação dos objectos ou ainda por qualquer outra razão. Usando o duplo-'buffering', isto poderá ser feito de uma forma eficiente e livre de intermitências. </para>
<para>Os itens da área de desenho podem-se sobrepor uns aos outros. Neste caso, o visível depende da ordem do 'z' que pode ser atribuída pelo QCanvasItem::setZ(). Os itens podem também ser tornados visíveis ou invisíveis. Você pode também indicar um fundo a ser desenhado "por detrás" de todos os itens e uma imagem de primeiro plano. Para associar os eventos do rato com os objectos na área de desenho, existe o método QCanvas::collisions() que devolve uma lista dos itens que se sobrepõem em qualquer ponto. Aqui mostramos uma imagem de uma vista sobre a área de desenho em acção: </para>
<mediaobject>
<imageobject><imagedata fileref="canvas.png"/></imageobject>
</mediaobject>
<para>Aqui, a malha é desenhada no fundo. Para além disso, existe um item QCanvasText item e um QCanvasPolygon violeta. A borboleta é um QCanvasPixmap. Ele tem áreas transparentes, por isso é possível ver os itens de baixo através dele. </para>
<para>Um tutorial sobre a utilização do QCanvas para criar jogos baseados em imagens poderá ser encontrado <ulink url="http://zez.org/article/articleview/2/1/">aqui</ulink>. </para>
</sect1>
<sect1 id="graphics-qglwidget">
<title>Gráficos 3D com o OpenGL</title>
<simplesect id="qglwidget-lowlevel">
<title>Interface de baixo nível</title>
<para>A norma de facto para desenhar gráficos 3D hoje em dia é o <ulink url="http://www.opengl.org">OpenGL</ulink>. As implementações desta especificação vêm com o Microsoft Windows, o Mac OS X e o XFree86 e muitas vezes suportam as funcionalidades de aceleração por 'hardware' oferecidas pelas placas gráficas modernas. O OpenGL em si só lida com o desenho de uma determinada área do ecrã através de um <emphasis>contexto GL</emphasis> e não tem nenhuma interacção com a plataforma do ambiente </para>
<para>O Qt fornece o item <ulink url="kdeapi:qt/QGLWidget">QGLWidget</ulink> que encapsula uma janela com um contexto GL associado. Basicamente, você poderá utilizá-la se criar uma sub-classe dela e implementar de novo alguns métodos. </para>
<itemizedlist>
<listitem><para>Em vez de reimplementar o <methodname>paintEvent()</methodname> e usar o QPainter para desenhar o conteúdo do elemento, você irá sobrepor o <methodname>paintGL()</methodname> e usar os comandos do GL para desenhar uma cena. A <classname>QLWidget</classname> irá tomar conta de tornar o seu contexto GL o actual antes de invocar o <methodname>paintGL()</methodname> e irá remeter tudo no fim. </para></listitem>
<listitem><para>O método virtual <methodname>initializeGL()</methodname> é invocado logo da primeira vez em que o <methodname>resizeGL()</methodname> ou o <methodname>paintGL()</methodname> são chamados. Isto pode ser usado para construir listas de visualização para os objectos e para fazer as várias inicializações. </para></listitem>
<listitem><para>Em vez de reimplementar o <methodname>resizeEvent()</methodname>, você irá sobrepor o <methodname>resizeGL()</methodname>. Este poderá ser usado para definir apropriadamente o porto de visualização. </para></listitem>
<listitem><para>Em vez de invocar o <methodname>update()</methodname> sempre que o estado da cena é mudado - por exemplo, quando você o anima com um temporizador -, você deverá invocar o <methodname>updateGL()</methodname>. Isto irá despoletar uma actualização. </para></listitem>
</itemizedlist>
<para>De um modo geral, o QGLWidget comporta-se como outro item gráfico, i.e., por exemplo, você poderá processar os eventos normais do rato como de costume, redimensionar a janela e combiná-la com outras numa dada disposição. </para>
<mediaobject>
<imageobject><imagedata fileref="opengl.png"/></imageobject>
</mediaobject>
<para>O Qt contém alguns exemplos de utilização do QGLWidget no seu exemplo <literal>demo</literal>. Pode-se encontrar uma colecção de tutoriais <ulink url="http://www.libsdl.org/opengl/intro.html">aqui</ulink>, assim como mais informações e uma referência ao OpenGL, na <ulink url="http://www.opengl.org">página pessoal do OpenGL</ulink>. </para>
</simplesect>
<simplesect id="qglwidget-highlevel">
<title>Interfaces de alto-nível</title>
<para>O OpenGL é uma interface de relativo baixo nível para gráficos 3D. Da mesma forma que o QCanvas dá ao programador uma interface de maior nível com detalhes para os objectos e as suas propriedades, existem também interfaces de alto nível para os gráficos 3D. Uma das mais conhecidas é o Open Inventor. Sendo originalmente uma tecnologia desenvolvida pela SGI, existe hoje em dia também a implementação 'open-source' que é a <ulink url="http://www.coin3d.org">Coin</ulink>, complementada por uma interface para a plataforma e para o Qt chamada SoQt. </para>
<para>O conceito básico do Open Inventor é o de uma <emphasis>cena</emphasis>. Uma cena poderá ser carregada a partir do disco e gravada num formato ligeiramente relacionado com o <ulink url="http://www.vrml.org">VRML</ulink>. Uma cena consiste numa colecção de objectos chamados <emphasis>nós</emphasis>. O Inventor já contém uma rica colecção de nós reutilizáveis, como cubos, cilindros e malhas, complementados por fontes de luz, materiais, câmaras, etc. Os nós são representados por classes de C++ e podem ser combinados e herdados. </para>
<para>Pode-se encontrar uma introdução ao Inventor <ulink url="http://www.motifzone.com/tmd/articles/OpenInventor/OpenInventor.html">aqui</ulink> (de um modo geral, você poderá substituir todas as menções ao SoXt por SoQt neste artigo). </para>
</simplesect>
</sect1>
</chapter>
<chapter id="userinterface">
<title>Interface do utilizador</title>
<sect1 id="userinterface-actionpattern">
<title>O padrão de acções</title>
<para></para>
</sect1>
<sect1 id="userinterface-xmlgui">
<title>Definir os menus e as barras de ferramentas em XML</title>
<simplesect id="xmlgui-intro">
<title>Introdução</title>
<para>Embora o <link linkend="userinterface-actionpattern">padrão de acções</link> permita encapsular as acções despoletadas pelo utilizador num objecto que possa estar "ligado" noutro sítio qualquer nos menus ou nas barras de ferramentas, ele não resolve por si só o problema de construir os próprios menus. Em particular, você terá de criar todos os menus em código de C++ e inserir explicitamente as acções por uma determinada ordem, segundo as considerações dos guias de estilo para as acções normais. Isto torna bastante difícil para os utilizadores poderem personalizar os menus ou alterar os menus ou os atalhos de teclado de acordo com as suas necessidades, sem ter de alterar o código-fonte. </para>
<para>Este problema é resolvido através de um conjunto de classes chamado <literal>XMLGUI</literal>. Basicamente, isto separa as acções (codificadas em C++) da sua aparência nas barras de menu e de ferramentas (codificadas em XML). Sem modificar nenhum código-fonte, os menus podem simplesmente ser personalizados, ajustando um ficheiro de XML. Para além disso, ajuda a garantir que as acções normais (como o <menuchoice><guimenu>Ficheiro</guimenu><guimenuitem>Abrir</guimenuitem></menuchoice> ou o <menuchoice><guimenu>Ajuda</guimenu><guimenuitem>Acerca</guimenuitem></menuchoice>) aparecem nas localizações indicadas pelos guias de estilo. O XMLGUI é especialmente importante para os programas modulares, em que os itens que aparecem no menu podem resultar de vários 'plugins' ou componentes diferentes. </para>
<para>A classe do KDE para as janelas de topo, a <ulink url="kdeapi:tdeui/TDEMainWindow.html">TDEMainWindow</ulink>, herda de <ulink url="kdeapi:tdeui/KXMLGUIClient.html">KXMLGUIClient</ulink> e, por isso, suporta a XMLGUI logo de raiz. Todas as acções criadas dentro dela terão de ter a <literal>actionCollection()</literal> do cliente como 'pai'. Uma chamada ao <literal>createGUI()</literal> irá então criar o conjunto completo de barras de menu e de ferramentas definidas no ficheiro XML da aplicação (que tem, convencionalmente, o sufixo <literal>ui.rc</literal>). </para>
</simplesect>
<simplesect id="xmlgui-kviewexample">
<title>Um exemplo: Menu do KView</title>
<para>No seguinte exemplo, iremos ver o visualizador de imagens <application>KView</application> do KDE. Ele tem um ficheiro <literal>ui.rc</literal> chamado <filename>kviewui.rc</filename> que é instalado com o código em <filename>Makefile.am</filename> </para>
<programlisting>rcdir = $(kde_datadir)/kview
rc_DATA = kviewui.rc
</programlisting>
<para>Aqui está um excerto do ficheiro <filename>kviewui.rc</filename>. Por questões de simplicidade, mostramos apenas a definição no menu <guimenu>View</guimenu> (Ver). </para>
<programlisting><!DOCTYPE kpartgui>
<kpartgui name="kview">
<MenuBar>
<Menu name="view" >
<Action name="zoom50" />
<Action name="zoom100" />
<Action name="zoom200" />
<Action name="zoomMaxpect" />
<Separator/>
<Action name="fullscreen" />
</Menu>
</MenuBar>
</kpartgui>
</programlisting>
<para>A componente correspondente da configuração em C++ é: </para>
<programlisting>KStdAction::zoomIn ( this, TQ_SLOT(slotZoomIn()), actionCollection() );
KStdAction::zoomOut ( this, TQ_SLOT(slotZoomOut()), actionCollection() );
KStdAction::zoom ( this, TQ_SLOT(slotZoom()), actionCollection() );
new TDEAction ( i18n("&Half size"), ALT+Key_0,
this, TQ_SLOT(slotHalfSize()),
actionCollection(), "zoom50" );
new TDEAction ( i18n("&Normal size"), ALT+Key_1,
this, TQ_SLOT(slotDoubleSize()),
actionCollection(), "zoom100" );
new TDEAction ( i18n("&Double size"), ALT+Key_2,
this, TQ_SLOT(slotDoubleSize()),
actionCollection(), "zoom200" );
new TDEAction ( i18n("&Fill Screen"), ALT+Key_3,
this, TQ_SLOT(slotFillScreen()),
actionCollection(), "zoomMaxpect" );
new TDEAction ( i18n("Fullscreen &Mode"), CTRL+SHIFT+Key_F,
this, TQ_SLOT(slotFullScreen()),
actionCollection(), "fullscreen" );
</programlisting>
<para>O menu <guimenu>View</guimenu> (Ver), resultante desta definição da interface, fica então semelhante ao que aparece nesta imagem: </para>
<mediaobject>
<imageobject><imagedata fileref="kview-menu.png"/></imageobject>
</mediaobject>
<para>O ficheiro XML começa com uma declaração do tipo de documento. O DTD do 'kpartgui' pode ser encontrado no código-fonte do 'tdelibs' em <filename>tdeui/kpartgui.dtd</filename>. O elemento exterior do ficheiro contém o nome da instância da aplicação como atributo. Poderá também conter um número de versão no formato "version=2". Isto é útil quando você lança novas versões de uma aplicação com uma estrutura de menus alterada, p.ex., com mais funcionalidades. Se você fornecer o número da versão no ficheiro <literal>ui.rc</literal>, o KDE certifica-se que qualquer versão personalizada do ficheiro é eliminada e passa a ser usado o novo ficheiro em alternativa. </para>
<para>A próxima linha, a <literal><MenuBar></literal>, contém a declaração de um menu. Você poderá também introduzir uma quantidade qualquer de declarações de <literal><ToolBar></literal> para criar algumas barras de ferramentas. O menu contém um submenu com o nome "view" (ver). Este nome já está predefinido e, por isso, irá ver a versão traduzida de "View" (no caso do português, "Ver") na imagem. Se você declarar os seus próprios submenus, você terá de adicionar explicitamente o título. Por exemplo, o <application>KView</application> tem um submenu com o título "Image" (Imagem) que é declarado da seguinte forma: </para>
<programlisting><Menu name="image" >
<text>&amp;Image</text>
...
</Menu>
</programlisting>
<para>Na plataforma do 'automake' do KDE, esses títulos são automaticamente extraídos e colocados no ficheiro <ulink url="tde-i18n-howto.html"><literal>.po</literal></ulink> da aplicação, para que seja usados pelos tradutores. Lembre-se que você tem de representar o marcador de aceleradores "&" na forma compatível com o XML "&amp;". </para>
<para>Voltando ao exemplo do <application>KView</application>, o seu menu <guimenu>View</guimenu> contém um conjunto de acções personalizadas: <literal>zoom50</literal>, <literal>zoom100</literal>, <literal>zoom200</literal>, <literal>zoomMaxpect</literal> e <literal>fullscreen</literal>, declaradas com um elemento <literal><Action></literal>. O separador nas imagens corresponde ao elemento <literal><Separator></literal>. </para>
<para>Você irá reparar que alguns itens do menu não têm um elemento correspondente no ficheiro XML. Estes são as <emphasis>acções-padrão</emphasis>. As acções-padrão são criadas pela classe <ulink url="kdeapi:tdeui/KStdAction.html">KStdAction</ulink>. Quando você cria essas acções na sua aplicação (como no exemplo em C++ acima), elas serão automaticamente introduzidas numa posição prescrita, e possivelmente com uma tecla de atalho. Você poderá procurar essas localizações no ficheiro <filename>tdeui/ui_standards.rc</filename> no código-fonte do 'tdelibs'. </para>
</simplesect>
<simplesect id="xmlgui-konqexample">
<title>Um exemplo: Barras de Ferramentas no Konqueror</title>
<para>Para a discussão das barras de ferramentas, o foco será agora a definição da GUI do <application>Konqueror</application>. Este excerto define a barra de localização, que contém o campo de introdução de URLs. </para>
<programlisting><ToolBar name="locationToolBar" fullWidth="true" newline="true" >
<text>Location Toolbar</text>
<Action name="clear_location" />
<Action name="location_label" />
<Action name="toolbar_url_combo" />
<Action name="go_url" />
</ToolBar>
</programlisting>
<para>A primeira coisa que salta à vista é que existem muitos mais atributos que nos menus. Estes incluem: </para>
<itemizedlist>
<listitem><para><literal>fullWidth</literal>: Diz ao XMLGUI que a barra de ferramentas tem a mesma largura que a janela de topo. Dado que este está igual a "false" (falso), a barra de ferramentas só ocupa o espaço necessário e poderão ser colocadas mais barras de ferramentas na mesma linha. </para></listitem>
<listitem><para><literal>newline</literal>: Este está relacionado com a opção acima. Se for igual a "true" (verdadeiro), a barra de ferramentas inicia uma nova linha. Caso contrário, poderá ser colocada na mesma linha que a barra anterior. </para></listitem>
<listitem><para><literal>noEdit</literal>: Normalmente as barras de ferramentas podem ser personalizadas pelo utilizador, p.ex. na opção <menuchoice><guimenu>Configuração</guimenu><guimenuitem>Configurar as Barras de Ferramentas</guimenuitem></menuchoice> do <application>Konqueror</application>. Se esta opção for igual a "true" (verdadeiro), a barra de ferramentas em questão não fica editável. Isto é importante para as barras de ferramentas que são carregadas com itens na altura da execução, como por exemplo a barra de Favoritos do <application>Konqueror</application>. </para></listitem>
<listitem><para><literal>iconText</literal>: Diz ao XMLGUI para mostrar o texto da acção ao lado do ícone. Normalmente, o texto só é mostrado como uma dica quando o cursor do rato se mantiver em cima do ícone durante algum tempo. Os valores possíveis para este atributo são o "icononly" (mostra só o ícone), "textonly" (mostra só o texto), "icontextright" (mostra o texto do lado direito do ícone) e "icontextbottom" (mostra o texto por baixo do ícone). </para></listitem>
<listitem><para><literal>hidden</literal>: Se este valor for "true" (verdadeiro), a barra de ferramentas não fica visível inicialmente e deverá ser activada por um item de menu qualquer. </para></listitem>
<listitem><para><literal>position</literal>: O valor por omissão para este atributo é o "top", que significa que a barra de ferramentas fica por baixo do menu. Para os programas com várias ferramentas, como os programas gráficos, poderá ser interessante substituir isto por "left" (esquerda), "right" (direita) ou "bottom" (baixo). </para></listitem>
</itemizedlist>
</simplesect>
<simplesect id="xmlgui-dynamical">
<title>Menus dinâmicos</title>
<para>Obviamente, um ficheiro XML só poderá conter uma descrição estática da interface do utilizador. Normalmente, existem menus que mudam durante a execução. Por exemplo, o menu do <application>Konqueror</application> <guimenu>Localização</guimenu> contém um conjunto de itens <guimenuitem>Abrir com XPTO</guimenuitem> com as aplicações que são capazes de abrir um dado ficheiro com um dado tipo MIME. De cada vez que o documento apresentado muda, a lista de itens do menu muda. O XMLGUI está preparado para lidar com estes casos, usando a noção de <emphasis>listas de acções</emphasis>. Uma lista de acções é declarada como um itm no ficheiro XML, mas de facto consiste em várias acções que são associadas ao menu durante a execução. O exemplo acima está implementado com a seguinte declaração no ficheiro XML do <application>Konqueror</application>: </para>
<programlisting><Menu name="file">
<text>&amp;Location</text>
...
<ActionList name="openwith">
...
</Menu>
</programlisting>
<para>A função <function>KXMLGUIClient::plugActionList()</function> é então usada para adicionar as acções a mostrar, enquanto que a função <function>KXMLGuiClient::unplugActionList()</function> remove todas as acções ligadas. A rotina responsável pela actualização é semelhante à seguinte: </para>
<programlisting>void JanelaPrincipal::actualizarAccoesAbrirCom()
{
unplugActionList("openwith"); // Nome declarado no ficheiro XML
accoesAbrirCom.clear();
for ( /* iterar pelos serviços relevantes */ ) {
TDEAction *accao = new TDEAction( ...);
accoesAbrirCom.append(accao);
}
plugActionList("openwith", accoesAbrirCom);
}
</programlisting>
<para>Lembre-se que, em contraste com as acções estáticas, as que aqui são criadas <emphasis>não</emphasis> têm a colecção de acções como 'mãe', como tal você é responsável por removê-las você mesmo. A forma mais simples de o fazer é usando o método <literal>accoesAbrirCom.setAutoDelete(true)</literal> no exemplo acima. </para>
</simplesect>
<simplesect id="xmlgui-contextmenus">
<title>Menus de contexto</title>
<para>Os exemplos acima só continham casos em que as barras de menu e de ferramentas de uma janela principal eram criados. Existem os casos em que os processos de criação destes repositórios estão completamente escondidos do programador por detrás da chamada do <function>createGUI()</function> (excepto se você tiver repositórios personalizados). Contudo, existem casos em que você deseja construir outros repositórios e preenchê-los com definições da GUI a partir do ficheiro XML. Um desses exemplos são os menus de contexto. Para obter uma referência a um menu de contexto, você terá de pedir ao criador ('factory') do cliente essa referência: </para>
<programlisting>void JanelaPrincipal::menuPedido()
{
TQWidget *m = factory()->container("menu_contexto", this);
QPopupMenu *menu = static_cast<QPopupMenu *>(m);
menu->exec(QCursor::pos());
}
</programlisting>
<para>O método <function>KXMLGUIFactory::container()</function> usado acima procura onde encontrar um repositório no ficheiro XML com o nome indicado. Nesse caso, uma definição possível poderia ser semelhante à seguinte: </para>
<programlisting>...
<Menu name="menu_contexto">
<Action name="ficheiro_adicionar"/>
<Action name="ficheiro_remover"/>
</Menu>
...
</programlisting>
</simplesect>
</sect1>
<sect1 id="help">
<title>Fornecer ajuda 'online'</title>
<para>Tornar um programa intuitivo e fácil de usar envolve um conjunto de funcionalidades que são chamadas normalmente de ajuda 'online'. A ajuda 'online' tem vários objectivos, alguns deles em conflito: por um lado, deverá dar ao utilizador respostas à pergunta "Como é que faço uma determinada tarefa?"; por outro lado, deverá ajudar o utilizador a explorar a aplicação e a encontrar funcionalidades que ainda não conhece. É importante reconhecer que isto só poderá ser conseguido se oferecer vários níveis de ajuda: </para>
<itemizedlist>
<listitem><para>As dicas de ferramentas são pequenas legendas que aparecem por cima dos elementos da interface gráfica, sempre que o cursor do rato fica algum tempo sobre eles. Elas são especialmente importantes para as barras de ferramentas, onde os ícones nem sempre são suficientes para explicar o intuito de um botão. </para></listitem>
<listitem><para>A ajuda o "O que é isto?" é normalmente uma explicação mais extensa e mais rica sobre um elemento gráfico ou um item do menu. É também mais complicada de usar: nas janelas, pode ser invocadas de duas formas: quer carregando em <keycombo><keycap>Shift</keycap><keycap>F1</keycap></keycombo> ou carregando no ponto de interrogação na barra de título (onde o suporte para a última depende do gestor de janelas). O cursor do rato irá então mudar para uma seta com um ponto de interrogação, onde a janela de ajuda aparece sempre que um elemento da interface for pressionado. A ajuda "o que é isto?" para os itens do menu é normalmente activada por um botão na barra de ferramentas que contém uma seta e um ponto de interrogação. </para></listitem>
<listitem><para>O problema com esta abordagem é que o utilizador não consegue ver se um elemento contém ajudas ou não. Quando o utilizador activa o botão do ponto de interrogação e não obtém nenhuma janela de ajuda quando carregar num elemento da interface do utilizador, ele irá ficar frustrado muito depressa. </para>
<para>A vantagem das janelas de ajuda "O Que É Isto?" oferecidas pelo Qt e pelo KDE é que elas poderão conter <ulink url="kdeapi:qt/QStyleSheet">texto formatado</ulink>, i.e. poderão conter vários tipos de letra, texto em negrito e itálico, ou mesmo imagens e tabelas. </para>
<para>Um exemplo de uma ajuda "O Que É Isto?": </para>
<mediaobject>
<imageobject><imagedata fileref="whatsthis.png"/></imageobject>
</mediaobject>
</listitem>
<listitem><para>Finalmente, todos os programas deverão ter um manual. Um manual é normalmente visto no <application>KHelpCenter</application>, activando o menu <guimenu>Ajuda</guimenu>. Isto significa, que uma aplicação adicional completa aparece e distrai o utilizador do seu trabalho. Por consequência, a consulta do manual só deverá ser necessária se as outras funcionalidades como as dicas e a ajuda "o que é isto?" não forem suficientes. Obviamente, um manual tem a vantagem que não explica apenas aspectos únicos e isolados da interface do utilizador. Em vez disso, ele poderá explicar aspectos da aplicação num contexto mais amplo. Os manuais para o KDE são escritos usando a linguagem de formatação <ulink url="http://i18n.kde.org">DocBook</ulink>. </para></listitem>
</itemizedlist>
<para>Do ponto de vista do programador, o Qt oferece uma API fácil de usar para a ajuda 'online'. Para atribuir uma dica a um dado elemento gráfico, use a classe <ulink url="kdeapi:qt/QToolTip">QToolTip</ulink>. </para>
<programlisting>QToolTip::add(e, i18n("Este elemento faz uma dada tarefa."))
</programlisting>
<para>Se as barras de menu e as barras de ferramentas forem criadas com o <ulink url="actionpattern.html">padrão de acções</ulink>, o texto usado como dica deriva do primeiro argumento do construtor da <ulink url="kdeapi:tdeui/TDEAction.html">TDEAction</ulink>: </para>
<programlisting>accao = new TDEAction(i18n("&Remover"), "editdelete",
SHIFT+Key_Delete, actionCollection(), "del")
</programlisting>
<para>Aqui também é possível atribuir um dado texto que é apresentado na barra de estado quando o item do menu respectivo é seleccionado: </para>
<programlisting>action->setStatusText(i18n("Apaga o texto marcado"))
</programlisting>
<para>A API da ajuda "O que é isto?' é bastante parecido. Nas janelas, use o seguinte código: </para>
<programlisting>QWhatsThis::add(e, i18n("<qt>Isto demonstra o motor"
" do <b>Qt</b> para"
" o texto formatado.<ul>"
"<li>Um</li>"
"<li>Dois</li>"
"</ul></qt>"))
</programlisting>
<para>Para os itens do menu, use </para>
<programlisting>accao->setWhatsThis(i18n("Apaga o ficheiro marcado"))
</programlisting>
<para>A invocação do <application>KHelpCenter</application> está encapsulada na classe <ulink url="kdeapi:tdecore/TDEApplication">TDEApplication</ulink>. Para mostrar o manual da sua aplicação, basta usar </para>
<programlisting>kapp->invokeHelp()
</programlisting>
<para>Isto mostra a primeira página com o índice analítico. Quando você quer mostrar apenas uma dada secção do manual, você poderá dar um argumento adicional ao <function>invokeHelp()</function> que indica a 'âncora' para a qual o navegador irá saltar. </para>
</sect1>
</chapter>
<chapter id="components">
<title>Componentes e serviços</title>
<sect1 id="components-services">
<title>Serviços do KDE</title>
<simplesect id="services-whatarekdeservices">
<title>O que são os serviços do KDE?</title>
<para>A noção de um <emphasis>serviço</emphasis> é um conceito central da arquitectura modular do KDE. Não existe nenhuma implementação técnica restrita associada a este termo - os serviço podem ser 'plugins' sob a forma de bibliotecas dinâmicas ou podem ser programas controlados através de <ulink url="dcop.html">DCOP</ulink>. Quando alegar ter um determinado <emphasis>tipo de serviço</emphasis>, um serviço promete implementar certas APIs ou funcionalidades. Em termos de C++, pode-se pensar num tipo de serviço como uma classe abstracta e num serviço como uma implementação dessa interface. </para>
<para>A vantagem desta separação é clara: Uma aplicação que use um tipo de serviço não tem de conhecer as possíveis implementações od mesmo. Só usa as APIs associadas ao tipo de serviço. Desta forma, o serviço usado pode ser alterado sem afectar a aplicação. Da mesma forma, o utilizador pode configurar os serviços que ele prefere para certas funcionalidades. </para>
<para>Alguns exemplos: </para>
<itemizedlist>
<listitem><para>O motor de desenho de HTML no <application>Konqueror</application> é uma componente embebida que implementa os tipos de serviços <literal>KParts/ReadOnlyPart</literal> e <literal>Browser/View</literal>. </para></listitem>
<listitem><para>No HEAD do <application>KDevelop</application>, a maioria da funcionalidade está incorporada em 'plugins' com o tipo de serviço <literal>KDevelop/Part</literal>. No arranque, todos os serviços deste tipo são carregados, de modo a que você possa extender o IDE de uma forma muito flexível. </para></listitem>
<listitem><para>Na vista em ícones, o <application>Konqueror</application> mostra - se estiver activo - as miniaturas das imagens, páginas HTML, PDF e ficheiros de texto. Esta capacidade pode ser extendida. Se você quiser que ela mostre imagens de antevisão dos seus próprios ficheiros de dados com algum tipo MIME, você poderá implementar um serviço do tipo <classname>ThumbCreator</classname>. </para></listitem>
</itemizedlist>
<para>Obviamente, um serviço não é só caracterizado pelos tipos de serviços que implementa, mas também em algumas <emphasis>propriedades</emphasis>. Por exemplo, um ThumbCreator não só alega que implementa a classe de C++ com o tipo <classname>ThumbCreator</classname>, mas também tem uma lista de tipos MIME pelos quais é responsável. De forma semelhante, as componentes do KDevelop têm a a linguagem de programação que suportam como uma propriedades. Quando uma aplicação pede um tipo de serviço, pode também listar as restrições nas propriedades do serviço. No exemplo acima, quando o KDevelop carrega os 'plugins' de um projecto Java, ele só pede os 'plugins' que tenham o Java como propriedade da linguagem de programação. Para esse fim, o KDE contém um <emphasis>trader</emphasis> (mediador) semelhante ao do CORBA com uma linguagem de pesquisa complexa. </para>
</simplesect>
<simplesect id="services-definingservicetypes">
<title>Definir tipos de serviço</title>
<para>Os novos tipos de serviços são adicionados ao instalar uma descrição dos mesmos em <filename>TDEDIR/share/servicetypes</filename>. Na plataforma do 'automake', isto pode ser feito com este excerto do <filename>Makefile.am</filename>: </para>
<programlisting>kde_servicetypesdir_DATA = tdeveloppart.desktop
EXTRA_DIST = $(kde_servicetypesdir_DATA)
</programlisting>
<para>A definição <filename>tdeveloppart.desktop</filename> de uma componente do <application>KDevelop</application> assemelha-se ao seguinte: </para>
<programlisting>[Desktop Entry]
Type=ServiceType
X-TDE-ServiceType=KDevelop/Part
Name=KDevelop Part
[PropertyDef::X-KDevelop-Scope]
Type=TQString
[PropertyDef::X-KDevelop-ProgrammingLanguages]
Type=QStringList
[PropertyDef::X-KDevelop-Args]
Type=TQString
</programlisting>
<para>Para além dos itens normais, este exemplo demonstra como é que você declara que um serviço tem determinadas propriedades. Cada definição de propriedades corresponde a um grupo <literal>[PropertyDef::name]</literal> no ficheiro de configuração. Neste grupo, o item <literal>Type</literal> define o tipo da propriedades. Os tipos possíveis são todos os que conseguem ser registados num <ulink url="kdeapi:qt/QVariant">QVariant</ulink>. </para>
</simplesect>
<simplesect id="services-defininglibraryservices">
<title>Definir os serviços das bibliotecas dinâmicas</title>
<para>As definições dos serviços são gravadas na directoria <filename>TDEDIR/share/services</filename>: </para>
<programlisting>kde_servicesdir_DATA = kdevdoxygen.desktop
EXTRA_DIST = $(kde_servicesdir_DATA)
</programlisting>
<para>O conteúdo do seguinte ficheiro de exemplo <filename>kdevdoxygen.desktop</filename> define o 'plugin' do <literal>KDevDoxygen</literal> com o tipo de serviço <literal>KDevelop/Part</literal>: </para>
<programlisting>[Desktop Entry]
Type=Service
Comment=Doxygen
Name=KDevDoxygen
ServiceTypes=KDevelop/Part
X-TDE-Library=libkdevdoxygen
X-KDevelop-ProgrammingLanguages=C,C++,Java
X-KDevelop-Scope=Project
</programlisting>
<para>Para além das declarações normais, um item importante é o <literal>X-TDE-Library</literal>. Este contém o nome da biblioteca do 'libtool' (sem a extensão <literal>.la</literal>). Também corrige (com o prefixo <literal>init_</literal> anexado) o nome do símbolo exportado na biblioteca que devolve uma 'factory' (fábrica) de objectos. Para o exemplo acima, a biblioteca deve conter a seguinte função: </para>
<programlisting>extern "C" {
void *init_libkdevdoxygen()
{
return new DoxygenFactory;
}
};
</programlisting>
<para>O tipo da classe da 'factory' <classname>DoxygenFactory</classname> depende do tipo de serviço específico que este serviço implementa. No nosso exemplo de um 'plugin' do KDevelop, a 'factory' deverá ser uma <classname>KDevFactory</classname> (que herda de <classname>KLibFactory</classname>). Os exemplos mais comuns são a <ulink url="kdeapi:tdeparts/KParts::Factory">KParts::Factory</ulink> que é suposto produzir objectos <ulink url="kdeapi:tdeparts/KParts::ReadOnlyPart">KParts::ReadOnlyPart</ulink> ou, na maioria dos casos, a <ulink url="kdeapi:tdecore/KLibFactory">KLibFactory</ulink> genérica. </para>
</simplesect>
<simplesect id="services-usinglibraryservices">
<title>Usar os serviços das bibliotecas dinâmicas</title>
<para>Para usar um serviço de uma biblioteca dinâmica numa aplicação, você precisa de obter um objecto <ulink url="kdeapi:tdeio/KService.html">KService</ulink> que a represente. Isto é discutido na <ulink url="mime.html">secção sobre os tipos MIME</ulink> (e numa secção sobre o mediador, a ser escrita :-) </para>
<para>Com o objecto <classname>KService</classname> acessível, você poderá simplesmente carregar a biblioteca e obter uma referência para o objecto da sua 'factory': </para>
<programlisting>KService *servico = ...
TQString nomeBiblioteca = QFile::encodeName(servico->library());
KLibFactory *fabrica = KLibLoader::self()->factory(nomeBiblioteca);
if (!fabrica) {
TQString nome = servico->name();
TQString mensagemErro = KLibLoader::self()->lastErrorMessage();
KMessageBox::error(0, i18n("Ocorreu um erro ao carregar o serviço %1.\n"
"O diagnóstico da libtool é:\n%2")
.arg(nome).arg(mensagemErro);
}
</programlisting>
<para>A partir deste ponto, o procedimento posterior depende de novo do tipo de serviço. Para os 'plugins' genéricos, você cria objectos com o método <ulink url="kdeapi:tdecore/KLibFactory.html#ref3">KLibFactory::create()</ulink>. Para as KParts, você precisa de converter o ponteiro da 'factory' para a classe mais específica KParts::Factory e usar o seu método create(): </para>
<programlisting>if (fabrica->inherits("KParts::Factory")) {
KParts::Factory *fabricaComponentes = static_cast<KParts::Factory*>(fabrica);
TQObject *objecto = fabricaComponentes->createPart(janelaMae, nomeJanela,
mae, nome, "KParts::ReadOnlyPart");
...
} else {
cout << "O serviço na implementa a fábrica correcta" << endl;
}
</programlisting>
</simplesect>
<simplesect id="services-definingdcopservices">
<title>Definir serviços de DCOP</title>
<para>Um serviço de DCOP é normalmente implementado como um programa que é iniciado sempre que é necessário. Ele entra então em ciclo e fica à espera de ligações do DCOP. O programa poderá ser interactivo, mas também poderá correr completamente, ou durante parte do seu tempo de vida, como um servidor em segundo plano, sem que o utilizador repare nele. Um exemplo destes servidores é o <literal>tdeio_uiserver</literal>, que implementa a interacção com o utilizador, como a janela de progresso para a biblioteca TDEIO. A vantagem de um servidor centralizado deste no contexto em questão é que p.ex., pode-se mostrar o progresso da transferência para vários ficheiros diferentes numa só uma janela, mesmo que estas transferências tenham sido iniciadas a partir de aplicações diferentes. </para>
<para>Um serviço de DCOP é definido de forma diferente de um serviço de uma biblioteca dinâmica. Obviamente, não diz respeito a uma biblioteca, mas sim a um executável. Para além disso, os serviços de DCOP não indicam uma linha ServiceType, porque normalmente eles são iniciados pelo nomes deles. Como propriedades adicionais, contêm duas linhas: </para>
<para>O <literal>X-DCOP-ServiceType</literal> define a forma como o serviço é iniciado. O valor <literal>Unique</literal> diz que o serviço não poderá ser iniciado mais do que uma vez. Isto significa que, se você tentar iniciar este serviço (p.ex., através do <ulink url="kdeapi:tdecore/TDEApplication.html#startServiceByName"> TDEApplication::startServiceByName()</ulink>, o KDE irá descobrir se já está registado no DCOP e usa o serviço em execução. Se ainda não estiver registado, o KDE irá iniciá-lo e esperar até que esteja registado. Desta forma, você poderá enviar imediatamente chamadas de DCOP para o serviço. Nesse caso, o serviço deverá ser implementado como uma <ulink url="kdeapi:tdecore/KUniqueApplication.html">KUniqueApplication</ulink>. </para>
<para>O valor <literal>Multi</literal> para o <literal>X-DCOP-ServiceType</literal> diz que poderão coexistir várias instâncias do serviço, por isso todas as tentativas de iniciar o serviço irão criar outro processo. Como última possibilidade, o valor <literal>None</literal> poderá ser usado. Neste caso, o arranque do serviço não irá esperar até ter sido registado com o DCOP. </para>
<para>O <literal>X-TDE-StartupNotify</literal> deverá normalmente ser igual a 'false' (falso). Caso contrário, quando o programa for iniciado, a barra de tarefas irá mostrar uma notificação de arranque ou, dependo da configuração do utilizador, o cursor irá mudar. </para>
<para>Aqui está a definição do <literal>tdeio_uiserver</literal>: </para>
<programlisting>[Desktop Entry]
Type=Service
Name=tdeio_uiserver
Exec=tdeio_uiserver
X-DCOP-ServiceType=Unique
X-TDE-StartupNotify=false
</programlisting>
</simplesect>
<simplesect id="services-usingdcopservices">
<title>Usar os serviços de DCOP</title>
<para>Um serviço de DCOP é iniciado com um de vários métodos na classe TDEApplication: </para>
<programlisting>DCOPClient *cliente = kapp->dcopClient();
cliente->attach();
if (!cliente->isApplicationRegistered("tdeio_uiserver")) {
TQString erro;
if (TDEApplication::startServiceByName("tdeio_uiserver", QStringList(), &erro))
cout << "O início do kioserver falhou com a mensagem " << erro << endl;
}
...
QByteArray dados, dadosResposta;
QCString tipoResposta;
QDataStream arg(dados, IO_WriteOnly);
arg << true;
if (!client->call("tdeio_uiserver", "UIServer", "setListMode(bool)",
dados, tipoResposta, dadosResposta))
cout << "A chamada do tdeio_uiserver falhou" << endl;
...
</programlisting>
<para>Repare que o exemplo de uma chamada de DCOP indicado aqui utiliza a codificação explícita dos argumentos. Nornalmente, você iria usar um 'stub' (uma classe de adaptação) gerado pelo 'dcopidl2cpp', por ser muito mais simples e menos sujeito a erros. </para>
<para>No exemplo aqui dado, o serviço foi iniciado "por nome", i.e., o primeiro argumento do <function>TDEApplication::startServiceByName()</function> é o nome que aparece na linha <literal>Name</literal> do ficheiro 'desktop'. Uma alternativa é usar o <function>TDEApplication::startServiceByDesktopName()</function>, que recebe o nome do ficheiro 'desktop' como argumento, i.e., neste caso, seria igual a <literal>"tdeio_uiserver.desktop"</literal>. </para>
<para>Todas estas chamadas recebem uma lista de URLs como segundo argumento, o qual é dado ao serviço na linha de comandos. O terceiro argumento é um ponteiro para uma <classname>TQString</classname>. Se o início do serviço falhar, este argumento fica igual à mensagem de erro traduzida. </para>
</simplesect>
</sect1>
<sect1 id="components-mime">
<title>Tipos MIME</title>
<simplesect id="mime-whataremimetypes">
<title>O que são tipos MIME?</title>
<para>Os tipos MIME são usados para descrever o tipo de conteúdo dos ficheiros ou dos blocos de dados. Originalmente, foram introduzidos para permitir o envio de imagens, ficheiros de som, etc., por e-mail (o MIME significa "Multipurpose Internet Mail Extensions" - Extensões Multi-Uso de Correio pela Internet). Depois, este sistema foi também usado pelos navegadores Web para saber como apresentar os dados enviados por um servidor Web para o utilizador. Por exemplo, uma página de HTML tem um tipo MIME "text/html", um ficheiro PostScript tem o tipo "application/postscript". No KDE, este conceito é usado em vários sítios: </para>
<itemizedlist>
<listitem><para>Na vista em ícones do <application>Konqueror</application>, os ficheiros são representados por ícones. Cada tipo MIME tem um dado ícone associado, que é aqui apresentado. </para></listitem>
<listitem><para>Quando você carrega no ícone de um ficheiro ou no seu nome no <application>Konqueror</application>, o ficheiro tanto pode ser aberto num visualizador incorporado como numa aplicação associada ao tipo de ficheiro. </para></listitem>
<listitem><para>Quando você arrasta e larga alguns dados de uma aplicação noutra (ou dentro da mesma aplicação), o destino dos dados pode optar por aceitar apenas alguns tipos de dados. Para além disso, ele irá lidar com os dados de imagens de forma diferente dos dados textuais. </para></listitem>
<listitem><para>Os dados na área de transferência têm um tipo MIME. Tradicionalmente, os programas do X só lidam com imagens ou texto, mas com o Qt, não existem restrições ao tipo de dados. </para></listitem>
</itemizedlist>
<para>Nos exemplos acima, é óbvio que o tratamento do MIME é uma questão complexa. Primeiro, é necessário estabelecer um mapeamento dos nomes dos ficheiros para os tipos MIME. O KDE vai mais além, permitindo até que o conteúdo dos ficheiros seja mapeado em tipos MIME, para os casos em que o nome do ficheiro não está disponível. Segundo, é necessário mapear os tipos MIME nas aplicações ou nas bibliotecas que podem ver ou editar os ficheiros de um determinado tipo ou ainda criar uma imagem em miniatura deles. </para>
<para>Existe uma variedade de APIs para descobrir o tipo MIME dos dados ou ficheiros. De um modo geral, existe um certo compromisso de velocidade/fiabilidade que terá de fazer. Você poderá descobrir o tipo de um ficheiro, examinando apenas o nome do seu ficheiro (i.e., na maioria dos casos, pela sua extensão). Por exemplo, um ficheiro <filename>xpto.jpg</filename> é normalmente um "image/jpeg". Nos casos em que a extensão não existe, isto não é seguro, e você terá de ver o conteúdo do ficheiro. Isto é obviamente mais lento, em particular para os ficheiros que terão de ser obtidos via HTTP em primeiro lugar. O método baseado no conteúdo baseia-se no ficheiro <filename>TDEDIR/share/mimelnk/magic</filename> e, como tal, poderá ser difícil de extender. Mas, de um modo geral, a informação do tipo MIME poderá ser disponibilizada de forma simples ao sistema se instalar um ficheiro <literal>.desktop</literal>, e está disponível de forma eficiente e conveniente através das bibliotecas do KDE. </para>
</simplesect>
<simplesect id="mime-definingmimetypes">
<title>Definir os tipos MIME</title>
<para>Vamos então definir um tipo <literal>"application/x-xpto"</literal> para o nosso programa <application>programaXpto</application>. Para tal, você terá de criar um ficheiro <filename>xpto.desktop</filename> e instalá-lo em <filename>TDEDIR/share/mimelnk/application</filename>. (Esta é a localização normal, mas poderá variar entre distribuições). Isto pode ser feito se adicionar o seguinte ao <filename>Makefile.am</filename>: </para>
<programlisting>mimedir = $(kde_mimedir)/application
mime_DATA = xpto.desktop
EXTRA_DIST = $(mime_DATA)
</programlisting>
<para>O ficheiro <filename>xpto.desktop</filename> deverá ser parecido com o seguinte: </para>
<programlisting>[Desktop Entry]
Type=MimeType
MimeType=application/x-xpto
Icon=icone_xpto
Patterns=*.xpto;
DefaultApp=programaXpto
Comment=XPTO Data File
Comment[pt]=Dados em XPTO
</programlisting>
<para>O item <literal>"Comment"</literal> é suposto ser traduzido. Dado que o ficheiro <filename>.desktop</filename> refere um ícone, você deverá também instalar um ícone <filename>icone_xpto.png</filename>, que representa o ficheiro p.ex. no <application>Konqueror</application>. </para>
<para>Nas bibliotecas do KDE, a definição de um tipo destes é mapeada numa instância da classe <ulink url="kdeapi:tdeio/KMimeType.html">KMimeType</ulink>. Use esta como é mostrado no exemplo a seguir: </para>
<programlisting>KMimeType::Ptr tipo = KMimeType::mimeType("application/x-xpto");
cout << "Tipo: " << tipo->name() < endl;
cout << "Ícone: " << tipo->icon() < endl;
cout << "Comentário: " << tipo->icon() < endl;
QStringList padroes = tipo->patterns();
QStringList::ConstIterator it;
for (it = padroes.begin(); it != padroes.end(); ++it)
cout << "Padrão: " << (*it) << endl;
</programlisting>
</simplesect>
<simplesect id="mime-determiningmimetypes">
<title>Determinar o tipo MIME dos dados</title>
<para>O método mais rápido para determinar o tipo de um ficheiro é o <function>KMimeType::findByURL()</function>. Isto procura pelo texto no URL e, na maioria dos casos, determina o tipo a partir da extensão. Para certos protocolos (p.ex., 'http', 'man', 'info'), este mecanismo não é usado. Por exemplos, os 'scripts' CGI nos servidores Web escritos em Perl normalmente têm a extensão <literal>.pl</literal>, o que iria corresponder a um tipo <literal>"text/x-perl"</literal>. Todavia, o ficheiro devolvido pelo servidor é o resultado deste 'script', que é normalmente HTML. Para esse caso, o <function>KMimeType::findByURL()</function> devolve o tipo MIME <literal>"application/octet-stream"</literal> (disponível através do <function>KMimeType::defaultMimeType()</function>), que indica uma falha da descoberta do tipo. </para>
<programlisting>KMimeType::Ptr tipo = KMimeType::findByURL("/home/ze/xpto.jpg");
if (tipo->name() == KMimeType::defaultMimeType())
cout << "Não foi possível descobrir o tipo" << endl;
else
cout << "Tipo: " << tipo->name() << endl;
</programlisting>
<para>(este método tem mais alguns argumentos, mas estes não estão documentados, por isso esqueça-os). </para>
<para>Você poderá querer determinar o tipo MIME a partir do conteúdo do ficheiro em vez de ser pelo seu nome. Isto é mais fiável, mas também é mais lento, dado que implica ler uma parte do ficheiro. Isto é feito com a classe <ulink url="kdeapi:tdeio/KMimeMagic.html">KMimeMagic</ulink>, que tem tratamentos de erros diferentes: </para>
<programlisting>KMimeMagicResult *resultado = KMimeMagic::self()->findFileType("/home/ze/xpto.jpg");
if (!resultado || !resultado->isValid())
cout << "Não foi possível descobrir o tipo" << endl;
else
cout << "Tipo: " << resultado->mimeType() << endl;
</programlisting>
<para>Como variante desta função, você também poderá determinar o tipo de um dado bloco de memória. Isto é p.ex. usado no <application>Kate</application> para descobrir o modo de realce: </para>
<programlisting>QByteArray dados;
...
KMimeMagicResult *resultado = KMimeMagic::self()->findBufferType(dados);
if (!resultado || !resultado->isValid())
cout << "Não foi possível descobrir o tipo" << endl;
else
cout << "Tipo: " << resultado->mimeType() << endl;
</programlisting>
<para>Obviamente, até mesmo o KMimeMagic só é capaz de determinar o tipo do ficheiro para o conteúdo de um ficheiro local. Para os ficheiros remotos, existe uma outra possibilidade: </para>
<programlisting>KURL url("http://developer.kde.org/favicon.ico");
TQString tipo = TDEIO::NetAccess::mimetype(url);
if (tipo == KMimeType::defaultMimeType())
cout << "Não foi possível descobrir o tipo" << endl;
else
cout << "Tipo: " << tipo << endl;
</programlisting>
<para>Isto inicia uma tarefa do TDEIO para obter uma parte do ficheiro e analisá-la. Lembre-se que esta função é talvez bastante lenta e bloqueia o programa. Normalmente, você só irá querer usar isto se o <function>KMimeType::findByURL()</function> devolveu <literal>"application/octet-stream"</literal>. </para>
<para>Por outro lado, se você não quiser bloquear a sua aplicação, você poderá iniciar explicitamente a tarefa do TDEIO e ligar-se a um dos seus 'signals': </para>
<programlisting>void ClasseXpto::descobrirTipo()
{
KURL url("http://developer.kde.org/favicon.ico");
TDEIO::MimetypeJob *tarefa = TDEIO::mimetype(url);
connect( tarefa, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(mimeResult(TDEIO::Job*)) );
}
void ClasseXpto::resultadoMime(TDEIO::Job *tarefa)
{
if (tarefa->error())
tarefa->showErrorDialog();
else
cout << "Tipo MIME: " << ((TDEIO::MimetypeJob *)tarefa)->mimetype() << endl;
}
</programlisting>
</simplesect>
<simplesect id="mime-mappingmimetypes">
<title>Mapear um tipo MIME a uma aplicação ou serviço</title>
<para>Quando uma aplicação é instalada, ela coloca um ficheiro <literal>.desktop</literal> que contém uma lista dos tipos MIME que esta aplicação pode carregar. De forma semelhante, os componentes como as KParts disponibilizam esta informação através dos ficheiros <literal>.desktop</literal> dos serviços. Por isso, de um modo geral, existem vários programas e componentes que podem processar um dado tipo MIME. Você poderá obter uma dessas listas a partir da classe <classname>KServiceTypeProfile</classname>: </para>
<programlisting>KService::OfferList ofertas = KServiceTypeProfile::offers("text/html", "Application");
KService::OfferList::ConstIterator it;
for (it = ofertas.begin(); it != ofertas.end(); ++it) {
KService::Ptr servico = (*it);
cout << "Nome: " << servico->name() << endl;
}
</programlisting>
<para>O valor devolvido por esta função é uma lista de ofertas de serviços. Um objecto <classname>KServiceOffer</classname> contém um KService::Ptr em conjunto com um número de preferência. A lista devolvida pelo <function>KServiceTypeProfile::offers()</function> vem ordenada de acordo com a preferência do utilizador. O utilizador poderá alterar isto com o comando <command>"keditfiletype text/html"</command> ou escolhendo <guimenuitem>Editar o Tipo de Ficheiro</guimenuitem> no menu de contexto do <application>Konqueror</application> num ficheiro HTML. </para>
<para>No exemplo acima, foi pedida uma lista de ofertas de aplicações que suportem o <literal>text/html</literal>. Isto irá - entre outros - conter os editores de HTML como o <application>Quanta Plus</application>. Você poderá também substituir o segundo argumento <literal>"Application"</literal> por <literal>"KParts::ReadOnlyPart"</literal>. Nesse caso, você irá obter uma lista dos componentes incorporados para apresentar conteúdos em HTML, como por exemplo o TDEHTML. </para>
<para>Na maioria dos casos, você não está interessado na lista de todas as ofertas de serviços para uma dada combinação de tipo MIME e tipo de serviço. Existe uma função de conveniência que lhe dá apenas a oferta de serviço com a maior preferência: </para>
<programlisting>KService::Ptr oferta = KServiceTypeProfile::preferredService("text/html", "Application");
if (oferta)
cout << "Nome: " << oferta->name() << endl;
else
cout << "Não foi encontrado nenhum serviço apropriado" << endl;
</programlisting>
<para>Para as pesquisas ainda mais complexas, existe um <ulink url="kdeapi:tdeio/TDETrader.html">mediador</ulink> completo e semelhante ao do CORBA. </para>
<para>Para poder executar um serviço de aplicação com alguns URLs, use o <ulink url="kdeapi:tdeio/KRun.html">KRun</ulink>: </para>
<programlisting>KURL::List listaUrls;
listaUrls << "http://www.ietf.org/rfc/rfc1341.txt?number=1341";
listaUrls << "http://www.ietf.org/rfc/rfc2046.txt?number=2046";
KRun::run(ofertas.service(), listaUrls);
</programlisting>
</simplesect>
<simplesect id="mime-misc">
<title>Diversos</title>
<para>Nesta secção, nós queremos listar algumas APIs que estão de certo modo relacionadas com a discussão anterior. </para>
<para>Obter um ícone para um dado URL. Isto procura o tipo do URL e devolve o ícone associado. </para>
<programlisting>KURL url("ftp://ftp.kde.org/pub/incoming/wibble.c");
TQString icone = KMimeType::iconForURL(url);
</programlisting>
<para>Executar um URL. Isto procura pelo tipo do URL e inicia o programa preferido do utilizador associado a este tipo. </para>
<programlisting>KURL url("http://dot.kde.org");
new KRun(url);
</programlisting>
</simplesect>
</sect1>
<sect1 id="nettransparency">
<title>Transparência na rede</title>
<simplesect id="nettransparency-intro">
<title>Introdução</title>
<para>Na era na World Wide Web, é de uma importância essencial que as aplicações possam aceder aos recursos na Internet: elas deverão ser capazes de obter os ficheiros a partir de um servidor Web, gravar os ficheiros num servidor FTP ou ler as mensagens de e-mail de um servidor Web. Normalmente, a capacidade de aceder aos ficheiros, independentemente da sua localização é chamada de <emphasis>transparência na rede</emphasis>. </para>
<para>No passado, foram implementadas aproximações diferentes para estes objectivos. O sistema de ficheiros antigo NFS é uma tentativa de implementar a transparência de rede ao nível da API do POSIX. Embora esta aproximação funcione bastante bem nas redes locais e próximas, não é escalável para os recursos cujo acesso não seja fiável ou seja lento. Aqui, a <emphasis>assincronização</emphasis> é importante. Enquanto você está à espera do seu navegador Web para transferir uma página, a interface do utilizador não deverá bloquear. Da mesma forma, o início do desenho da página não deverá começar somente quando a página estiver disponível por completo mas sim actualizar-se regulamente à medida que os dados vão chegando. </para>
<para>Nas bibliotecas do KDE, a transparência da rede está implementada na API do TDEIO. O conceito central desta arquitectura é a <emphasis>tarefa</emphasis> de E/S. Uma tarefa pode copiar ou remover ficheiros, entre outras coisas. Logo que uma tarefa seja inicia, ela fica em segundo plano e não bloqueia a aplicação. Todas as comunicações da tarefa para a aplicação - como a entrega dos dados ou a informação de progresso - é feita de forma integrada com o ciclo de eventos do Qt. </para>
<para>A operação em segundo-plano é conseguida com o arranque de <emphasis>ioslaves</emphasis> para efectuar certas tarefas. Os 'ioslaves' são iniciados como processos separados e comunicam através de 'sockets' do domínio UNIX. Desta forma, não é necessário nenhum suporte de multi-tarefa e os 'slaves' instáveis não poderão estoirar as aplicações que os usam. </para>
<para>As localizações dos ficheiros são indicadas pelos URLs que são usados em grande escala. Mas, no KDE, os URLs não só se expandem à gama de ficheiros endereçáveis para além do sistema de ficheiros local. Também funciona na direcção oposta - p.ex. você poderá navegar nos pacotes TAR. Isto é conseguido com os URLs aninhados. Por exemplo, um ficheiro num pacote TAR num servidor HTTP poderá ter o URL </para>
<programlisting>http://www.xpto.pt/~ze/artigo.tgz#tar:/documento.tex
</programlisting>
</simplesect>
<simplesect id="nettransparency-usingkio">
<title>Usar o TDEIO</title>
<para>Na maioria dos casos, as tarefas são criadas ao invocar as funções no espaço de nomes do TDEIO. Estas funções recebem um ou dois URLs como argumentos e possivelmente outros parâmetros necessários. Quando a tarefa terminar, ela emite o 'signal' <literal>result(TDEIO::Job*)</literal>. Depois de este 'signal' ter sido emitido, a tarefa elimina-se a si própria. Deste modo, um caso de uso típico poderia ser semelhante ao seguinte: </para>
<programlisting>void ClasseXpto::criarDirectoria()
{
SimpleJob *tarefa = TDEIO::mkdir(KURL("file:/home/ze/dir_tdeio"));
connect( tarefa, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(resultadoMkdir(TDEIO::Job*)) );
}
void ClasseXpto::resultadoMkdir(TDEIO::Job *tarefa)
{
if (tarefa->error())
tarefa->showErrorDialog();
else
cout << "o 'mkdir' correu bem" << endl;
}
</programlisting>
<para>Dependendo do tipo de tarefa, você poder-se-á também ligar a outros 'signals'. </para>
<para>Aqui está uma ideia geral das funções possíveis: </para>
<variablelist>
<varlistentry><term>TDEIO::mkdir(const KURL &url, int permissao)</term>
<listitem><para>Criar uma directoria, com algumas permissões opcionais. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::rmdir(const KURL &url)</term>
<listitem><para>Remove uma directoria. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::chmod(const KURL &url, int permissoes)</term>
<listitem><para>Muda as permissões de um ficheiro. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::rename(const KURL &origem, const KURL &destino, bool sobrepor)</term>
<listitem><para>Muda o nome de um ficheiro. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::symlink(const TQString &alvo, const KURL &destino, bool sobrepor, bool mostrarProgresso)</term>
<listitem><para>Cria uma ligação simbólica. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::stat(const KURL &url, bool mostrarProgresso)</term>
<listitem><para>Descobre certas informações sobre o ficheiro, como o tamanho, a data de modificação e as permissões. A informação pode ser obtida a partir do TDEIO::StatJob::statResult() depois de a tarefa terminar. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::get(const KURL &url, bool reler, bool mostrarProgresso)</term>
<listitem><para>Transfere os dados de um dado URL. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::put(const KURL &url, int permissoes, bool sobrepor, bool continuar, bool mostrarProgresso)</term>
<listitem><para>Transfere os dados para um dado URL. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::http_post(const KURL &url, const QByteArray &dados, bool mostrarProgresso)</term>
<listitem><para>Envia os dados. É específico do HTTP. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::mimetype(const KURL &url, bool mostrarProgresso)</term>
<listitem><para>Tenta descobrir o tipo MIME do URL. O tipo poderá ser obtido a partir do TDEIO::MimetypeJob::mimetype() depois de a tarefa terminar. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::file_copy(const KURL &origem, const KURL &destino, int permissoes, bool sobrepor, bool continuar, bool mostrarProgresso)</term>
<listitem><para>Copia um único ficheiro. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::file_move(const KURL &origem, const KURL &destino, int permissoes, bool sobrepor, bool continuar, bool mostrarProgresso)</term>
<listitem><para>Muda o nome ou move um único ficheiro. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::file_delete(const KURL &url, bool mostrarProgresso)</term>
<listitem><para>Apaga um único ficheiro. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::listDir(const KURL &url, bool mostrarProgresso)</term>
<listitem><para>Lista o conteúdo de uma dada directoria. De cada vez que alguns itens passam a ser conhecidos, o 'signal' TDEIO::ListJob::entries() é emitido. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::listRecursive(const KURL &url, bool mostrarProgresso)</term>
<listitem><para>Semelhante à função listDir(), só que esta função é recursiva. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::copy(const KURL &origem, const KURL &destino, bool mostrarProgresso)</term>
<listitem><para>Copia um ficheiro ou directoria. As directorias são copiadas de forma recursiva. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::move(const KURL &origem, const KURL &destino, bool mostrarProgresso)</term>
<listitem><para>Move ou muda o nome de um ficheiro ou directoria. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::del(const KURL &src, bool shred, bool showProgressInfo)</term>
<listitem><para>Apaga um ficheiro ou directoria. </para></listitem>
</varlistentry>
</variablelist>
</simplesect>
<simplesect id="nettransparency-direntries">
<title>Itens da directoria</title>
<para>Tanto as tarefas TDEIO::stat() como a TDEIO::listDir() devolvem os seus resultados como um tipo UDSEntry e UDSEntryList respectivamente. A última está definida como sendo um QValueList<UDSEntry>. O acrónimo UDS significa "Universal directory service" (serviço de directório universal). O princípio está em que o item da directoria só contém a informação que um 'ioslave' poderá fornecer, nada mais. Por exemplo, o 'slave' de HTTP não fornece nenhuma informação sobre as permissões de acesso ou os donos dos ficheiros. Em vez disso, uma UDSEntry é uma lista de UDSAtoms. Cada átomo contém um item informativo específico. Ele consiste num tipo armazenado no 'm_uds' e num valor inteiro no 'm_long' ou um valor de texto no 'm_str', dependendo do tipo. </para>
<para>Os seguintes tipos estão actualmente definidos: </para>
<itemizedlist>
<listitem><para>UDS_SIZE (inteiro) - O tamanho do ficheiro. </para></listitem>
<listitem><para>UDS_USER (texto) - O utilizador que possui o ficheiro. </para></listitem>
<listitem><para>UDS_GROUP (texto) - O grupo que possui o ficheiro. </para></listitem>
<listitem><para>UDS_NAME (texto) - O nome do ficheiro. </para></listitem>
<listitem><para>UDS_ACCESS (inteiro) - As permissões sobre o ficheiro, como é guardado p.ex. pela função da 'libc' stat() no campo 'st_mode'. </para></listitem>
<listitem><para>UDS_FILE_TYPE (inteiro) - O tipo do ficheiro, tal como é, p.ex., registado pelo stat() no campo 'st_mode'. Como tal, você poderá usar as macros normais da 'libc' como a S_ISDIR para testar este valor .Repare que os dados fornecidos pelos 'ioslaves' correspondem ao stat(), não ao lstat(), i.e., no caso das ligações simbólicas, o tipo aqui mencionado é o tipo do ficheiro apontado pela ligação, não a ligação em si. </para></listitem>
<listitem><para>UDS_LINK_DEST (texto) - No caso de uma ligação simbólica, o nome do ficheiro para onde esta ligação aponta. </para></listitem>
<listitem><para>UDS_MODIFICATION_TIME (inteiro) - A hora (como no tipo 'time_t') em que o ficheiro foi modificado da última vez, como é p.ex. registado pelo stat() no campo 'st_mtime'. </para></listitem>
<listitem><para>UDS_ACCESS_TIME (inteiro) - A hora (como no tipo 'time_t') em que o ficheiro foi acedido da última vez, como é p.ex. registado pelo stat() no campo 'st_atime'. </para></listitem>
<listitem><para>UDS_CREATION_TIME (inteiro) - A hora (como no tipo 'time_t') em que o ficheiro foi criado, como é p.ex. registado pelo stat() no campo 'st_ctime'. </para></listitem>
<listitem><para>UDS_URL (texto) - Fornece um URL do ficheiro, se não for simplesmente a concatenação do URL da directoria e o nome do ficheiro. </para></listitem>
<listitem><para>UDS_MIME_TYPE (texto) - tipo MIME do ficheiro </para></listitem>
<listitem><para>UDS_GUESSED_MIME_TYPE (texto) - o tipo MIME do ficheiro, tal como é determinado pelo 'slave'. A diferença em relação ao tipo anterior é que o que é fornecido aqui não deverá ser considerado fiável (porque determiná-lo de forma fiável será demasiado dispendioso). Por exemplo, a classe KRun verifica explicitamente o tipo MIME se não tiver nenhuma informação fiável. </para></listitem>
</itemizedlist>
<para>Ainda que a forma de armazenar as informações sobre os ficheiros num <classname>UDSEntry</classname> seja flexível e prático do ponto de vista dos 'ioslaves', é uma confusão para ser usado pelo programador da aplicação. Por exemplo, para saber qual é o tipo MIME do ficheiro, você teria de iterar por todos os átomos e testar se o <literal>m_uds</literal> era o <literal>UDS_MIME_TYPE</literal>. Felizmente, existe uma API que é bastante mais simples de usar: a classe <classname>KFileItem</classname>. </para>
</simplesect>
<simplesect id="nettransparency-syncuse">
<title>Utilização síncrona</title>
<para>Normalmente, a API síncrona do TDEIO é demasiado complexa de usar e, como tal, a implementação de uma assincronização completa não é uma prioridade. Por exemplo, num programa que só consiga lidar com um ficheiro de cada vez, não há muito a fazer enquanto o programa está a transferir um ficheiro, de qualquer forma. Para esses casos simples, existe uma API muito mais simples sob a forma de funções estáticas no TDEIO::NetAccess. Por exemplo, para poder copiar um ficheiro, use </para>
<programlisting>KURL origem, destino;
source = ...;
target = ...
TDEIO::NetAccess::copy(origem, destino);
</programlisting>
<para>A função irá regressar depois de o processo de cópia ter terminado por completo. De qualquer forma, este método fornece uma janela de progresso e certifica-se que os processos da aplicação actualizam os eventos. </para>
<para>Uma combinação particularmente interessante de funções é a <function>download()</function> em conjunto com a <function>removeTempFile()</function>. A primeira obtém um ficheiro a partir de um dado URL e guarda-o num ficheiro temporário com um nome único. O nome é guardado no segundo argumento. <emphasis>Se</emphasis> o URL for local, o ficheiro não é transferido e, em vez disso, o segundo argumento passa a ser o nome do ficheiro local. A função <function>removeTempFile()</function> apaga o ficheiro indicado pelo seu argumento, se o ficheiro for o resultado de uma transferência anterior. Se não for o caso, não faz nada. Desta forma, uma forma muito simples de carregar os ficheiros, independentemente da sua localização é o pedaço de código a seguir: </para>
<programlisting>KURL url;
url = ...;
TQString ficheiroTemporario;
if (TDEIO::NetAccess::download(url, ficheiroTemporario) {
// carregar o ficheiro com o nome 'ficheiroTemporario'
TDEIO::NetAccess::removeTempFile(ficheiroTemporario);
}
</programlisting>
</simplesect>
<simplesect id="nettransparency-metadata">
<title>Meta-dados</title>
<para>Como pode ser visto em cima, a interface para as tarefas de E/S é bastante abstracta e não considera nenhuma troca de informação entre a aplicação e o 'IO slave', o qual é específico do protocolo. Isto nem sempre é apropriado. Por exemplo, você poderá querer dar certos parâmetros ao 'slave' de HTTP para controlar o comportamento da sua 'cache' ou para enviar um conjunto de 'cookies' com o pedido. Para esse fim, o conceito de meta-dados foi introduzido. Quando for criada uma tarefa, você poderá configurá-la se lhe adicionar meta-dados. Cada item de meta-dados consiste num par chave/valor. Por exemplo, para evitar que o 'slave' de HTTP carregue a página Web da sua 'cache', você pode usar: </para>
<programlisting>void ClasseXpto::relerPagina()
{
KURL url("http://www.kdevelop.org/index.html");
TDEIO::TransferJob *tarefa = TDEIO::get(url, true, false);
tarefa->addMetaData("cache", "reload");
...
}
</programlisting>
<para>A mesma técnica é usada na outra direcção, i.e., para a comunicação do 'slave' para a aplicação. O método <function>Job::queryMetaData()</function> pede o valor de uma certa chave indicada pelo 'slave'. Para o 'slave' de HTTP, um desses exemplos é a chave <literal>"modified"</literal> (modificado), que contém uma (representação em texto da) data em que a página Web foi modificada da última vez. Um exemplo de como você pode usar isto é o seguinte: </para>
<programlisting>void ClasseXpto::mostrarDataModificacao()
{
KURL url("http://developer.kde.org/documentation/kde2arch/index.html");
TDEIO::TransferJob *tarefa = TDEIO::get(url, true, false);
connect( tarefa, TQ_SIGNAL(result(TDEIO::Job*)),
this, TQ_SLOT(transferirResultado(TDEIO::Job*)) );
}
void ClasseXpto::transferirResultado(TDEIO::Job *tarefa)
{
TQString tipoMime;
if (tarefa->error())
tarefa->showErrorDialog();
else {
TDEIO::TransferJob *tarefaTransferencia = (TDEIO::TransferJob*) tarefa;
TQString modificado = tarefaTransferencia->queryMetaData("modified");
cout << "Última modificação: " << modificado << endl;
}
</programlisting>
</simplesect>
<simplesect id="nettransparency-scheduling">
<title>Escalonamento</title>
<para>Ao usar a API do TDEIO, você normalmente não tem de lidar com os detalhes de arranque dos 'IO slaves' e da comunicação com eles. O caso de uso normal é iniciar uma tarefa e, com alguns parâmetros, tratar os 'signals' que esta emite. </para>
<para>Nos bastidores, o cenário é bastante mais complicado. Quando você cria uma tarefa, esta é posta numa fila. Quando a aplicação regressa ao ciclo de eventos, o TDEIO reserva processos de 'slaves' para as tarefas na fila. Para as primeiras tarefas que sejam iniciadas, isto é trivial: um 'IO slave' para o protocolo corresponde é iniciado. Contudo, depois de a tarefa (como a transferência de um servidor de HTTP) ter terminado, não é imediatamente morta. Em vez disso, é colocada num grupo de 'slaves' inactivos e é morta ao fim de um dado período de inactividade (normalmente 3 minutos). Se surgir um novo pedido para o mesmo protocolo e máquina, o 'slave' é reutilizado. A vantagem óbvia é que, para uma série de tarefas para a mesma máquina, o custo da criação de novos processos e da passagem por um processo de autenticação é poupado. </para>
<para>Claro que a reutilização só é possível quando o 'slave' existente já tiver terminado a sua tarefa anterior. Sempre que chega um novo pedido enquanto um 'slave' existente está ainda a correr, é iniciado um novo processo para ser utilizado. Na utilização da API nos exemplos acima, não existe nenhuma limitação para criar novos processos de 'slaves': se você iniciar uma série consecutiva de transferências para 20 ficheiros, então o TDEIO irá iniciar 20 processos de 'slaves'. Este esquema de atribuição de 'slaves' a tarefas é chamado de <emphasis>directo</emphasis>. Não é sempre o esquema mais apropriado, dado que poderá necessitar de bastante memória e poderá colocar uma carga elevada tanto no cliente como no servidor. </para>
<para>Por isso, existe uma forma diferente. Você poderá <emphasis>escalonar</emphasis> as tarefas. Se o fizer, somente um número limitado (de momento 3) de processos de 'slaves' para um dado protocolo serão criados. Se você criar mais tarefas que isso, elas serão colocadas numa fila e são processadas quando um processo de um 'slave' ficar inactivo. Isto é feito da seguinte forma: </para>
<programlisting>KURL url("http://developer.kde.org/documentation/kde2arch/index.html");
TDEIO::TransferJob *tarefa = TDEIO::get(url, true, false);
TDEIO::Scheduler::scheduleJob(tarefa);
</programlisting>
<para>Uma terceira possibilidade é <emphasis>orientar à ligação</emphasis>. Por exemplo, no caso do 'slave' de IMAP, não faz nenhum sentido lançar vários processos para o mesmo servidor. Só uma ligação de IMAP de cada vez é que deverá ser permitida. Neste caso, a aplicação deverá lidar explicitamente com a noção de um 'slave'. Terá de libertar um 'slave' para uma determinada ligação e então atribuir todas as tarefas que deverão ir pela mesma ligação ao mesmo 'slave'. Isto poderá ser conseguido facilmente com a utilização do TDEIO::Scheduler: </para>
<programlisting>KURL urlBase("imap://bernd@albert.physik.hu-berlin.de");
TDEIO::Slave *slave = TDEIO::Scheduler::getConnectedSlave(urlBase);
TDEIO::TransferJob *tarefa1 = TDEIO::get(KURL(urlBase, "/INBOX;UID=79374"));
TDEIO::Scheduler::assignJobToSlave(slave, tarefa1);
TDEIO::TransferJob *tarefa2 = TDEIO::get(KURL(urlBase, "/INBOX;UID=86793"));
TDEIO::Scheduler::assignJobToSlave(slave, tarefa2);
...
TDEIO::Scheduler::disconnectSlave(slave);
</programlisting>
<para>Você só poderá desligar o 'slave' depois de todas as tarefas atribuídas a ela terem terminado de forma garantida. </para>
</simplesect>
<simplesect id="nettransparency-definingslaves">
<title>Definir um 'ioslave'</title>
<para>Na parte seguinte iremos discutir como é que você poderá adicionar um novo 'ioslave' ao sistema. Em analogia aos serviços, os 'ioslaves' novos são publicados no sistema, instalando para tal um pequeno ficheiro de configuração. O seguinte excerto do Makefile.am instala o protocolo FTP: </para>
<programlisting>protocoldir = $(kde_servicesdir)
protocol_DATA = ftp.protocol
EXTRA_DIST = $(mime_DATA)
</programlisting>
<para>O conteúdo do ficheiro 'ftp.protocol' é o seguinte: </para>
<programlisting>[Protocol]
exec=tdeio_ftp
protocol=ftp
input=none
output=filesystem
listing=Name,Type,Size,Date,Access,Owner,Group,Link,
reading=true
writing=true
makedir=true
deleting=true
Icon=ftp
</programlisting>
<para>O item <literal>"protocol"</literal> define qual o protocolo pelo qual este 'slave' é responsável. O <literal>"exec"</literal> é (ao contrário do que estaria à espera) o nome da biblioteca que implementa o 'slave'. Quando o 'slave' for suposto arrancar, o executável <command>"tdeinit"</command> é iniciado, o qual por sua vez arranca esta biblioteca no seu espaço de endereçamento. Por isso, na prática, você poderá pensar no 'slave' em execução como um processo separado, ainda que seja implementado como uma biblioteca. A vantagem deste mecanismo é que poupa bastante memória e reduz o tempo necessário pelo editor de ligações durante a execução. </para>
<para>As linhas "input" e "output" não são usadas de momento. </para>
<para>As linhas restantes do ficheiro <literal>.protocol</literal> definem quais as capacidades que o 'slave' tem. De um modo geral, as funcionalidades que um 'slave' tem de implementar são muito mais simples do que as funcionalidades que a API do TDEIO oferece à aplicação. A razão para tal é que as tarefas complexas são escalonadas para um conjunto de sub-tarefas. Por exemplo, para poder listar uma directoria recursivamente, terá de ser iniciada uma tarefa para a directoria de topo. Depois, para cada subdirectoria indicada, são criadas novas sub-tarefas. Um escalonador no TDEIO certifica-se que não estão demasiadas tarefas activas ao mesmo tempo. De forma semelhante, para poder copiar um ficheiro num protocolo que não suporte a cópia directa (como o protocolo <literal>ftp:</literal>), o TDEIO poderá ler o ficheiro de origem e então escrever os dados para o ficheiro de destino. Para isto funcionar, o <literal>.protocol</literal> precisa de publicar as acções que o seu 'slave' suporta. </para>
<para>Dado que os 'slaves' são carregados como bibliotecas dinâmicas, mas constituem em si programas autónomos, a sua plataforma de código parece ligeiramente diferente dos 'plugins' normais das bibliotecas dinâmicas. A função que é invocada para iniciar o 'slave' chama-se <function>kdemain()</function>. Esta função faz algumas inicializações e vai então para o ciclo de eventos, onde fica à espera de pedidos da aplicação que a usa. Isto parece-se com o seguinte: </para>
<programlisting>extern "C" { int kdemain(int argc, char **argv); }
int kdemain(int argc, char **argv)
{
TDELocale::setMainCatalogue("tdelibs");
TDEInstance instance("tdeio_ftp");
(void) TDEGlobal::locale();
if (argc != 4) {
fprintf(stderr, "Utilização: tdeio_ftp protocolo "
"socket1-dominio socket2-dominio\n");
exit(-1);
}
FtpSlave slave(argv[2], argv[3]);
slave.dispatchLoop();
return 0;
}
</programlisting>
</simplesect>
<simplesect id="nettransparency-implementingslaves">
<title>Implementar um 'ioslave'</title>
<para>Os 'slaves' são implementados como sub-classes da <classname>TDEIO::SlaveBase</classname> (a FtpSlave no exemplo acima). Como tal, as acções listadas no ficheiro <literal>.protocol</literal> correspondem a certas funções virtuais no <classname>TDEIO::SlaveBase</classname> que a implementação do 'slave' precisa de reimplementar. Aqui está uma lista das acções possíveis e das funções virtuais correspondentes: </para>
<variablelist>
<varlistentry><term>leitura - Lê os dados de um URL</term>
<listitem><para>void get(const KURL &url)</para></listitem></varlistentry>
<varlistentry><term>escrita - Escreve os dados num URL e cria o ficheiro se ainda não existir nenhum.</term>
<listitem><para>void put(const KURL &url, int permissoes, bool sobrepor, bool continuar)</para></listitem></varlistentry>
<varlistentry><term>mudança de nome - Muda o nome de um ficheiro.</term>
<listitem><para>void rename(const KURL &origem, const KURL &destino, bool sobrepor)</para></listitem></varlistentry>
<varlistentry><term>remoção - Remove um ficheiro ou directoria.</term>
<listitem><para>void del(const KURL &url, bool eUmFicheiro)</para></listitem></varlistentry>
<varlistentry><term>listagem - Mostra o conteúdo de uma directoria.</term>
<listitem><para>void listDir(const KURL &url)</para></listitem></varlistentry>
<varlistentry><term>makedir - Cria uma directoria.</term>
<listitem><para>void mkdir(const KURL &url, int permissoes)</para></listitem></varlistentry>
</variablelist>
<para>Adicionalmente, existem funções que podem ser implementadas de novo e que não estão listadas no ficheiro <literal>.protocol</literal>. Para essas operações, o TDEIO determina automaticamente se elas são suportadas ou não (i.e., se a implementação por omissão devolve um erro). </para>
<variablelist>
<varlistentry><term>Fornece dados sobre um ficheiro, de forma semelhante à função do C stat().</term>
<listitem><para>void stat(const KURL &url)</para></listitem></varlistentry>
<varlistentry><term>Muda as permissões de acesso de um ficheiro.</term>
<listitem><para>void chmod(const KURL &url, int permissoes)</para></listitem></varlistentry>
<varlistentry><term>Determina o tipo MIME de um ficheiro.</term>
<listitem><para>void mimetype(const KURL &url)</para></listitem></varlistentry>
<varlistentry><term>Copia um ficheiro.</term>
<listitem><para>copy(const KURL &url, const KURL &destino, int permissoes, bool sobrepor)</para></listitem></varlistentry>
<varlistentry><term>Cria uma ligação simbólica.</term>
<listitem><para>void symlink(const TQString &alvo, const KURL &destino, bool sobrepor)</para></listitem></varlistentry>
</variablelist>
<para>Todas estas implementações deverão terminar com uma de duas chamadas: Se a operação foi bem sucedida, deverão invocar o <literal>finished()</literal>. Se ocorreu um erro, o <literal>error()</literal> deverá ser invocado com um código de erro como primeiro argumento e um texto no segundo. Os códigos de erro possíveis estão listados no tipo enumerado <type>TDEIO::Error</type>. O segundo argumento é normalmente o URL em questão. É usado, p.ex., no <function>TDEIO::Job::showErrorDialog()</function> para parametrizar a mensagem de erro para o utilizador. </para>
<para>Para os 'slaves' que correspondem aos protocolos de rede, poderá ser interessante reimplementar o método <function>SlaveBase::setHost()</function>. Isto é chamado para indicar ao processo do 'slave' qual a máquina e o porto, assim como o utilizador e a senha a usar. De um modo geral, os meta-dados definidos pela aplicação poderão ser questionados pelo <function>SlaveBase::metaData()</function>. Você poderá verificar a existência de meta-dados de uma determinada chave com o <function>SlaveBase::hasMetaData()</function>. </para>
</simplesect>
<simplesect id="nettransparency-communication">
<title>Comunicar de volta à aplicação</title>
<para>As várias acções implementadas num 'slave' precisam de uma forma qualquer para comunicar de volta para a aplicação, usando o processo do 'slave': </para>
<itemizedlist>
<listitem><para>O <function>get()</function> envia blocos de dados. Isto é feito com o <function>data()</function>, que recebe um <classname>QByteArray</classname> como argumento. Claro que não precisa de enviar todos os dados de uma vez. Se enviar um ficheiro grande, invoque o <function>data()</function> com blocos de dados mais pequenos, de modo a que a aplicação os processe. Invoque o <function>finished()</function> quando a transferência terminar. </para></listitem>
<listitem><para>O <function>listDir()</function> devolve informações sobre os itens de uma directoria. Para esse fim, chame o <function>listEntries()</function> com um <classname>TDEIO::UDSEntryList</classname> como argumento. De forma análoga à do <function>data()</function>, você poderá invocá-lo várias vezes. Quando terminar, invoque o <function>listEntry()</function> com o segundo parâmetro igual a 'true' (verdadeiro). Você poderá também chamar o <function>totalSize()</function> para indicar o número total de itens da directoria, se forem conhecidos. </para></listitem>
<listitem><para>O <function>stat()</function> devolve informações acerca de um ficheiro como o seu tamanho, o tipo MIME, etc. Essa informação está contida num <classname>TDEIO::UDSEntry</classname>, o qual será discutido em baixo. Use o <function>statEntry()</function> para enviar um desses itens para a aplicação. </para></listitem>
<listitem><para>O <function>mimetype()</function> chama o <function>mimeType()</function> com um argumento de texto. </para></listitem>
<listitem><para>O <function>get()</function> e o <function>copy()</function> podem querer fornecer informações de progresso. Isto é feito com os métodos <function>totalSize()</function>, <function>processedSize()</function>, <function>speed()</function>. O tamanho total e o tamanho processado são indicados em 'bytes', enquanto que a velocidade é dada em 'bytes' por segundo. </para></listitem>
<listitem><para>Você poderá enviar pares arbitrários de chaves/valores de meta-dados com o <function>setMetaData()</function>. </para></listitem>
</itemizedlist>
</simplesect>
<simplesect id="nettransparency-interacting">
<title>Interagir com o utilizador</title>
<para>Algumas das vezes, um 'slave' precisa de interagir com o utilizador. Os exemplos incluem as mensagens de informações, as janela de autenticação e as janelas de confirmação, sempre que um ficheiro está prestes a ser sobreposto. </para>
<itemizedlist>
<listitem><para><function>infoMessage()</function> - Isto é para fins de informação, como a mensagem "A obter dados de <máquina>" do 'slave' de HTTP, o qual é mostrado normalmente na barra de estado do programa. Do lado da aplicação, este método corresponde ao 'signal' <function>TDEIO::Job::infoMessage()</function>. </para></listitem>
<listitem><para><function>warning()</function> - Mostra um aviso numa janela com o <function>KMessageBox::information()</function>. Se ainda estiver aberta uma mensagem de uma invocação anterior do warning() do mesmo processo-filho, nada acontece. </para></listitem>
<listitem><para><function>messageBox()</function> - Este é mais rico que o método anterior. Permite-lhe abrir uma mensagem com um texto e um título, assim como alguns botões. Veja o tipo enumerado <type>SlaveBase::MessageBoxType</type> para mais referências. </para></listitem>
<listitem><para><function>openPassDlg()</function> - Abre uma janela onde se poderá indicar o nome do utilizador e a sua senha. </para></listitem>
</itemizedlist>
</simplesect>
</sect1>
</chapter>
<appendix id="misc">
<title>Licença</title>
&underFDL;
&underGPL;
</appendix>
</book>
|