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
|
<?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 % French "INCLUDE"> <!-- change language only here -->
]>
<book lang="&language;">
<bookinfo>
<title>Vue d'ensemble de l'architecture de 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>Cette documentation donne une vue d'ensemble de la plate-forme de développement de KDE</para>
</abstract>
<keywordset>
<keyword>KDE</keyword>
<keyword>architecture</keyword>
<keyword>développement</keyword>
<keyword>programmation</keyword>
</keywordset>
</bookinfo>
<chapter id="structure">
<title>Structure des bibliothèques</title>
<simplesect id="structure-byname">
<title>Bibliothèques par nom</title>
<variablelist>
<varlistentry>
<term><ulink url="kdeapi:tdecore/index.html">tdecore</ulink></term>
<listitem><para>La bibliothèque tdecore est l'environnement d'applications de base de tout programme basé sur KDE. Elle fournit l'accès au système de configuration, la gestion de la ligne de commande, le chargement et la manipulation des icônes, certains types spéciaux de communication entre processus, la gestion des fichiers et divers autres utilitaires. </para></listitem>
</varlistentry>
<varlistentry>
<term><ulink url="kdeapi:tdeui/index.html">tdeui</ulink></term>
<listitem><para>La bibliothèque <literal>tdeui</literal> fournit de nombreux widgets et boîtes de dialogue standard dont Qt ne dispose pas ou qui ont davantage de fonctionnalités que leurs contreparties Qt. Elle contient également plusieurs widgets qui sont sous-classés à partir de ceux de Qt et sont mieux intégrés au bureau KDE en respectant les préférences de l'utilisateur. </para></listitem>
</varlistentry>
<varlistentry>
<term><ulink url="kdeapi:tdeio/index.html">tdeio</ulink></term>
<listitem><para>La bibliothèque <literal>tdeio</literal> contient des ressources pour les entrées / sorties asynchrones, transparentes vis-à-vis du réseau et un accès à la gestion des types mime. Elle fournit aussi les boîtes de dialogue des fichiers KDE et ses classes d'aide. </para></listitem>
</varlistentry>
<varlistentry>
<term><ulink url="kdeapi:kjs/index.html">kjs</ulink></term>
<listitem><para>La bibliothèque <literal>kjs</literal> fournit une implémentation de JavaScript. </para></listitem>
</varlistentry>
<varlistentry>
<term><ulink url="kdeapi:tdehtml/index.html">tdehtml</ulink></term>
<listitem><para>La bibliothèque <literal>tdehtml</literal> contient la partie TDEHTML, un widget de navigation HTML, l'API et l'analyseur DOM, y compris les interfaces à Java et JavaScript. </para></listitem>
</varlistentry>
</variablelist>
</simplesect>
<simplesect id="structure-grouped">
<title>Classes groupées</title>
<para>Squelette fondamental d'une application — classes requises par pratiquement toutes les applications. </para>
<itemizedlist>
<listitem><formalpara>
<title><ulink url="kdeapi:tdecore/TDEApplication">TDEApplication</ulink></title>
<para>Initialise et contrôle une application KDE. </para>
</formalpara></listitem>
<listitem><formalpara>
<title><ulink url="kdeapi:tdecore/KUniqueApplication">KUniqueApplication</ulink></title>
<para>Veille à ce qu'une seule instance d'une application puisse s'exécuter. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEAboutData">TDEAboutData</ulink></title>
<para>Contient des informations sur la zone « À propos ». </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDECmdLineArgs">TDECmdLineArgs</ulink></title>
<para>Traitement des arguments en ligne de commande. </para>
</formalpara></listitem>
</itemizedlist>
<para>Paramètres de configuration — accès à la base de données de configuration hiérarchique de KDE, aux réglages globaux et aux ressources des applications. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEConfig">TDEConfig</ulink></title>
<para>Fournit l'accès à la base de données de configuration de KDE. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KSimpleConfig">KSimpleConfig</ulink></title>
<para>Accès aux fichiers de configuration simples, non hiérarchiques. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KDesktopFile">KDesktopFile</ulink></title>
<para>Accès aux fichiers <literal>.desktop</literal>. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEGlobalSettings">TDEGlobalSettings</ulink></title>
<para>Accès pratique aux réglages non spécifiques à une application. </para>
</formalpara></listitem>
</itemizedlist>
<para>Gestion des fichiers et des URL — décodage des URL, fichiers temporaires, &etc; </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KURL">KURL</ulink></title>
<para>Représente et analyse les URL. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KTempFile">KTempFile</ulink></title>
<para>Crée des fichiers uniques pour les données temporaires. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KSaveFile">KSaveFile</ulink></title>
<para>Permet d'enregistrer des fichiers atomiquement. </para>
</formalpara></listitem>
</itemizedlist>
<para>Communication entre processus — classes d'assistant DCOP et invocation des sous-processus. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEProcess">TDEProcess</ulink></title>
<para>Invoque et contrôle les processus enfants. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KShellProcess">KShellProcess</ulink></title>
<para>Invoque les processus enfants <emphasis>via</emphasis> un shell. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdesu/PtyProcess">PtyProcess</ulink></title>
<para>Communication avec des processus enfants au moyen d'un pseudoterminal. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KIPC">KIPC</ulink></title>
<para>Mécanisme IPC simple utilisant ClientMessages sous X11. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:dcop/DCOPClient">DCOPClient</ulink></title>
<para>Messagerie DCOP. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KDCOPPropertyProxy">KDCOPPropertyProxy</ulink></title>
<para>Une classe de proxy annonçant les propriétés Qt au moyen de DCOP. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KDCOPActionProxy">KDCOPActionProxy</ulink></title>
<para>Une classe de proxy annonçant une interface DCOP pour des actions. </para>
</formalpara></listitem>
</itemizedlist>
<para>Classes d'utilitaires — gestion de la mémoire, expressions rationnelles, manipulation des chaînes, nombres aléatoires </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KRegExp">KRegExp</ulink></title>
<para>Correspondance des expressions rationnelles POSIX. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KStringHandler">KStringHandler</ulink></title>
<para>Une interface luxueuse pour la manipulation des chaînes. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEZoneAllocator">TDEZoneAllocator</ulink></title>
<para>Allocateur de mémoire efficace pour de grands groupes de petits objets. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KRandomSequence">KRandomSequence</ulink></title>
<para>Générateur de nombres pseudoaléatoires. </para>
</formalpara></listitem>
</itemizedlist>
<para>Accélérateurs clavier — classes aidant à établir des associations de touches cohérentes sur tout le bureau. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEAccel">TDEAccel</ulink></title>
<para>Collection de raccourcis clavier. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEStdAccel">TDEStdAccel</ulink></title>
<para>Accès aisé aux touches courantes de raccourcis clavier. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEGlobalAccel"></ulink></title>
<para>Collection de raccourcis clavier pour l'ensemble du système. </para>
</formalpara></listitem>
</itemizedlist>
<para>Traitement des images — chargement et manipulation des icônes. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEIconLoader">TDEIconLoader</ulink></title>
<para>Charge des icônes d'une manière se conformant à un thème. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDEIconTheme">TDEIconTheme</ulink></title>
<para>Classes d'aide pour TDEIconLoader. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KPixmap">KPixmap</ulink></title>
<para>Une classe de pixmaps avec des possibilités de tramage étendues. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KPixmapEffect">KPixmapEffect</ulink></title>
<para>Effets de pixmaps comme les dégradés et les motifs. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KPixmapIO">KPixmapIO</ulink></title>
<para>Conversion rapide <classname>QImage</classname> en <classname>QPixmap</classname>. </para>
</formalpara></listitem>
</itemizedlist>
<para>Glisser et déposer — objets guides pour les couleurs et les URL. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KURLDrag">KURLDrag</ulink></title>
<para>Un objet guide pour les URL. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KColorDrag">KColorDrag</ulink></title>
<para>Un objet guide pour les couleurs. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KMultipleDrag">KMultipleDrag</ulink></title>
<para>Permet de construire des objets guides à partir de plusieurs autres. </para>
</formalpara></listitem>
</itemizedlist>
<para>Complétement automatique </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/TDECompletion">TDECompletion</ulink></title>
<para>Complétement automatique générique des chaînes. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KURLCompletion">KURLCompletion</ulink></title>
<para>Complétement automatique des URL. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KShellCompletion">KShellCompletion</ulink></title>
<para>Complétement automatique des exécutables. </para>
</formalpara></listitem>
</itemizedlist>
<para>Widgets — classes de widgets pour le mode liste, les règles, le choix des couleurs, &etc; </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEListView">TDEListView</ulink></title>
<para>Une variante de <classname>QListView</classname> qui fait honneur aux réglages de KDE sur l'ensemble du système. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEListView">TDEListBox</ulink></title>
<para>Une variante de <classname>QListBox</classname> qui fait honneur aux réglages de KDE sur l'ensemble du système. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEListView">TDEIconView</ulink></title>
<para>Une variante de <classname>QIconView</classname> qui fait honneur aux réglages de KDE sur l'ensemble du système. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEListView">KLineEdit</ulink></title>
<para>Une variante de <classname>QLineEdit</classname> avec la prise en charge du complétement. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KComboBox">KComboBox</ulink></title>
<para>Une variante de <classname>QComboBox</classname> avec la prise en charge du complétement. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEFontCombo">TDEFontCombo</ulink></title>
<para>Une zone de liste modifiable pour sélectionner les polices. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KColorCombo">KColorCombo</ulink></title>
<para>Une zone de liste modifiable pour sélectionner les couleurs. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KColorButton">KColorButton</ulink></title>
<para>Un bouton pour sélectionner les couleurs. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KURLCombo">KURLCombo</ulink></title>
<para>Une zone de liste modifiable pour sélectionner les noms de fichiers et les URL. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdefile/KURLRequester">KURLRequester</ulink></title>
<para>Une édition de lignes pour sélectionner les noms de fichiers et les URL. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KRuler">KRuler</ulink></title>
<para>Un widget règle. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink
url="kdeapi:tdeui/KAnimWidget">KAnimWidget</ulink></title>
<para>Des animations. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KNumInput">KNumInput</ulink></title>
<para>Un widget pour saisir les nombres. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KPasswordEdit">KPasswordEdit</ulink></title>
<para>Un widget pour saisir les mots de passe. </para>
</formalpara></listitem>
</itemizedlist>
<para>Boîtes de dialogue — boîtes de dialogue complètes pour la sélection des fichiers, des couleurs et des polices. </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdefile/KFileDialog">KFileDialog</ulink></title>
<para>Une boîte de dialogue de sélection des fichiers. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KColorDialog">KColorDialog</ulink></title>
<para>Une boîte de dialogue de sélection des couleurs. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEFontDialog">TDEFontDialog</ulink></title>
<para>Une boîte de dialogue pour la sélection des polices. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdefile/TDEIconDialog">TDEIconDialog</ulink></title>
<para>Une boîte de dialogue pour la sélection des icônes. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KKeyDialog">KKeyDialog</ulink></title>
<para>Une boîte de dialogue pour l'édition des associations de touches clavier. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KEditToolBar">KEditToolBar</ulink></title>
<para>Une boîte de dialogue pour l'édition des barres d'outils. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KTipDialog">KTipDialog</ulink></title>
<para>Une boîte de dialogue « Astuce du jour ». </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEAboutDialog">TDEAboutDialog</ulink></title>
<para>Une boîte de dialogue « À propos ». </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KLineEditDlg">KLineEditDlg</ulink></title>
<para>Une boîte de dialogue simple pour saisir du texte. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdefile/KURLRequesterDlg">KURLRequesterDlg</ulink></title>
<para>Une boîte de dialogue simple pour saisir les URL. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KMessageBox">KMessageBox</ulink></title>
<para>Une boîte de dialogue pour signaler les erreurs et les avertissements. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KPasswordDialog">KPasswordDialog</ulink></title>
<para>Une boîte de dialogue pour saisir les mots de passe. </para>
</formalpara></listitem>
</itemizedlist>
<para>Actions et interface graphique XML </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEAction">TDEAction</ulink></title>
<para>Abstraction pour une action qui peut être intégrée dans les barres de menus et les barres d'outils. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/TDEActionCollection">TDEActionCollection</ulink></title>
<para>Un ensemble d'actions. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeui/KXMLGUIClient">KXMLGUIClient</ulink></title>
<para>Un fragment d'interface graphique se composant d'une collection d'actions et d'une arborescence DOM représentant leur emplacement dans l'interface graphique. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeparts/KPartManager">KPartManager</ulink></title>
<para>Gère l'activation des clients XMLGUI. </para>
</formalpara></listitem>
</itemizedlist>
<para>Modules externes (<emphasis>plugins</emphasis>) et composants </para>
<itemizedlist>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KLibrary">KLibrary</ulink></title>
<para>Représente une bibliothèque chargée dynamiquement. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KLibrary">KLibLoader</ulink></title>
<para>Chargement d'une bibliothèque partagée. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdecore/KLibFactory">KLibFactory</ulink></title>
<para>Fabrique d'objets dans des modules externes. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KServiceType">KServiceType</ulink></title>
<para>Représente un type de service. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KService">KService</ulink></title>
<para>Représente un service. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KMimeType">KMimeType</ulink></title>
<para>Représente un type MIME. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KServiceTypeProfile">KServiceTypeProfile</ulink></title>
<para>Préférences utilisateur pour la mise en correspondance des types MIME. </para>
</formalpara></listitem>
<listitem><formalpara><title><ulink url="kdeapi:tdeio/KServiceTypeProfile">TDETrader</ulink></title>
<para>Requêtes de services. </para>
</formalpara></listitem>
</itemizedlist>
</simplesect>
</chapter>
<chapter id="graphics">
<title>Graphiques</title>
<sect1 id="graphics-qpainter">
<title>Graphiques bas niveau avec QPainter</title>
<simplesect id="qpainter-rendering">
<title>Rendu avec QPainter</title>
<para>Le modèle d'imagerie bas niveau de Qt est basé sur les possibilités fournies par X11 et d'autres systèmes de fenêtrage pour lesquels des ports Qt existent. Mais il les étend également en implémentant des fonctionnalités additionnelles telles que les transformations affines arbitraires pour le texte et les pixmaps. </para>
<para>La classe graphique centrale pour le dessin en 2D avec Qt est <ulink url="kdeapi:qt/QPainter">QPainter</ulink>. Elle peut dessiner sur un <ulink url="kdeapi:qt/QPaintDevice">QPaintDevice</ulink>. Il y a trois périphériques de dessin possibles implémentés : l'un est <ulink url="kdeapi:qt/QWidget">QWidget</ulink> qui représente un widget sur l'écran. Le deuxième est <ulink url="kdeapi:qt/QPrinter">QPrinter</ulink> qui représente une imprimante et produit une sortie Postscript. Le troisième est la classe <ulink url="kdeapi:qt/QPicture">QPicture</ulink> qui enregistre les commandes de dessin, peut les enregistrer sur disque et les lire plus tard. Un format possible de stockage pour le dessin est le standard SVG du W3C. </para>
<para>Il est donc possible de réutiliser le code de rendu pour afficher un widget pour l'impression, avec les mêmes fonctionnalités prises en charge. Bien sûr, en pratique, le code est utilisé dans un contexte légèrement différent. Le dessin sur un widget est presque exclusivement exécuté dans la méthode paintEvent() d'une classe de widget. </para>
<programlisting>void FooWidget::paintEvent()
{
QPainter p(this);
// Configurer le pinceau
// Utiliser le pinceau
}
</programlisting>
<para>En dessinant sur une imprimante, vous devez veiller à employer QPrinter::newPage() pour terminer une page et en commencer une nouvelle — chose qui naturellement n'a rien de pertinent lorsqu'il s'agit de dessiner des widgets. De plus, au moment de l'impression vous pouvez être amené à employer la <ulink url="kdeapi:qt/QPaintDeviceMetrics">métrique du périphérique</ulink> afin d'en calculer les coordonnées. </para>
</simplesect>
<simplesect id="qpainter-transformations">
<title>Transformations</title>
<para>Lorsqu'on se sert de QPainter, ce dernier trace par défaut le système de coordonnées naturel du périphérique utilisé. Cela signifie que si vous dessinez le long de l'axe horizontal une ligne d'une longueur de 10 unités, elle sera tracée sur l'écran comme une ligne horizontale d'une longueur de 10 pixels. Cependant, QPainter peut appliquer des transformations affines arbitraires avant de véritablement rendre les formes et les courbes. Une transformation affine met en correspondance les coordonnées x et y linéairement en x' et y' en conséquence </para>
<mediaobject>
<imageobject><imagedata fileref="affine-general.png"/></imageobject>
</mediaobject>
<para>La matrice 3x3 dans cette équation peut être définie avec QPainter::setWorldMatrix() et elle est de type <ulink url="kdeapi:qt/QWMatrix">QWMatrix</ulink>. Normalement, il s'agit de la matrice identité, &cad; que m11 et m22 sont égales à un, et les autres paramètres sont nuls. Il y a essentiellement trois groupes différents de transformations : </para>
<itemizedlist>
<listitem><formalpara>
<title>Translations</title>
<para>Celles-ci déplacent tous les points d'un objet d'une quantité fixe dans une certaine direction. Une matrice de translation peut être obtenue en appelant la méthode m.translate(dx, dy) pour une QWMatrix. Ceci correspond à la matrice </para>
</formalpara>
<mediaobject>
<imageobject><imagedata fileref="affine-translate.png"/></imageobject>
</mediaobject>
</listitem>
<listitem><formalpara>
<title>Changement d'échelle</title>
<para>Celle-ci étire ou rétrécit les coordonnées d'un objet, en le rendant plus gros ou plus petit sans le distordre. Une transformation de changement d'échelle peut être appliquée à une QWMatrix en appelant m.scale(sx, sy). Ceci correspond à la matrice </para>
</formalpara>
<mediaobject>
<imageobject><imagedata fileref="affine-scale.png"/></imageobject>
</mediaobject>
<para>En attribuant à l'un de ces paramètres une valeur négative, on peut réaliser une mise en miroir du système de coordonnées. </para>
</listitem>
<listitem><formalpara>
<title>Glissement</title>
<para>Une distorsion du système de coordonnées avec deux paramètres. Une transformation de glissement peut être appliquée en appelant m.shear(sh, sv), correspondant à la matrice </para>
</formalpara>
<mediaobject>
<imageobject><imagedata fileref="affine-shear.png"/></imageobject>
</mediaobject>
</listitem>
<listitem><formalpara>
<title>Rotation</title>
<para>Celle-ci fait tourner un objet. Une transformation de rotation peut être appliquée en appelant m.rotate(alpha). Notez que l'angle doit être indiqué en degrés, non sous un angle mathématique ! La matrice correspondante est </para>
</formalpara>
<mediaobject>
<imageobject><imagedata fileref="affine-rotate.png"/></imageobject>
</mediaobject>
<para>Notez qu'une rotation est équivalente à une combinaison de changement d'échelle et de glissement. </para>
</listitem>
</itemizedlist>
<para>Voici quelques images qui montre l'effet de la transformation élémentaire de notre mascotte : </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) Normale</entry>
<entry>b) Après rotation de 30 degrés</entry>
<entry>c) Après glissement de 0.4</entry>
<entry>d) Mise en miroir</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>Les transformations peuvent être combinées en multipliant les matrices élémentaires. Notez que les opérations sur les matrices ne sont pas commutatives en général et, par conséquent, l'effet combiné d'une concaténation dépend de l'ordre dans lequel les matrices sont multipliées. </para>
</simplesect>
<simplesect id="qpainter-strokeattributes">
<title>Définition des attributs de frappe</title>
<para>Le rendu des lignes, courbes et contours des polygones peut être modifié en définissant un crayon spécial avec QPainter::setPen(). L'argument de cette fonction est un objet <ulink url="kdeapi:qt/QPen">QPen</ulink>. Les propriétés qui y sont enregistrées sont un style, une couleur, un style de jointure et un style de capuchon. </para>
<para>Le style de crayon est un membre de l'énumération <ulink url="kdeapi:qt/Qt#PenStyle-enum">Qt::PenStyle</ulink>, et peut prendre une des valeurs suivantes : </para>
<mediaobject>
<imageobject><imagedata fileref="penstyles.png"/></imageobject>
</mediaobject>
<para>Le style de jointure est un membre de l'énumération <ulink url="kdeapi:qt/Qt#PenJoinStyle-enum">Qt::PenJoinStyle</ulink>. Il spécifie comment est tracée la jonction entre des lignes mutliples qui sont reliées l'une à l'autre. Il peut prendre une des valeurs suivantes : </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 (jointure en onglet)</entry>
<entry>c) BevelJoin (jointure biseautée)</entry>
<entry>b) RoundJoin (jointure arrondie)</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>Le style de capuchon est un membre de l'énumération <ulink url="kdeapi:qt/Qt#PenCapStyle-enum">Qt::PenCapStyle</ulink> et spécifie comment sont tracés les points finaux des lignes. Il prend l'une des valeurs provenant du tableau suivant : </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 (capuchon plat)</entry>
<entry>b) SquareCap (capuchon carré)</entry>
<entry>c) RoundCap (capuchon rond)</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</simplesect>
<simplesect id="qpainter-fillattributes">
<title>Définition des attributs de remplissage</title>
<para>Le style de remplissage des polygones, cercles ou rectangles peut être modifié en définissant une brosse spéciale avec QPainter::setBrush(). Cette fonction prend un objet <ulink url="kdeapi:qt/QBrush">QBrush</ulink> comme argument. Les brosses peuvent être construites de quatre manières différentes : </para>
<itemizedlist>
<listitem>
<para>QBrush::QBrush() — crée une brosse qui ne remplit pas les formes.</para>
</listitem>
<listitem>
<para>QBrush::QBrush(BrushStyle) — crée une brosse noire avec un des motifs par défaut illustrés ci-dessous.</para>
</listitem>
<listitem>
<para>QBrush::QBrush(const QColor &, BrushStyle) — crée une brosse colorée avec un des motifs illustrés ci-dessous.</para>
</listitem>
<listitem>
<para>QBrush::QBrush(const QColor &, const QPixmap) — crée une brosse colorée avec le motif personnalisé que vous indiquez comme second paramètre.</para>
</listitem>
</itemizedlist>
<para>Un style de brosse par défaut est un membre de l'énumération <ulink url="kdeapi:qt/Qt#BrushStyle-enum">Qt::BrushStyle</ulink>. Voici une illustration de tous les motifs prédéfinis : </para>
<mediaobject>
<imageobject><imagedata fileref="brushstyles.png"/></imageobject>
</mediaobject>
<para>Une autre manière de personnaliser le comportement de la brosse est d'utiliser la fonction QPainter::setBrushOrigin(). </para>
</simplesect>
<simplesect id="qpainter-color">
<title>Couleur</title>
<para>Les couleurs jouent un rôle à la fois lors de la frappe des courbes et lors du remplissage des formes. Dans Qt, les couleurs sont représentées par la classe <ulink url="kdeapi:qt/QColor">QColor</ulink>. Qt ne prend en charge aucune fonctionnalité graphique avancée comme les profils de couleur ICC (<emphasis>International Color Consortium</emphasis>) et la correction des couleurs. Les couleurs sont habituellement construites en spécifiant leurs composantes rouge, verte et bleue, puisque le modèle RVB est la manière dont sont composés les pixels sur un moniteur. </para>
<para>Il est également possible d'utiliser une teinte, une saturation et une valeur. Cette représentation HSV est ce dont vous vous servez dans la boîte des couleurs Gtk, &pex; dans Le GIMP. Ici, la teinte correspond à l'angle sur la roue de couleurs, alors que la saturation correspond à la distance depuis le centre du cercle. La valeur peut être choisie avec un curseur séparé. </para>
</simplesect>
<simplesect id="qpainter-paintsettings">
<title>Autres paramètres</title>
<para>Normalement, lorsque vous peignez sur un périphérique de peinture, les pixels que vous dessinez remplacent ceux qui s'y trouvaient auparavant. Cela signifie que lorsque vous peignez une certaine région avec une couleur rouge et que vous peignez la même région avec une couleur verte par la suite, seule la couleur bleue sera visible. Le modèle d'imagerie de Qt ne prend pas en charge la transparence, &cad; une manière de fondre l'avant-plan peint avec l'arrière-plan. Cependant, il y a un moyen simple de combiner arrière-plan et avant-plan avec des opérateurs booléens. La méthode QPainter::setRasterOp() définit l'opérateur utilisé, qui provient de l'énumération <ulink url="kdeapi:qt/Qt#RasterOp-enum">RasterOp</ulink>. </para>
<para>La valeur par défaut est CopyROP, qui ignore l'arrière-plan. Un autre choix courant est XorROP. Si vous tracez une ligne noire avec cet opérateur sur une image colorée, la zone couverte est alors inversée. Cet effet est par exemple permet de créer les sélections d'étirement dans les programmes de manipulation d'image connus sous l'expression « fourmis en marche ». </para>
</simplesect>
<simplesect id="qpainter-primitives">
<title>Traçage des primitives graphiques</title>
<para>Dans ce qui suit, nous répertorions les éléments graphiques élémentaires que gère QPainter. La plupart d'entre eux existe en plusieurs versions saturées qui prennent un nombre différent d'arguments. Par exemple, les méthodes qui portent sur les rectangles prennent soit un <ulink url="kdeapi:qt/QRect">QRect</ulink> comme argument, soit un ensemble de quatre entiers. </para>
<itemizedlist>
<listitem>
<para>Traçage d'un seul point — drawPoint().</para>
</listitem>
<listitem>
<para>Traçage des lignes — drawLine(), drawLineSegments() et drawPolyLine().</para>
</listitem>
<listitem>
<para>Traçage et remplissage des rectangles — drawRect(), drawRoundRect(), fillRect() et eraseRect().</para>
</listitem>
<listitem>
<para>Traçage et remplissage des cercles, des ellipses et de parties de ceux-ci — drawEllipse(), drawArc(), drawPie et drawChord().</para>
</listitem>
<listitem>
<para>Traçage et remplissage des polygones en général — drawPolygon().</para>
</listitem>
<listitem>
<para>Traçage des courbes de Bézier — drawQuadBezier() [drawCubicBezier dans Qt 3.0].</para>
</listitem>
</itemizedlist>
</simplesect>
<simplesect id="qpainter-pixmaps">
<title>Traçage des pixmaps et des images</title>
<para>Qt fournit deux classes très différentes pour représenter les images. </para>
<para><ulink url="kdeapi:qt/QPixmap">QPixmap</ulink> corrrespond directement aux objets pixmaps dans X11. Les pixmaps sont des objets côté serveur et peuvent — sur une carte graphique moderne — même être enregistrés directement dans la mémoire de la carte. Ce comportement la rend <emphasis>très</emphasis> efficace pour transférer les pixmaps à l'écran. Les pixmaps agissent aussi comme l'équivalent d'un hors-écran de widgets — la classe QPixmap étant une sous-classe de QPaintDevice, vous pouvez dessiner dessus avec un QPainter. Les opérations de dessin élémentaires sont habituellement accélérées par les cartes graphiques modernes. Par conséquent, un motif d'usage courant est d'utiliser les pixmaps pour le double tamponnement. Cela signifie que, au lieu de peindre directement sur un widget, vous peignez sur un objet pixmap temporaire et que vous employez la fonction <ulink url="kdeapi:qt/QPaintDevice#bitBlt-1">bitBlt</ulink> pour transférer le pixmap au widget. Pour des retraçages complexes, cette astuce permet d'éviter le papillottement. </para>
<para>En revanche, les objets <ulink url="kdeapi:qt/QImage">QImage</ulink> résident côté client. Ils se distinguent en fournissant un accès direct aux pixels de l'image. Ce comportement explique leur utilisation dans la manipulation des images, ainsi que les tâches comme le chargement et l'enregistrement sur disque (la méthode load() de QPixmap considère QImage comme une étape intermédiaire). Par ailleurs, le traçage d'une image sur un widget est une opération relativement coûteuse car elle implique un transfert vers le serveur X qui peut prendre du temps, en particulier pour les images de grandes dimensions et pour les serveurs distants. En fonction de la profondeur de couleur, la conversion de QImage en QPixmap peut aussi exiger un tramage. </para>
</simplesect>
<simplesect id="qpainter-drawingtext">
<title>Traçage du texte</title>
<para>Le texte peut être tracé avec une des variantes saturées de la méthode QPainter::drawText(). Celles-ci dessinent une QString soit à un point donné, soit dans un rectangle donné, en utilisant la police définie par QPainter::setFont(). Il y a également un paramètre qui prend une combinaison OU exclusif de certaines drapeaux à partir des énumérations <ulink url="kdeapi:qt/Qt#AlignmentFlags-enum">Qt::AlignmentFlags</ulink> et <ulink url="kdeapi:qt/Qt#TextFlags-enum">Qt::TextFlags</ulink> </para>
<para>En commençant par la version 3.0, Qt tient compte de la disposition complète du texte, même pour les langues qui s'écrivent de droite à gauche. </para>
<para>Une manière plus sophistiquée d'afficher du texte marqué est la classe <ulink url="kdeapi:qt/QSimpleRichText">QSimpleRichText</ulink>. Les objets de cette classe peuvent être construits avec un élément de texte à l'aide d'un sous-ensemble des marqueurs HTML, qui est assez riche et fournit même des tableaux. Le style du texte peut être personnalisé par l'emploi d'une <ulink url="kdeapi/qt/QStyleSheet">QStyleSheet</ulink> (la documentation des marqueurs se trouve également ici). Une fois l'objet texte enrichi construit, il peut être rendu sur un widget ou un autre périphérique de traçage avec la méthode QSimpleRichText::draw(). </para>
</simplesect>
</sect1>
<sect1 id="graphics-qcanvas">
<title>Graphiques structurés avec QCanvas</title>
<para>QPainter offre un modèle d'imagerie puissant pour peindre sur les widgets et les pixmaps. Toutefois, son utilisation peut être fastidieuse. Chaque fois que votre widget reçoit un événement peinture, il doit analyser la QPaintEvent::region() ou la QPaintEvent::rect() qui doit être redessinée. Puis il lui faut configurer un QPainter et peindre tous les objets qui se chevauchent sur cette région. Imaginez par exemple un programme de dessin vectoriel qui permet de faire glisser des objets comme les polygones, les cercles et les groupes de ceux-ci tout autour. Chaque fois que ces objets se déplacent un peu, l'événement souris du widget déclenche un événement peinture pour l'ensemble de la zone couverte par les objets dans leur ancienne position et dans leur nouvelle position. La découverte des retraçages nécessaires et leur exécution d'une manière efficace peut être difficile et peut entraîner un conflit avec la structure orientée objet du code source du programme. </para>
<para>À titre d'alternative, Qt contient la classe <ulink url="kdeapi:qt/QCanvas">QCanvas</ulink> dans laquelle vous placerez des objets graphiques comme les polygones, le texte, les pixmaps. Vous pouvez également fournir des éléments additionnels en sous-classant <ulink url="kdeapi:qt/QCanvasItem">QCanvasItem</ulink> ou une de ses sous-classes plus spécialisées. Un canevas peut être représenté sur l'écran par un ou plusieurs widgets de la classe <ulink url="kdeapi:qt/QCanvas">QCanvasView</ulink> que vous devez sous-classer afin de gérer les interactions utilisateur. Qt tient compte de tous les retraçages des objets de la vue, si elles sont occasionnées par le widget exposé, les nouveaux objets créés ou modifiés, voire d'autres choses. En utilisant le double tamponnement, ceci peut être effectué d'une manière efficace et sans papillotement. </para>
<para>Les éléments du canevas peuvent se chevaucher les uns les autres. Dans ce cas, celui qui est visible dépend de l'ordre que QCanvasItem::setZ() peut affecter. Les éléments peuvent aussi être rendus visibles ou invisibles. Vous pouvez également fournir un arrière-plan à dessiner « derrière » tous les éléments et un avant-plan. Pour associer des événements souris à des objets, dans le canevas, il y a la méthode QCanvas::collisions() qui retourne une liste des éléments se chevauchant à un point donné. Voici une capture d'écran d'une vue du canevas en action : </para>
<mediaobject>
<imageobject><imagedata fileref="canvas.png"/></imageobject>
</mediaobject>
<para>Ici, le maillage est dessiné en arrière-plan. De plus, il y a un élément QCanvasText et un QCanvasPolygon violet. Le papillon est un QCanvasPixmap. Il a des zones transparentes de façon à ce que vous puissiez voir les éléments sous-jacents à travers lui. </para>
<para>Un didactitiel sur l'utilisation de QCanvas pour écrire des jeux basés sur des objets images se trouve <ulink url="http://zez.org/article/articleview/2/1/">ici</ulink>. </para>
</sect1>
<sect1 id="graphics-qglwidget">
<title>Graphiques en 3D avec OpenGL</title>
<simplesect id="qglwidget-lowlevel">
<title>Interface bas niveau</title>
<para>Le standard <emphasis>de facto</emphasis> pour le rendu des graphiques en 3D aujourd'hui est <ulink url="http://www.opengl.org">OpenGL</ulink>. Les implémentations de ces spécifications sont présentes dans Microsoft Windows, Mac OS X, XFree86 et gèrent souvent les fonctionnalités d'accélération matérielle qu'offrent les cartes graphiques modernes. OpenGL lui-même ne se consacre qu'au rendu sur une zone spécifiée du tampon de trame grâce à un <emphasis>contexte GL</emphasis> et n'a aucune interaction avec la boîte à outils de l'environnement </para>
<para>Qt offre le widget <ulink url="kdeapi:qt/QGLWidget">QGLWidget</ulink> qui encapsule une fenêtre avec un contexte GL associé. Vous l'utiliserez essentiellement en le sous-classant et en réimplémentant certaines méthodes. </para>
<itemizedlist>
<listitem><para>Au lieu de réimplémenter paintEvent() et d'utiliser QPainter pour dessiner le contenu du widget, annulez paintGL() et utilisez les commandes GL pour rendre une scène. QLWidget prendra soin de faire de son contexte GL le contexte actuel avant que paintGL() ne soit appelé, et il l'éliminera par la suite. </para></listitem>
<listitem><para>La méthode virtuelle initializeGL() est appelée immédiatement avant la première fois où resizeGL() ou paintGL() est appelées. Elle peut servir à construire des listes d'affichage pour des objets et procéder à quelques initialisations. </para></listitem>
<listitem><para>Au lieu de réimplémenter resizeEvent(), annulez resizeGL(). Cette dernière peut servir pour définir la fenêtre d'affichage de manière appropriée. </para></listitem>
<listitem><para>Au lieu d'appeler update() quand l'état de la scène a changé — &pex; quand vous l'animez avec un minuteur — appelez updateGL(). Cette action déclenchera un retraçage. </para></listitem>
</itemizedlist>
<para>En général, QGLWidget se comporte tout comme n'importe quel autre widget, &cad; &pex; que vous pouvez traiter les événements souris comme d'habitude, redimensionner le widget et le combiner avec d'autres dans une topologie. </para>
<mediaobject>
<imageobject><imagedata fileref="opengl.png"/></imageobject>
</mediaobject>
<para>Qt contient quelques exemples de l'utilisation de QGLWidget dans son exemple <literal>démo</literal>. Vous trouverez <ulink url="http://www.libsdl.org/opengl/intro.html">ici</ulink> un ensemble de didactitiels ; d'autres informations et une référence d'OpenGL sont disponibles sur la <ulink url="http://www.opengl.org">page d'accueil d'OpenGL</ulink>. </para>
</simplesect>
<simplesect id="qglwidget-highlevel">
<title>Interfaces haut niveau</title>
<para>OpenGL est une interface assez bas niveau pour dessiner des graphiques en 3D. De la même manière que QCanvas donne au programmeur une interface de plus haut niveau avec des détails, des objets et leurs propriétés, il y a également des interfaces haut niveau pour les graphiques en 3D. Une des interfaces les plus connues est Open Inventor. Technologie à l'origine développée par SGI, il existe aujourd'hui l'implémentation open source <ulink url="http://www.coin3d.org">Coin</ulink>, complétée par l'association d'une boîte à outils à Qt appelée SoQt. </para>
<para>Le concept fondamental d'Open Inventor est celui d'une <emphasis>scène</emphasis>. Une scène peut être chargée depuis un disque et enregistrée dans un format spécial étroitement lié à <ulink url="http://www.vrml.org">VRML</ulink>. Une scène consiste en une collection d'objets appelés <emphasis>nœuds</emphasis>. Inventor fournit déjà une riche collection de nœuds réutilisables, tels que des cubes, des cylindres et des mailles, en plus de sources lumineuses, de matériaux, de caméras, &etc; Les nœuds sont représentés par des classes C++ et peuvent être combinés et sous-classés. </para>
<para>Vous trouverez une introduction à Inventor <ulink url="http://www.motifzone.com/tmd/articles/OpenInventor/OpenInventor.html">ici</ulink> (en général, vous pouvez substituer toutes les mentions de SoXt par SoQt dans cet article). </para>
</simplesect>
</sect1>
</chapter>
<chapter id="userinterface">
<title>Interface utilisateur</title>
<sect1 id="userinterface-actionpattern">
<title>Le motif de l'action</title>
<para></para>
</sect1>
<sect1 id="userinterface-xmlgui">
<title>Définition des menus et des barres d'outils dans XML</title>
<simplesect id="xmlgui-intro">
<title>Introduction</title>
<para>Alors que le <link linkend="userinterface-actionpattern">motif des actions</link> permet d'encapsuler les actions déclenchées par l'utilisateur dans un objet qui peut être « enfiché » quelque part dans les barres de menus ou les barres d'outils, il ne résoud pas par lui-même le problème de la construction des menus proprement dits. En particulier, vous aurez à construire tous les menus contextuels en code C++ et à insérer explicitement les actions dans un certain ordre, à l'étude du guide de style pour les actions standard. Ceci complique la tâche de l'utilisateur pour personnaliser les menus ou changer les raccourcis pour les adapter à ses besoins, sans modifier le code source. </para>
<para>Ce problème est résolu par un ensemble de classes appelé <literal>XMLGUI</literal>. En susbtance, celui-ci sépare les actions (codées en C++) de leur apparance dans les barres de menus et les barres d'outils (codées en XML). Sans modifier aucun code source, les menus peuvent être simplement personnalisés en ajustant un fichier XML. En outre, il permet de s'assurer que les actions standard (telles que <menuchoice><guimenu>Fichier</guimenu><guimenuitem>Ouvrir</guimenuitem></menuchoice> ou <menuchoice><guimenu>Aide</guimenu><guimenuitem>À propos de</guimenuitem></menuchoice>) apparaissent dans les endroits suggérés par le guide de style. XMLGUI est particulièrement important pour les programmes modulaires, dans lesquels les éléments apparaissant dans la barre de menus peuvent provenir de nombreux modules externes (<emphasis>plugins</emphasis>) ou parties différents. </para>
<para>La classe de KDE pour les fenêtres de premier niveau, <ulink url="kdeapi:tdeui/TDEMainWindow.html">TDEMainWindow</ulink>, hérite de <ulink url="kdeapi:tdeui/KXMLGUIClient.html">KXMLGUIClient</ulink> et gère donc XMLGUI en dehors de l'ordinateur. Toutes les actions créées en son sein doivent avoir la <literal>actionCollection()</literal> du client comme parent. Un appel à <literal>createGUI()</literal> construira ensuite l'ensemble complet des barres de menus et d'outils défini dans le fichier XML des applications (par convention, avec le suffixe <literal>ui.rc</literal>). </para>
</simplesect>
<simplesect id="xmlgui-kviewexample">
<title>Un exemple : un menu dans KView</title>
<para>Dans ce qui suit, nous prenons l'afficheur d'images <application>KView</application> de KDE à titre d'exemple. Il a un fichier <literal>ui.rc</literal> nommé <filename>kviewui.rc</filename> qui est installé avec le fragment <filename>Makefile.am</filename> </para>
<programlisting>rcdir = $(kde_datadir)/kview
rc_DATA = kviewui.rc
</programlisting>
<para>Voici un extrait du fichier <filename>kviewui.rc</filename>. Pour la simplicité, nous n'afficherons que la définition du menu <guimenu>Affichage</guimenu>. </para>
<programlisting><!DOCTYPE kpartgui>
<kpartgui name="kview">
<MenuBar>
<Menu name="affichage" >
<Action name="zoom50" />
<Action name="zoom100" />
<Action name="zoom200" />
<Action name="zoomMaxpect" />
<Separator/>
<Action name="plein écran" />
</Menu>
</MenuBar>
</kpartgui>
</programlisting>
<para>La partie correspondante de la configuration en C++ est : </para>
<programlisting>KStdAction::zoomIn ( this, SLOT(slotZoomIn()), actionCollection() );
KStdAction::zoomOut ( this, SLOT(slotZoomOut()), actionCollection() );
KStdAction::zoom ( this, SLOT(slotZoom()), actionCollection() );
new TDEAction ( i18n("&Half size"), ALT+Key_0,
this, SLOT(slotHalfSize()),
actionCollection(), "zoom50" );
new TDEAction ( i18n("&Normal size"), ALT+Key_1,
this, SLOT(slotDoubleSize()),
actionCollection(), "zoom100" );
new TDEAction ( i18n("&Double size"), ALT+Key_2,
this, SLOT(slotDoubleSize()),
actionCollection(), "zoom200" );
new TDEAction ( i18n("&Fill Screen"), ALT+Key_3,
this, SLOT(slotFillScreen()),
actionCollection(), "zoomMaxpect" );
new TDEAction ( i18n("Fullscreen &Mode"), CTRL+SHIFT+Key_F,
this, SLOT(slotFullScreen()),
actionCollection(), "fullscreen" );
</programlisting>
<para>Le menu <guimenu>Affichage</guimenu> résultant de la définition de cette interface graphique ressemble à celle de cette capture d'écran : </para>
<mediaobject>
<imageobject><imagedata fileref="kview-menu.png"/></imageobject>
</mediaobject>
<para>Le fichier XML commence par une déclaration de type de document. La DTD pour kpartgui se trouve dans les sources tdelibs dans <filename>tdeui/kpartgui.dtd</filename>. L'élément le plus externe du fichier contient le nom d'instance de l'application comme attribut. Il peut également contenir un numéro de version de la forme « version=2 ». Ce détail est utile lorsque vous diffusez de nouvelles versions d'une application avec une structure de menu modifiée, &pex; avec davantage de fonctionnalités. Si vous gonflez le numéro de version du fichier <literal>ui.rc</literal>, KDE s'assure que toute version personnalisée du fichier est éliminée et que le nouveau fichier est utilisé à la place. </para>
<para>La ligne suivante, <literal><MenuBar></literal>, contient une déclaration d'une barre de menus. Vous pouvez aussi insérer n'importe quel nombre de déclarations <literal><ToolBar></literal> afin de créer quelques barres d'outils. Le menu contient un sous-menu avec le nom « affichage ». Ce nom est déjà prédéfini et ainsi, vous voyez une version traduite du mot « View » dans la capture d'écran. Si vous déclarez vos propres sous-menus, ajoutez le titre explicitement. Par exemple, <application>KView</application> a un sous-menu avec le titre « Image » déclaré comme suit : </para>
<programlisting><Menu name="image" >
<text>&amp;Image</text>
...
</Menu>
</programlisting>
<para>Dans l'environnement automake de KDE, de tels titres sont automatiquement extraits et placés dans le fichier <ulink url="tde-i18n-howto.html"><literal>.po</literal></ulink> de l'application pour que les traducteurs puissent le traiter. Notez que vous devez écrire le marqueur d'accélérateur « & » sous la forme conforme à XML, « &amp; ». </para>
<para>Revenons à notre exemple. Le menu <guimenu>Affichage</guimenu> de <application>KView</application> contient quelques actions personnalisées : <literal>zoom50</literal>, <literal>zoom100</literal>, <literal>zoom200</literal>, <literal>zoomMaxpect</literal> et <literal>fullscreen</literal>, déclarées avec un élément <literal><Action></literal>. Le séparateur dans les captures d'écran correspond à l'élément <literal><Separator></literal>. </para>
<para>Vous noterez que certains éléments de menus n'ont pas d'élément correspondant dans le fichier XML. Ce sont des <emphasis>actions standard</emphasis>. Les actions standard sont créées par la classe <ulink url="kdeapi:tdeui/KStdAction.html">KStdAction</ulink>. Quand vous créez de telles actions dans votre application (comme dans l'exemple C++ ci-dessus), elles sont automatiquement insérées dans une position imposée et éventuellement avec une icône et une touche de raccourci. Consultez ces emplacements dans le fichier <filename>tdeui/ui_standards.rc</filename>, dans les sources tdelibs. </para>
</simplesect>
<simplesect id="xmlgui-konqexample">
<title>Un exemple : les barres d'outils dans Konqueror</title>
<para>Pour l'étude des barres d'outils, passons à la définition de l'interface graphique de <application>Konqueror</application>. Cet extrait définit la barre d'URL qui contient le champ de saisie des URL. </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>La première chose que nous remarquons est qu'il y a beaucoup plus d'attributs que pour les barres de menus. Celles-ci comprennent : </para>
<itemizedlist>
<listitem><para><literal>fullWidth</literal> : indique à XMLGUI que la barre d'outils a la même largeur que la fenêtre de premier niveau. Si celle-ci est « false », la barre d'outils prend seulement l'espace nécessaire et les autres barres d'outils sont placées sur la même ligne. </para></listitem>
<listitem><para><literal>newline</literal> : ceci est en rapport avec l'option ci-dessus. Si « newline » est « true », la barre d'outils commence une nouvelle ligne. Sinon elle peut être placée dans la même ligne, associée à la barre d'outils précédente. </para></listitem>
<listitem><para><literal>noEdit</literal> : normalement, les barres d'outils peuvent être personnalisées par l'utilisateur, &pex; dans <menuchoice><guimenu>Configuration</guimenu> <guimenuitem>Configurer les barres d'outils</guimenuitem></menuchoice> dans <application>Konqueror</application>. Le fait de définir cette option à « true » marque cette barre d'outils comme non modifiable. Ceci est important pour les barres d'outils qui sont remplis d'éléments au moment de l'exécution, &pex; la barre d'outils des signets de <application>Konqueror</application>. </para></listitem>
<listitem><para><literal>iconText</literal> : indique à XMLGUI d'afficher le texte de l'action qui suit l'icône. Normalement, le texte n'est affiché que sous la forme d'une bulle d'aide lorsque le curseur de la souris reste sur l'icône un instant. Des valeurs possibles pour cet attribut sont « icononly » (affiche uniquement l'icône), « textonly » (affiche uniquement le texte), « icontextright » (affiche le texte sur le côté droit de l'icône) et « icontextbottom » (affiche le texte au-dessous de l'icône). </para></listitem>
<listitem><para><literal>hidden</literal> : si ceci est « true », la barre d'outils n'est pas visible initialement et doit être activée par un élément de menu. </para></listitem>
<listitem><para><literal>position</literal> : la valeur par défaut pour cet attribut est « top », ce qui signifie que la barre d'outils est positionnée sous la barre de menus. Pour les programmes dotés de nombreux outils, comme les programmes graphiques, il peut être intéressant de remplacer ceci par « left », « right » ou « bottom ». </para></listitem>
</itemizedlist>
</simplesect>
<simplesect id="xmlgui-dynamical">
<title>Menus dynamiques</title>
<para>À l'évidence, un fichier XML ne peut contenir qu'une description statique d'une interface utilisateur. Souvent, il y a des menus qui changent au moment de l'exécution. Par exemple, le menu <guimenu>Document</guimenu> de <application>Konqueror</application> contient un ensemble d'éléments <guimenuitem>Ouvrir avec quelque chose</guimenuitem> avec les applications capables de charger un fichier avec un type MIME donné. Chaque fois que le document affiché change, la liste des éléments du menu est mise à jour. XMLGUI est préparée à gérer ce type de cas avec la notion de <emphasis>listes d'actions</emphasis>. Une liste d'actions est déclarée comme un seul élément dans le fichier XML mais se compose de plusieurs actions qui sont « enfichées » dans le menu au moment de l'exécution. L'exemple ci-dessus est mis en œuvre avec la déclaration suivante dans le fichier XML de <application>Konqueror</application> : </para>
<programlisting><Menu name="filchier">
<text>&amp;Location</text>
...
<ActionList name="openwith">
...
</Menu>
</programlisting>
<para>La fonction <function>KXMLGUIClient::plugActionList()</function> est alors utilisée pour ajouter des actions à afficher, alors que la fonction <function>KXMLGuiClient::unplugActionList()</function> supprime toutes les fonctions « enfichées ». Voici à quoi ressemble la routine responsable de la mise à jour : </para>
<programlisting>void MainWindow::updateOpenWithActions()
{
unplugActionList("openwith");
openWithActions.clear();
for ( /* itérer sur les services pertinents */ ) {
TDEAction *action = new TDEAction( ...);
openWithActions.append(action);
}
plugActionList("openwith", openWithActions);
}
</programlisting>
<para>Notez que, contrairement aux actions statiques, celles qui sont créées ici <emphasis>ne sont pas</emphasis> construites avec la collection des actions comme parent et que vous êtes responsable de leur suppression en propre. La manière la plus souple pour ce faire est d'utiliser <literal>openWithActions.setAutoDelete(true)</literal> dans l'exemple ci-dessus. </para>
</simplesect>
<simplesect id="xmlgui-contextmenus">
<title>Menus contextuels</title>
<para>Les exemples ci-dessus ne contenaient que des cas où étaient créées une barre de menus et des barres d'outils d'une fenêtre principale. Ici, les processus de construction de ces conteneurs vous sont complètement cachés derrière l'appel <function>createGUI()</function> (sauf si vous avez des conteneurs personnalisés). Toutefois, il y a des cas où vous serez amené à construire d'autres conteneurs et à les doter de définitions d'interfaces graphiques provenant du fichier XML. Les menus contextuels en sont un exemple. Afin d'obtenir un pointeur vers un menu contextuel, vous devez le demander à la fabrique du client : </para>
<programlisting>void MainWindow::popupRequested()
{
QWidget *w = factory()->container("context_popup", this);
QPopupMenu *popup = static_cast<QPopupMenu *>(w);
popup->exec(QCursor::pos());
}
</programlisting>
<para>La méthode <function>KXMLGUIFactory::container()</function> utilisée précédemment examine le fichier XML pour savoir si elle y trouve un conteneur du nom donné. Ainsi, voici à quoi pourrait ressembler une définition possible : </para>
<programlisting>...
<Menu name="context_popup">
<Action name="file_add"/>
<Action name="file_remove"/>
</Menu>
...
</programlisting>
</simplesect>
</sect1>
<sect1 id="help">
<title>Mise à disposition d'une aide en ligne</title>
<para>Le fait de rendre un programme facile et intuitif à utiliser implique une large palette de fonctions habituellement appelées « aide en ligne ». L'aide en ligne a plusieurs buts, partiellement en conflit : d'une part, elle doit fournir à l'utilisateur des réponses à la question « Comment puis-je effectuer telle ou telle tâche ? », de l'autre, elle doit l'aider à explorer l'application et à trouver les fonctionnalités qu'il ne connaît pas encore. Il est important de reconnaître que cet objectif peut être atteint en offrant plusieurs niveaux d'aide : </para>
<itemizedlist>
<listitem><para>Les bulles d'aide sont de petites étiquettes qui apparaissent sur les éléments de l'interface utilisateur quand la souris y reste quelques secondes. Elles sont particulièrement importantes pour les barres d'outils où les icônes ne sont pas toujours suffisantes pour expliquer la finalité d'un bouton. </para></listitem>
<listitem><para>L'aide « Qu'est-ce que c'est ? » est souvent une explication plus longue et plus fournie d'un widget ou d'un élément de menu. Elle est également plus incertaine à utiliser. Dans les boîtes de dialogue, on peut l'invoquer de deux façons : soit en appuyant sur <keycombo><keycap>Maj</keycap><keycap>F1</keycap></keycombo>, soit en cliquant sur le point d'interrogation dans la barre de titre (où la prise en charge de cette dernière dépend du gestionnaire de fenêtres). Le pointeur de la souris se transforme alors en point d'interrogation et la fenêtre d'aide apparaît quand on clique sur un élément de l'interface utilisateur. L'aide « Qu'est-ce que c'est ? » est d'ordinaire activée dans la barre d'outils par un bouton contenant une flèche et un point d'interrogation. </para></listitem>
<listitem><para>Le problème avec cette approche est que l'utilisateur ne peut pas voir si un widget fournit de l'aide ou non. Lorsqu'il active le bouton en forme de point d'interrogation et qu'il n'obtient aucune fenêtre d'aide en cliquant un élément de l'interface utilisateur, il est très rapidement frustré. </para>
<para>L'avantage des fenêtres d'aide « Qu'est-ce que c'est ? » telles qu'elles sont fournies par Qt et KDE est qu'elles peuvent contenir du <ulink url="kdeapi:qt/QStyleSheet">texte enrichi</ulink>, &cad; différentes polices, du texte en gras et en italique, voire des images et des tableaux. </para>
<para>Un exemple de l'aide « Qu'est-ce que c'est ? » : </para>
<mediaobject>
<imageobject><imagedata fileref="whatsthis.png"/></imageobject>
</mediaobject>
</listitem>
<listitem><para>Pour finir, tous les programmes devraient avoir un manuel. Un manuel s'affiche en principe dans <application>KHelpCenter</application> en activant le menu <guimenu>Aide</guimenu>. Cela signifie qu'une application supplémentaire complète apparaît et distrait l'utilisateur de son travail. En conséquence, la consultation du manuel ne devrait être nécessaire que si d'autres fonctions comme les bulles d'aide et l'aide « Qu'est-ce que c'est ? » ne sont pas suffisantes. Naturellement un manuel a l'avantage de ne pas décrire un seul aspect isolé de l'application dans un contexte plus spacieux. Les manuels de KDE sont écrits à l'aide du langage de marquage <ulink url="http://i18n.kde.org">DocBook</ulink>. </para></listitem>
</itemizedlist>
<para>Du point de vue du programmeur, Qt fournit un moyen aisé d'utiliser l'API pour l'aide en ligne. Pour affecter une bulle d'aide à un widget, faites appel à la classe <ulink url="kdeapi:qt/QToolTip">QToolTip</ulink>. </para>
<programlisting>QToolTip::add(w, i18n("Ce widget ne fait rien"))
</programlisting>
<para>Si les barres de menus et les barres d'outils sont créées à l'aide du <ulink url="actionpattern.html">motif d'actions</ulink>, la chaîne employée comme bulle d'aide est dérivée du premier argument du constructeur <ulink url="kdeapi:tdeui/TDEAction.html">TDEAction</ulink> : </para>
<programlisting>action = new TDEAction(i18n("&Delete"), "editdelete",
SHIFT+Key_Delete, actionCollection(), "del")
</programlisting>
<para>Ici, il est également possible d'affecter un texte qui est affiché dans la barre d'état lorsque l'élément du menu respectif est mis en évidence : </para>
<programlisting>action->setStatusText(i18n("Supprime le fichier marqué"))
</programlisting>
<para>L'API pour l'aide « Qu'est-ce que c'est ? » est très similaire. Dans les boîtes de dialogue, utilisez le code suivant : </para>
<programlisting>QWhatsThis::add(w, i18n("<qt>This demonstrates <b>Qt</b>'s"
" rich text engine.<ul>"
"<li>Foo</li>"
"<li>Bar</li>"
"</ul></qt>"))
</programlisting>
<para>Pour les éléments de menu, utilisez </para>
<programlisting>action->setWhatsThis(i18n("Supprime le fichier marqué"))
</programlisting>
<para>L'invocation de <application>KHelpCenter</application> est encapsulée dans la classe <ulink url="kdeapi:tdecore/TDEApplication">TDEApplication</ulink>. Pour afficher le manuel de votre application, utilisez simplement </para>
<programlisting>kapp->invokeHelp()
</programlisting>
<para>Cette commande affiche la première page avec la table des matières. Si vous voulez n'afficher qu'une certaine section du manuel, vous pouvez fournir un argument supplémentaire à <function>invokeHelp()</function>, déterminant l'ancrage vers lequel le navigateur saute. </para>
</sect1>
</chapter>
<chapter id="components">
<title>Composants et services</title>
<sect1 id="components-services">
<title>Services KDE</title>
<simplesect id="services-whatarekdeservices">
<title>Que sont les services KDE ?</title>
<para>La notion de <emphasis>service</emphasis> est un concept fondamental dans l'architecture modulaire de KDE. Il n'y aucune implémentation technique stricte associée à ce terme — les services peuvent être des modules externes (<emphasis>plugins</emphasis>) sous la forme de bibliothèques partagées, ou bien il peut s'agir de programmes contrôlés <emphasis>via</emphasis> <ulink url="dcop.html">DCOP</ulink>. En se proclamant être d'un certain <emphasis>type de service</emphasis>, un service promet d'implémenter certaines API ou fonctionnalités. En termes C++, on peut penser à un type de service comme à une classe d'abstraction, et à un service comme à une implémentation de cette interface. </para>
<para>L'avantage de cette séparation est clair : une application utilisant un type de service n'a pas à en connaître les implémentations possibles. Elle se contente d'employer les API associées au type de service. De cette manière, le service utilisé peut être modifié sans affecter l'application. En outre, l'utilisateur peut configurer les services qu'il préfère pour certaines fonctionnalités. </para>
<para>Quelques exemples : </para>
<itemizedlist>
<listitem><para>Le moteur de rendu HTML utilisé dans <application>Konqueror</application> est un composant intégrable qui implémente les types de services <literal>KParts/ReadOnlyPart</literal> et <literal>Navigateur/Affichage</literal>. </para></listitem>
<listitem><para>Dans <application>KDevelop</application> HEAD, la majorité des fonctionnalités est conditionnée en modules externes avec le type de service <literal>KDevelop/Part</literal>. Au démarrage, tous les services de ce type sont chargés, de telle sorte que vous puissiez étendre l'EDi d'une manière très souple. </para></listitem>
<listitem><para>Dans l'affichage Icône, <application>Konqueror</application> affiche — si activé — des représentations miniatures des images, des pages HTML, des fichiers PDF et texte. Cette capacité peut être étendue. Si vous souhaitez qu'elle affiche des aperçus des images de vos propres fichiers de données avec tel ou tel type MIME, mettez en œuvre un service avec un type de service <classname>ThumbCreator</classname>. </para></listitem>
</itemizedlist>
<para>À l'évidence, un service n'est pas seulement caractérisé par les types de services qu'il met en œuvre, mais aussi par quelques <emphasis>propriétés</emphasis>. Par exemple, un ThumbCreator ne se se contente pas d'implémenter la classe C++ avec le type <classname>ThumbCreator</classname>, il a aussi une liste de types MIME dont il est responsable. De la même manière, les « parties » de KDevelop ont comme propriété le langage de programmation qu'elles prennent en charge. Lorsqu'une application demande un type de service, elle peut également dresser la liste des contraintes sur les propriétés du service. Dans l'exemple ci-dessus, quand KDevelop charge les modules externes pour un projet Java, il demande seulement ceux qui ont Java comme propriété de langage de programmation. À cette fin, KDE contient un <emphasis>courtier</emphasis> à part entière dans le style de CORBA, doté d'un langage de requête complexe. </para>
</simplesect>
<simplesect id="services-definingservicetypes">
<title>Définition des types de services</title>
<para>Les nouveaux types de services sont ajoutés en installant une description dans le dossier <filename>TDEDIR/share/servicetypes</filename>. Dans un environnement automake, cette tâche s'effectue avec ce fragment de <filename>Makefile.am</filename> : </para>
<programlisting>kde_servicetypesdir_DATA = tdeveloppart.desktop
EXTRA_DIST = $(kde_servicetypesdir_DATA)
</programlisting>
<para>Voici à quoi ressemble la définition <filename>tdeveloppart.desktop</filename> d'une « partie » <application>KDevelop</application> : </para>
<programlisting>[Desktop Entry]
Type=ServiceType
X-TDE-ServiceType=KDevelop/Part
Name=KDevelop Part
[PropertyDef::X-KDevelop-Scope]
Type=QString
[PropertyDef::X-KDevelop-ProgrammingLanguages]
Type=QStringList
[PropertyDef::X-KDevelop-Args]
Type=QString
</programlisting>
<para>En plus des lignes habituelles, cet exemple explique comment déclarer qu'un service a certaines propriétés. Chaque définition de propriété correspond à un groupe <literal>[PropertyDef::name]</literal> dans le fichier de configuration. Dans ce groupe, la ligne <literal>Type</literal> déclare le type de la propriété. Les types possibles sont tout ce qui peut être enregistré dans une <ulink url="kdeapi:qt/QVariant">QVariant</ulink>. </para>
</simplesect>
<simplesect id="services-defininglibraryservices">
<title>Définition des services de bibliothèques partagées</title>
<para>Les définitions des services sont enregistrées dans le dossier <filename>TDEDIR/share/services</filename>: </para>
<programlisting>kde_servicesdir_DATA = kdevdoxygen.desktop
EXTRA_DIST = $(kde_servicesdir_DATA)
</programlisting>
<para>Le contenu du fichier d'exemple suivant <filename>kdevdoxygen.desktop</filename> définit le module externe <literal>KDevDoxygen</literal> avec le type de service <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>En plus des déclarations habituelles, <literal>X-TDE-Library</literal> est une ligne importante. Elle contient le nom de la bibliothèque libtool (sans l'extension <literal>.la</literal>). Elle fixe également (avec le préfixe <literal>init_</literal> ajouté au début) le nom du symbole exporté dans la bibliothèque qui retourne une fabrique d'objets. Pour l'exemple ci-dessus, la bibliothèque doit contenir la fonction suivante : </para>
<programlisting>extern "C" {
void *init_libkdevdoxygen()
{
return new DoxygenFactory;
}
};
</programlisting>
<para>Le type de la classe de fabrique <classname>DoxygenFactory</classname> dépend du type de service spécifique que le service met en œuvre. Dans notre exemple d'un module externe KDevelop, la fabrique doit être une <classname>KDevFactory</classname> (qui hérite de <classname>KLibFactory</classname>). <ulink url="kdeapi:tdeparts/KParts::Factory">KParts::Factory</ulink> est un autre exemple courant supposé produire des objets <ulink url="kdeapi:tdeparts/KParts::ReadOnlyPart">KParts::ReadOnlyPart</ulink> ou dans la plupart des cas, la <ulink url="kdeapi:tdecore/KLibFactory">KLibFactory</ulink> générique. </para>
</simplesect>
<simplesect id="services-usinglibraryservices">
<title>Utilisation des services de bibliothèques partagées</title>
<para>Pour employer un service de bibliothèque partagée dans une application, vous devez obtenir un objet <ulink url="kdeapi:tdeio/KService.html">KService</ulink> qui le représente. Ce point est étudié dans la <ulink url="mime.html">section sur les types MIME</ulink> (et dans une section consacrée au courtier — à écrire) </para>
<para>Une fois l'objet <classname>KService</classname> en main, vous pouvez très simplement charger la bibliothèque et obtenir un pointeur vers son objet fabrique : </para>
<programlisting>KService *service = ...
QString libName = QFile::encodeName(service->library());
KLibFactory *factory = KLibLoader::self()->factory(libName);
if (!factory) {
QString name = service->name();
QString errorMessage = KLibLoader::self()->lastErrorMessage();
KMessageBox::error(0, i18n("Une erreur de chargement de service % s'est produite1.\n"
"Le diagnostic de libtool est :\n%2")
.arg(name).arg(errorMessage);
}
</programlisting>
<para>À partir de ce moment, la suite des opérations dépend à nouveau du type de service. Pour les modules externes génériques, vous créerez des objets avec la méthode <ulink url="kdeapi:tdecore/KLibFactory.html#ref3">KLibFactory::create()</ulink>. Pour KParts, vous devrez transtyper le pointeur de la fabrique vers les KParts::Factory plus spécifiques et employer sa méthode create() : </para>
<programlisting>if (factory->inherits("KParts::Factory")) {
KParts::Factory *partFactory = static_cast<KParts::Factory*>(factory);
QObject *obj = partFactory->createPart(parentWidget, widgetName,
parent, name, "KParts::ReadOnlyPart");
...
} else {
cout << "Le service n'implémente pas la fabrique correcte" << endl;
}
</programlisting>
</simplesect>
<simplesect id="services-definingdcopservices">
<title>Définition des services DCOP</title>
<para>Un service DCOP est habituellement mis en œuvre comme un programme qui est démarré lorsqu'il est nécessaire. Il entre ensuite dans une boucle et écoute les connexions DCOP. Il peut s'agir d'un programme interactif, mais il se peut aussi qu'il s'exécute complètement ou pour une partie de sa durée de vie comme un démon en arrière-plan, sans que l'utilisateur le remarque. Un exemple de ce type de démon est <literal>tdeio_uiserver</literal>, qui met en œuvre une interaction utilisateur comme boîte de dialogue de progression pour la bibliothèque TDEIO. L'avantage d'un tel démon centralisé dans ce contexte est que &pex; la progression du téléchargement de différents fichiers peut s'afficher dans une seule fenêtre, même si ces téléchargements ont été lancés à partir de différentes applications. </para>
<para>Un service DCOP est défini différemment depuis un service de bibliothèque partagée. Bien sûr, il ne spécifie pas une bibliothèque, mais plutôt un exécutable. En outre, les services DCOP ne spécifient pas de ligne ServiceType parce qu'ils sont habituellement démarrés par leur nom. À titre de propriétés additionnelles, il contient deux lignes : </para>
<para><literal>X-DCOP-ServiceType</literal> spécifie la manière dont le service est démarré. La valeur <literal>Unique</literal> indique que le service ne doit pas être démarré plus d'une fois. Cela signifie que si vous tentez de démarrer ce service (&pex; <emphasis>via</emphasis> <ulink url="kdeapi:tdecore/TDEApplication.html#startServiceByName"> TDEApplication::startServiceByName()</ulink>, KDE vérifie s'il est déjà enregistré avec DCOP et utilise le service en cours d'exécution. S'il n'est pas encore enregistré, KDE le démarre et attend jusqu'à ce qu'il soit enregistré. Ainsi, vous pouvez immédiatement envoyer des appels DCOP au service. Dans un tel cas, le service devra être mis en œuvre en tant que <ulink url="kdeapi:tdecore/KUniqueApplication.html">KUniqueApplication</ulink>. </para>
<para>La valeur <literal>Multi</literal> pour <literal>X-DCOP-ServiceType</literal> indique que, comme des instances multiples du service peuvent coexister, toute tentative pour démarrer le service créera un autre processus. En dernière possibilité, on peut employer la valeur <literal>None</literal>. Dans ce cas, un démarrage du service n'attendra pas jusqu'à ce qu'il soit enregistré avec DCOP. </para>
<para><literal>X-TDE-StartupNotify</literal> devrait normalement être défini à « false ». Sinon, quand le programme est démarré, la barre de tâches affiche une notification de démarrage ou, en fonction des réglages de l'utilisateur, le curseur est changé. </para>
<para>Voici la définition de <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>Utilisation des services DCOP</title>
<para>Un service DCOP est démarré avec une des quelques méthodes que contient la classe TDEApplication : </para>
<programlisting>DCOPClient *client = kapp->dcopClient();
client->attach();
if (!client->isApplicationRegistered("tdeio_uiserver")) {
QString error;
if (TDEApplication::startServiceByName("tdeio_uiserver", QStringList(), &error))
cout << "Le démarrage de kioserver a échoué avec le message " << error << endl;
}
...
QByteArray data, replyData;
QCString replyType;
QDataStream arg(data, IO_WriteOnly);
arg << true;
if (!client->call("tdeio_uiserver", "UIServer", "setListMode(bool)",
data, replyType, replyData))
cout << "L'appel à tdeio_uiserver a échoué" << endl;
...
</programlisting>
<para>Notez que l'exemple d'un appel DCOP donné utilise ici la mise en ordre explicite des arguments. Vous serez souvent amené à employer de préférence un élément de remplacement généré par dcopidl2cpp parce qu'il est plus simple et moins sujet aux erreurs. </para>
<para>Dans l'exemple donné ici, le service a été démarré « par nom », &cad; que le premier argument vers <function>TDEApplication::startServiceByName()</function> est le nom qui apparaît dans la ligne <literal>Name</literal> du fichier desktop. Une alternative consiste à utiliser <function>TDEApplication::startServiceByDesktopName()</function>, qui prend le nom de fichier de son fichier desktop comme argument, &cad; dans ce cas, <literal>"tdeio_uiserver.desktop"</literal>. </para>
<para>Tous ces appels prennent une liste d'URL comme deuxième argument, fourni au service sur la ligne de commande. Le troisième argument est un pointeur vers une <classname>QString</classname>. Si le démarrage du service échoue, cet argument devient un message d'erreur traduit. </para>
</simplesect>
</sect1>
<sect1 id="components-mime">
<title>Types MIME</title>
<simplesect id="mime-whataremimetypes">
<title>Que sont les types MIME ?</title>
<para>Les types MIME servent à décrire le type de contenu de blocs de fichiers ou de données. Au départ, ils ont été introduits afin d'autoriser l'envoi des images ou des fichiers son &etc; par courrier électronique (MIME signifie « Multipurpose Internet Mail Extensions », extensions multimédia de messagerie Internet). Plus tard, les navigateurs ont également fait appel à ce système pour déterminer comment présenter à l'utilisateur les données envoyées par un serveur web. Par exemple, une page HTML a un type MIME « text/html », un fichier PostScript « application/postscript ». Dans KDE, ce concept s'emploie à divers endroits : </para>
<itemizedlist>
<listitem><para>Dans l'affichage Icône de <application>Konqueror</application>, les fichiers sont représentés par des icônes. Chaque type MIME a une certaine icône associée illustrée ici. </para></listitem>
<listitem><para>Quand vous cliquez sur l'icône d'un fichier ou le nom d'un fichier dans <application>Konqueror</application>, soit le fichier s'affiche dans une vue intégrée, soit une application associée au type du fichier est ouverte. </para></listitem>
<listitem><para>Quand vous faites un glisser-déposer de certaines données d'une application à l'autre (ou au sein de la même application), la cible de dépôt peut choisir de n'accepter que certains types de données. De surcroît, elle gérera les données images différemment des données textuelles. </para></listitem>
<listitem><para>Les données du presse-papiers ont un type MIME. Traditionnellement, les programmes X ne gèrent que les pixmaps ou les textes, mais avec Qt, il n'y a aucune restriction sur le type des données. </para></listitem>
</itemizedlist>
<para>À la lumière des exemples précédents, il est clair que la gestion MIME est un problème complexe. Tout d'abord, il est nécessaire d'établir une correspondance depuis les noms des fichiers vers les types MIME. KDE franchit une étape supplémentaire en permettant même au contenu des fichiers d'être mis en correspondance vers les types MIME, pour les cas où le nom du fichier n'est pas disponible. En second lieu, il est nécessaire de mettre en correspondance les types MIME vers les applications ou les bibliothèques qui peuvent afficher ou modifier un fichier avec un certain type ou bien en créer une image miniature. </para>
<para>Il y a diverses API pour découvrir le type MIME des données ou des fichiers. En général, vous devez arriver à un certain compromis vitesse/fiabilité. Cherchez le type d'un fichier en n'examinant que son nom de fichier (&cad; dans la plupart des cas, l'extension du nom du fichier). Par exemple, un fichier <filename>foo.jpg</filename> est normalement « image/jpeg ». Dans les cas où l'extension est retirée, ce n'est pas sans risque et vous devez vraiment vérifier le contenu du fichier. Cette opération prend assurément plus de temps, en particulier pour les fichiers qu'il faut télécharger <emphasis>via</emphasis> HTTP au préalable. La méthode basée sur le contenu dépend du fichier <filename>TDEDIR/share/mimelnk/magic</filename> et est par conséquent difficile à étendre. Mais en général, les informations sur le type MIME peuvent être aisément mises à la disposition du système en installant un fichier <literal>.desktop</literal> : il est efficacement et commodément accessible grâce aux bibliothèques KDE. </para>
</simplesect>
<simplesect id="mime-definingmimetypes">
<title>Définition des types MIME</title>
<para>Définissons un type <literal>« application/x-foo »</literal> pour notre nouveau programme <application>foobar</application>. À cette fin, vous devez écrire un fichier <filename>foo.desktop</filename> et l'installer dans <filename>TDEDIR/share/mimelnk/application</filename>. (Il s'agit de l'emplacement habituel, qui peut différer entre les distributions). Cette opération peut s'effectuer en ajoutant les lignes suivantes au <filename>Makefile.am</filename> : </para>
<programlisting>mimedir = $(kde_mimedir)/application
mime_DATA = foo.desktop
EXTRA_DIST = $(mime_DATA)
</programlisting>
<para>Voici à quoi devrait ressembler le fichier <filename>foo.desktop</filename> : </para>
<programlisting>[Desktop Entry]
Type=MimeType
MimeType=application/x-foo
Icon=fooicon
Patterns=*.foo;
DefaultApp=foobar
Comment[fr]=Fichier de données Foo
Comment[en]=Foo Data File
</programlisting>
<para>La ligne <literal>« Comment »</literal> est supposée être traduite. Du fait que le fichier <filename>.desktop</filename> spécifie une icône, installez aussi une icône <filename>fooicon.png</filename>, qui représente le fichier, &pex; dans <application>Konqueror</application>. </para>
<para>Dans les bibliothèques KDE, un tel type de définition est mis en correspondance vers une instance de la classe <ulink url="kdeapi:tdeio/KMimeType.html">KMimeType</ulink>. Utilisez-la, comme dans l'exemple suivant : </para>
<programlisting>KMimeType::Ptr type = KMimeType::mimeType("application/x-foo");
cout << "Type: " << type->name() < endl;
cout << "Icon: " << type->icon() < endl;
cout << "Comment: " << type->icon() < endl;
QStringList patterns = type->patterns();
QStringList::ConstIterator it;
for (it = patterns.begin(); it != patterns.end(); ++it)
cout << "Motif : " << (*it) << endl;
</programlisting>
</simplesect>
<simplesect id="mime-determiningmimetypes">
<title>Détermination du type MIME des données</title>
<para>La méthode la plus rapide pour déterminer le type d'un fichier est <function>KMimeType::findByURL()</function>. Celle-ci cherche la chaîne d'URL et, le plus souvent, détermine le type à partir de l'extension. Pour certains protocoles (&pex;, http, man, info), ce mécanisme n'est pas employé. Par exemple, les scripts CGI sur les serveurs web écrits en Perl ont souvent l'extension <literal>.pl</literal> indiquant un type <literal>"text/x-perl"</literal>. Toutefois, le fichier que livre le serveur est la sortie de ce script, qui est normalement du HTML. Pour un tel cas, <function>KMimeType::findByURL()</function> retourne le type MIME <literal>"application/octet-stream"</literal> (disponible grâce à <function>KMimeType::defaultMimeType()</function>), indiquant qu'il est impossible de découvrir le type. </para>
<programlisting>KMimeType::Ptr type = KMimeType::findByURL("/home/bernd/foobar.jpg");
if (type->name() == KMimeType::defaultMimeType())
cout << "Impossible de découvrir le type" << endl;
else
cout << "Type : " << type->name() << endl;
</programlisting>
<para>(cette méthode a quelques arguments supplémentaires, mais comme ils ne sont pas documentés, ignorons-les.) </para>
<para>Vous pouvez être amené à trouver un type MIME à partir du contenu du fichier au lieu du nom du fichier. Ce procédé est plus fiable mais aussi plus lent, puisqu'il exige la lecture d'une partie du fichier. Pour ce faire, faites appel à la classe <ulink url="kdeapi:tdeio/KMimeMagic.html">KMimeMagic</ulink> qui gère différemment les erreurs : </para>
<programlisting>KMimeMagicResult *result = KMimeMagic::self()->findFileType("/home/bernd/foobar.jpg");
if (!result || !result->isValid())
cout << "Impossible de découvrir le type" << endl;
else
cout << "Type : " << result->mimeType() << endl;
</programlisting>
<para>Comme variante de cette fonction, vous pouvez aussi déterminer le type d'un bloc de mémoire. Elle est &pex; utilisée dans <application>Kate</application> pour trouver le mode de coloration syntaxique : </para>
<programlisting>QByteArray array;
...
KMimeMagicResult *result = KMimeMagic::self()->findBufferType(array);
if (!result || !result->isValid())
cout << "Impossible de découvrir le type" << endl;
else
cout << "Type : " << result->mimeType() << endl;
</programlisting>
<para>Bien sûr, même KMimeMagic n'est capable de déterminer un type de fichier qu'à partir du contenu d'un fichier local. Pour les fichiers distants, il y a une autre possibilité : </para>
<programlisting>KURL url("http://developer.kde.org/favicon.ico");
QString type = TDEIO::NetAccess::mimetype(url);
if (type == KMimeType::defaultMimeType())
cout << "Impossible de découvrir le type" << endl;
else
cout << "Type : " << type << endl;
</programlisting>
<para>Cette fonction démarre une tâche TDEIO pour télécharger une partie du fichier et le vérifie. Notez qu'elle peut être très lente et bloque le programme. Normalement, vous ne l'utiliserez que si <function>KMimeType::findByURL()</function> a retourné <literal>"application/octet-stream"</literal>. </para>
<para>Par ailleurs, si vous ne voulez pas bloquer votre application, vous pouvez également démarrer explicitement la tâche TDEIO et vous connecter à quelques-uns de ses signaux : </para>
<programlisting>void FooClass::findType()
{
KURL url("http://developer.kde.org/favicon.ico");
TDEIO::MimetypeJob *job = TDEIO::mimetype(url);
connect( job, SIGNAL(result(TDEIO::Job*)),
this, SLOT(mimeResult(TDEIO::Job*)) );
}
void FooClass::mimeResult(TDEIO::Job *job)
{
if (job->error())
job->showErrorDialog();
else
cout << "MIME type: " << ((TDEIO::MimetypeJob *)job)->mimetype() << endl;
}
</programlisting>
</simplesect>
<simplesect id="mime-mappingmimetypes">
<title>Mise en correspondance d'un type MIME vers une application ou un service</title>
<para>Lorsqu'une application est installée, elle prépare un fichier <literal>.desktop</literal> contenant une liste de types MIME que cette application peut charger. De la même manière, les composants comme KParts rendent cette information disponible au moyen de leurs fichiers <literal>.desktop</literal> de services. Il y a donc en général plusieurs programmes et composants pour traiter un type MIME donné. Vous pouvez obtenir ce genre de liste depuis la classe <classname>KServiceTypeProfile</classname> : </para>
<programlisting>KService::OfferList offers = KServiceTypeProfile::offers("text/html", "Application");
KService::OfferList::ConstIterator it;
for (it = offers.begin(); it != offers.end(); ++it) {
KService::Ptr service = (*it);
cout << "Nom : " << service->name() << endl;
}
</programlisting>
<para>La valeur de retour de cette fonction est une liste d'offres de services. Un objet <classname>KServiceOffer</classname> conditionne un KService::Ptr avec un numéro de préférence. La liste que <function>KServiceTypeProfile::offers()</function> retourne est numérotée dans l'ordre des préférences de l'utilisateur. Ce dernier peut modifier ce comportement en appelant <command>"keditfiletype text/html"</command> ou en choisissant <guimenuitem>Modifier le type du fichier</guimenuitem> dans le menu contextuel de <application>Konqueror</application> sur un fichier HTML. </para>
<para>Dans l'exemple ci-dessus, une liste d'offres des applications prenant en charge <literal>text/html</literal> a été demandée. Celle-ci contient — entre autres — des éditeurs HTML comme <application>Quanta Plus</application>. Vous pouvez également remplacer le second argument <literal>"Application"</literal> par <literal>"KParts::ReadOnlyPart"</literal>. Dans ce cas, vous obtenez une liste des composants intégrables pour présenter du contenu HTML, &pex;, TDEHTML. </para>
<para>La plupart du temps, la liste de toutes les offres de services n'a aucun intérêt pour une combinaison type MIME et type de service. Il y a une fonction de confort qui vous donne uniquement l'offre de service ayant la plus grande préférence : </para>
<programlisting>KService::Ptr offer = KServiceTypeProfile::preferredService("text/html", "Application");
if (offer)
cout << "Nom : " << service->name() << endl;
else
cout << "Aucun service approprié n'a été trouvé" << endl;
</programlisting>
<para>Pour des requêtes encore plus complexes, il y a un <ulink url="kdeapi:tdeio/TDETrader.html">courtier</ulink> à part entière dans le style de CORBA. </para>
<para>Pour exécuter un service d'application avec quelques URL, utilisez <ulink url="kdeapi:tdeio/KRun.html">KRun</ulink> : </para>
<programlisting>KURL::List urlList;
urlList << "http://www.ietf.org/rfc/rfc1341.txt?number=1341";
urlList << "http://www.ietf.org/rfc/rfc2046.txt?number=2046";
KRun::run(offer.service(), urlList);
</programlisting>
</simplesect>
<simplesect id="mime-misc">
<title>Divers</title>
<para>Dans cette section, nous souhaitons répertorier quelques API qui sont plus ou moins liées à l'étude précédente. </para>
<para>Obtention d'une icône pour une URL. Celle-ci cherche le type de l'URL et retourne l'icône associée. </para>
<programlisting>KURL url("ftp://ftp.kde.org/pub/incoming/wibble.c");
QString icon = KMimeType::iconForURL(url);
</programlisting>
<para>Exécution d'une URL. Celle-ci cherche le type de l'URL et démarre le programme préféré de l'utilisateur et associé à ce type. </para>
<programlisting>KURL url("http://dot.kde.org");
new KRun(url);
</programlisting>
</simplesect>
</sect1>
<sect1 id="nettransparency">
<title>Transparence réseau</title>
<simplesect id="nettransparency-intro">
<title>Introduction</title>
<para>À l'ère du World Wide Web, il est d'une importance capitale que les applications bureautiques puissent accéder aux ressources sur l'internet : elles devront être capables de télécharger des fichiers sur un serveur web, écrire des fichiers sur un serveur ftp ou lire des messages sur un serveur de messagerie. Souvent, la capacité à accéder à des fichiers quel que soit leur emplacement est appelée <emphasis>transparence réseau</emphasis>. </para>
<para>Dans le passé, différentes approches de ces objectifs ont été mises en œuvre. L'ancien système de fichiers NFS est une tentative pour implémenter la transparence réseau au niveau de l'API POSIX. Bien que cette approche fonctionne parfaitement dans des réseaux locaux,étroitement couplés, elle ne convient pas pour les ressources dont l'accès manque de fiabilité et souffre d'une éventuelle lenteur. Ici, l'<emphasis>asynchronicité</emphasis> est importante. Pendant que vous attendez que votre navigateur web télécharge une page, l'interface utilisateur ne devra pas se bloquer. De plus, le rendu de la page ne devrait pas commencer quand la page est complètement disponible, mais devrait être régulièrement actualisé au fur et à mesure que les données arrivent. </para>
<para>Dans les bibliothèques KDE, la transparence réseau est mise en œuvre dans l'API TDEIO. Le concept central de cette architecture est une <emphasis>tâche</emphasis> d'E/S. Une tâche peut copier ou supprimer des fichiers, ou toute autre chose similaire. Dès lors qu'une tâche est démarrée, elle s'exécute en arrière-plan et ne bloque pas l'application. Toute communication depuis la tâche à nouveau vers l'application — comme la remise des données ou les informations de progression — s'effectue alors qu'elle est intégrée à la boucle d'événement Qt. </para>
<para>L'opération d'arrière-plan est réalisée en démarrant les <emphasis>ioslaves</emphasis> pour exécuter certaines tâches. Les « ioslaves » sont démarrés en tant que processus séparés et communiquent avec eux grâce à des sockets du domaine UNIX. De cette manière, aucun traitement multiprocessus (<emphasis>multi-threading</emphasis>) n'est nécessaire et les esclaves instables ne peuvent pas « planter » l'application qui les utilise. </para>
<para>Les emplacements des fichiers sont exprimés par les URL bien connues. Mais dans KDE, les URL ne se contentent pas d'étendre la plage des fichiers adressables au-delà du système de fichiers local. Ce dernier va aussi dans la direction opposée — &pex;, vous pouvez explorer des archives « tar ». Ceci est réalisable grâce à l'imbrication des URL. Par exemple, un fichier dans une archive tar sur un serveur http pourrait avoir l'URL </para>
<programlisting>http://www-com.physik.hu-berlin.de/~bernd/article.tgz#tar:/paper.tex
</programlisting>
</simplesect>
<simplesect id="nettransparency-usingkio">
<title>Utilisation de TDEIO</title>
<para>Dans la majorité des cas, les tâches sont créées en appelant des fonctions dans l'espace de noms TDEIO. Celles-ci prennent une ou deux URL comme arguments, voire d'autres paramètres nécessaires. Lorsque la tâche est terminée, elle émet le signal <literal>result(TDEIO::Job*)</literal>. Une fois ce signal émis, la tâche se supprime. Ainsi, voici à quoi ressemble un cas classique d'utilisation : </para>
<programlisting>void FooClass::makeDirectory()
{
SimpleJob *job = TDEIO::mkdir(KURL("file:/home/bernd/kiodir"));
connect( job, SIGNAL(result(TDEIO::Job*)),
this, SLOT(mkdirResult(TDEIO::Job*)) );
}
void FooClass::mkdirResult(TDEIO::Job *job)
{
if (job->error())
job->showErrorDialog();
else
cout << "mkdir a bien fonctionné" << endl;
}
</programlisting>
<para>Selon le type de tâche, vous pouvez également vous connecter à d'autres signaux. </para>
<para>Voici une vue d'ensemble des fonctions possibles : </para>
<variablelist>
<varlistentry><term>TDEIO::mkdir(const KURL &url, int permission)</term>
<listitem><para>Crée un dossier, optionnellement avec certaines permissions. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::rmdir(const KURL &url)</term>
<listitem><para>Supprime un dossier. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::chmod(const KURL &url, int permissions)</term>
<listitem><para>Change les permissions d'un fichier. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::rename(const KURL &src, const KURL &dest, bool overwrite)</term>
<listitem><para>Renomme un fichier. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::symlink(const QString &target, const KURL &dest, bool overwrite, bool showProgressInfo)</term>
<listitem><para>Crée un lien symbolique. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::stat(const KURL &url, bool showProgressInfo)</term>
<listitem><para>Découvre certaines informations sur le fichier, comme sa taille, l'heure de sa modification et ses permissions. Les informations peuvent être obtenues à partir de TDEIO::StatJob::statResult() lorsque la tâche est terminée. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::get(const KURL &url, bool reload, bool showProgressInfo)</term>
<listitem><para>Transfère des données depuis une URL. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::put(const KURL &url, int permissions, bool overwrite, bool resume, bool showProgressInfo)</term>
<listitem><para>Transfère des données vers une URL. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::http_post(const KURL &url, const QByteArray &data, bool showProgressInfo)</term>
<listitem><para>Poste des données. Spécial pour HTTP. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::mimetype(const KURL &url, bool showProgressInfo)</term>
<listitem><para>Essaie de trouver le type MIME de l'URL. Le type peut être obtenu depuis TDEIO::MimetypeJob::mimetype() lorsque la tâche est terminée. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::file_copy(const KURL &src, const KURL &dest, int permissions, bool overwrite, bool resume, bool showProgressInfo)</term>
<listitem><para>Copie un seul fichier. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::file_move(const KURL &src, const KURL &dest, int permissions, bool overwrite, bool resume, bool showProgressInfo)</term>
<listitem><para>Renomme ou déplace un seul fichier. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::file_delete(const KURL &url, bool showProgressInfo)</term>
<listitem><para>Supprime un seul fichier. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::listDir(const KURL &url, bool showProgressInfo)</term>
<listitem><para>Répertorie le contenu d'un dossier. Chaque fois que de nouveaux éléments sont connus, le signal TDEIO::ListJob::entries() est émis. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::listRecursive(const KURL &url, bool showProgressInfo)</term>
<listitem><para>Similaire à la fonction listDir(), mais celle-ci est récursive. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::copy(const KURL &src, const KURL &dest, bool showProgressInfo)</term>
<listitem><para>Copie un fichier ou un dossier. Les dossiers sont copiés récursivement. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::move(const KURL &src, const KURL &dest, bool showProgressInfo)</term>
<listitem><para>Déplace ou renomme un fichier ou un dossier. </para></listitem>
</varlistentry>
<varlistentry><term>TDEIO::del(const KURL &src, bool shred, bool showProgressInfo)</term>
<listitem><para>Supprime un fichier ou un dossier. </para></listitem>
</varlistentry>
</variablelist>
</simplesect>
<simplesect id="nettransparency-direntries">
<title>Éléments des dossiers</title>
<para>Les tâches TDEIO::stat() et TDEIO::listDir() retournent toutes deux leur résultat sous la forme d'un type UDSEntry, UDSEntryList, respectivement. Cette dernière est définie en tant que QValueList<UDSEntry>. L'acronyme UDS signifie « Universal Directory Service » (service universel de dossiers). Le principe sous-jacent est que l'élément du dossier ne transporte que les informations qu'un ioslave peut fournir, sans plus. Par exemple, l'esclave http ne fournit aucune information sur les droits d'accès ou sur les propriétaires des fichiers. En revanche, un UDSEntry est une liste de UDSAtoms. Chaque atome fournit une partie spécifique d'information. Il se compose d'un type enregistré dans m_uds et soit d'une valeur entière dans m_long, soit d'une valeur chaîne dans m_str, en fonction du type. </para>
<para>Les types suivants sont actuellement définis : </para>
<itemizedlist>
<listitem><para>UDS_SIZE (integer) — taille du fichier. </para></listitem>
<listitem><para>UDS_USER (string) — utilisateur propriétaire du fichier. </para></listitem>
<listitem><para>UDS_GROUP (string) — groupe propriétaire du fichier. </para></listitem>
<listitem><para>UDS_NAME (string) — nom du fichier. </para></listitem>
<listitem><para>UDS_ACCESS (integer) — droits d'accès du fichier, comme &pex; enregistrés par la fonction libc stat() dans le champ st_mode. </para></listitem>
<listitem><para>UDS_FILE_TYPE (integer) — le type du fichier, comme &pex; enregistré par stat() dans le champ st_mode. Par conséquent, vous pouvez faire appel aux macros libc habituelles comme S_ISDIR pour tester cette valeur. Notez que les données fournies par les ioslaves correspondent à stat(), non lstat(), &cad; que dans le cas de liens symboliques, le type du fichier est ici le type du fichier sur lequel pointe le lien, non le lien lui-même. </para></listitem>
<listitem><para>UDS_LINK_DEST (string) — dans le cas d'un lien symbolique, le nom du fichier sur lequel pointe le fichier. </para></listitem>
<listitem><para>UDS_MODIFICATION_TIME (integer) — l'heure (comme dans le type time_t) de la dernière modification du fichier, comme &pex; enregistré par stat() dans le champ st_mtime. </para></listitem>
<listitem><para>UDS_ACCESS_TIME (integer) — l'heure du dernier accès au fichier, comme &pex; enregistré par stat() dans le champ st_atime. </para></listitem>
<listitem><para>UDS_CREATION_TIME (integer) — l'heure à laquelle le fichier a été créé, comme &pex; enregistré par stat() dans le champ st_ctime. </para></listitem>
<listitem><para>UDS_URL (string) — fournit l'URL d'un fichier, s'il ne s'agit pas simplement de la concaténation de l'URL d'un dossier et d'un nom de fichier. </para></listitem>
<listitem><para>UDS_MIME_TYPE (string) — type MIME du fichier </para></listitem>
<listitem><para>UDS_GUESSED_MIME_TYPE (string) — type MIME du fichier comme le devine l'esclave. La différence avec le type précédent est que celui fourni ici ne devra pas être considéré comme fiable (parce que le fait de le déterminer d'une manière sûre serait trop coûteux). Par exemple, la classe KRun vérifie explicitement le type MIME s'il n'a pas d'informations dignes de foi. </para></listitem>
</itemizedlist>
<para>Bien que la manière d'enregister des informations sur les fichiers dans un <classname>UDSEntry</classname> soit souple et pratique du point de vue de l'ioslave, son utilisation pour le programmeur d'applications est fastidieuse. Par exemple, pour découvrir le type MIME du fichier, vous devez itérer sur tous les atomes et tester si <literal>m_uds</literal> est <literal>UDS_MIME_TYPE</literal>. Heureusement il y a une API beaucoup plus facile à utiliser : la classe <classname>KFileItem</classname>. </para>
</simplesect>
<simplesect id="nettransparency-syncuse">
<title>Utilisation synchrone</title>
<para>Souvent, l'API asynchrone de TDEIO est trop complexe à employer et donc, la mise en œuvre de l'asynchronicité complète n'est pas une priorité. Par exemple, dans un programme qui ne peut gérer qu'un fichier document à la fois, il y a de toute façon très peu de choses à faire pendant que le programme télécharge un fichier. Pour ces cas peu complexes, il y a une API beaucoup plus simple, sous la forme d'un ensemble de fonctions statiques dans TDEIO::NetAccess. Par exemple, pour copier un fichier, utilisez </para>
<programlisting>KURL source, target;
source = ...;
target = ...
TDEIO::NetAccess::copy(source, target);
</programlisting>
<para>La fonction revient à l'état antérieur une fois que le processus complet de copie est terminé. De plus, cette méthode fournit une boîte de dialogue de progression et s'assure que les processus d'application retracent les événements. </para>
<para>La fonction <function>download()</function>, en combinaison avec <function>removeTempFile()</function> est particulièrement intéressante. La première télécharge un fichier depuis l'URL donnée et l'enregistre dans un fichier temporaire avec un nom unique. Ce nom est enregistré dans le second argument. <emphasis>Si</emphasis> l'URL est locale, le fichier n'est pas téléchargé et, en revanche, le second argument est défini au nom du fichier local. La fonction <function>removeTempFile()</function> supprime le fichier donné par son argument si le fichier est le résultat d'un téléchargement précédent. Si tel n'est pas le cas, elle ne fait rien. Ainsi, le fragment de code suivant est un moyen très aisé d'utiliser le chargement des fichiers, quel que soit leur emplacement : </para>
<programlisting>KURL url;
url = ...;
QString tempFile;
if (TDEIO::NetAccess::download(url, tempFile) {
// load the file with the name tempFile
TDEIO::NetAccess::removeTempFile(tempFile);
}
</programlisting>
</simplesect>
<simplesect id="nettransparency-metadata">
<title>Métadonnées</title>
<para>Comme on peut le voir plus haut, l'interface aux tâches IO est assez abstraite et ne prend en considération aucun échange d'informations entre l'application et l'<emphasis>ioslave</emphasis> spécifique au protocole : ce n'est pas toujours approprié. Par exemple, vous pouvez fournir certains paramètres à l'esclave HTTP pour contrôler le comportement de sa mise en cache ou envoyer un groupe de cookies avec la requête. Le concept de métadonnées a été introduit pour satisfaire cette exigence. Lorsqu'une tâche est créée, vous pouvez la configurer en lui ajoutant des métadonnées. Chaque élément de métadonnées se compose d'une paire clé/valeur. Par exemple, pour empêcher l'esclave HTTP de charger une page web depuis son cache, utilisez : </para>
<programlisting>void FooClass::reloadPage()
{
KURL url("http://www.kdevelop.org/index.html");
TDEIO::TransferJob *job = TDEIO::get(url, true, false);
job->addMetaData("cache", "reload");
...
}
</programlisting>
<para>La même technique s'emploie dans l'autre sens, &cad; pour la communication depuis l'esclave vers l'application. La méhode <function>Job::queryMetaData()</function> demande la valeur de la clé remise par l'esclave. Pour l'esclave HTTP, un tel exemple est la clé <literal>« modified »</literal>, qui contient une représentation sous forme de chaîne de la date de la dernière modification de la page web. Voici un exemple de la manière dont vous pouvez l'utiliser : </para>
<programlisting>void FooClass::printModifiedDate()
{
KURL url("http://developer.kde.org/documentation/kde2arch/index.html");
TDEIO::TransferJob *job = TDEIO::get(url, true, false);
connect( job, SIGNAL(result(TDEIO::Job*)),
this, SLOT(transferResult(TDEIO::Job*)) );
}
void FooClass::transferResult(TDEIO::Job *job)
{
QString mimetype;
if (job->error())
job->showErrorDialog();
else {
TDEIO::TransferJob *transferJob = (TDEIO::TransferJob*) job;
QString modified = transferJob->queryMetaData("modified");
cout << "Dernière modification : " << modified << endl;
}
</programlisting>
</simplesect>
<simplesect id="nettransparency-scheduling">
<title>Planification</title>
<para>Lorsque vous employez l'API TDEIO, vous n'avez d'ordinaire pas à vous préoccuper des détails du démarrage des IOslaves et de la communication avec ces derniers. Le cas normal d'utilisation est de démarrer une tâche et avec certains paramètres, ainsi que de gérer les signaux que la tâche émet. </para>
<para>En coulisses, le scénario est beaucoup plus compliqué. Dès que vous créez une tâche, elle est mise en file d'attente. Quand l'application revient vers la boucle d'événement, TDEIO alloue les processus esclaves pour les tâches contenues dans la file d'attente. Pour la première tâche démarrée, c'est trivial : un IOslave est démarré pour le protocole approprié. Toutefois, une fois que la tâche (comme un téléchargement depuis un serveur http) est terminée, elle n'est pas tuée immédiatement. Elle est au contraire placée dans un groupe d'esclaves inactifs et tuée après un certain temps d'inactivité (le plus souvent, 3 minutes). Si une nouvelle requête pour le même protocole et le même hôte arrive, l'esclave est réutilisé. L'avantage évident est que, pour une série de tâches concernant le même hôte, le coût nécessaire à la création de nouveaux processus et éventuellement à l'obtention d'une procédure d'authentification est économisé. </para>
<para>Naturellement, la réutilisation n'est possible que si l'esclave existant a déjà terminé sa tâche précédente. Quand une nouvelle requête arrive alors qu'un processus esclave existant s'exécute encore, un nouveau processus doit être démarré et utilisé. Lors de l'usage de l'API dans les exemples précédents, il n'y a aucune limite à la création de nouveaux processus esclaves : si vous démarrez une série consécutive de téléchargements pour 20 fichiers différents, alors TDEIO démarre 20 processus esclaves. Ce dispositif visant à affecter des esclaves aux tâches est appelé <emphasis>direct</emphasis>. Ce n'est pas toujours celui qui est le plus approprié, car il peut exiger beaucoup de mémoire et placer une charge élevée à la fois sur les machines clientes et serveurs. </para>
<para>Il y a donc un autre moyen : <emphasis>planifier</emphasis> les tâches. Si vous le faites, seul un nombre limité (actuellement, 3) de processus esclaves pour un protocole sera créé. Si vous créez davantage de tâches, elles sont placées dans une file d'attente et traitées lorsqu'un processus esclave devient inactif. Voici comment s'effectue l'opération : </para>
<programlisting>KURL url("http://developer.kde.org/documentation/kde2arch/index.html");
TDEIO::TransferJob *job = TDEIO::get(url, true, false);
TDEIO::Scheduler::scheduleJob(job);
</programlisting>
<para>Une troisième possibilité est <emphasis>orientée connexion</emphasis>. Par exemple, pour l'esclave IMAP, il n'est pas judicieux de démarrer de multiples processus pour le même serveur. Une seule connexion IMAP à la fois devra être imposée. Dans ce cas, l'application doit accepter explicitement la notion d'esclave. Il faut qu'elle désalloue un esclave pour une certaine connexion puis qu'elle affecte toutes les tâches qui obtiendront la même connexion au même esclave. Cette opération peut à nouveau être réalisée à l'aide du TDEIO::Scheduler : </para>
<programlisting>KURL baseUrl("imap://bernd@albert.physik.hu-berlin.de");
TDEIO::Slave *slave = TDEIO::Scheduler::getConnectedSlave(baseUrl);
TDEIO::TransferJob *job1 = TDEIO::get(KURL(baseUrl, "/INBOX;UID=79374"));
TDEIO::Scheduler::assignJobToSlave(slave, job1);
TDEIO::TransferJob *job2 = TDEIO::get(KURL(baseUrl, "/INBOX;UID=86793"));
TDEIO::Scheduler::assignJobToSlave(slave, job2);
...
TDEIO::Scheduler::disconnectSlave(slave);
</programlisting>
<para>Vous pouvez déconnecter l'esclave uniquement après que toutes les tâches qui lui sont affectées sont garanties être terminées. </para>
</simplesect>
<simplesect id="nettransparency-definingslaves">
<title>Définition d'un ioslave</title>
<para>Dans ce qui suit, nous verrons comment vous pouvez ajouter un nouveau ioslave au système. Par analogie avec les services, les nouveaux ioslaves sont annoncés au système en installant un petit fichier de configuration. Le fragment de Makefile.am suivant installa le protocole ftp : </para>
<programlisting>protocoldir = $(kde_servicesdir)
protocol_DATA = ftp.protocol
EXTRA_DIST = $(mime_DATA)
</programlisting>
<para>Voici le contenu du fichier ftp.protocol : </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>L'élément <literal>« protocol »</literal> définit de quel protocole cet esclave est responsable. <literal>« exec »</literal> est (contrairement à ce que vous pourriez attendre naïvement), le nom de la bibliothèque qui implémente l'esclave. Quand ce dernier est supposé démarrer, l'exécutable <command>« tdeinit »</command> est démarré, lequel à son tour charge cette bibliothèque dans son espace d'adressage. Donc, en pratique, vous pouvez imaginer l'esclave en cours d'exécution comme un processus séparé, bien qu'il soit implémenté en tant que bibliothèque. L'avantage de ce mécanisme est qu'il économise une grande quantité de mémoire et réduit le temps qu'exige l'éditeur de liens au moment de l'exécution. </para>
<para>Les lignes « input » et « output » ne sont pas utilisées actuellement. </para>
<para>Dans le fichier <literal>.protocol</literal>, les lignes restantes définissent les capacités qu'a l'esclave. En général, les fonctionnalités qu'un esclave doit implémenter sont beaucoup plus simples que celles que l'API TDEIO fournit pour l'application. La raison à cela est que les tâches complexes sont planifiées pour quelques sous-tâches. Par exemple, pour répertorier un dossier récursivement, une tâche sera démarrée pour le dossier de premier niveau. Puis, pour chaque sous-dossier faisant l'objet d'un rapport, de nouvelles sous-tâches sont démarrées. Dans TDEIO, un planificateur veille à ce qu'il n'y ait pas trop de tâches actives au même moment. De la même manière, pour copier un fichier au sein d'un protocole qui ne prend pas en charge la copie directement (comme le protocole <literal>ftp:</literal>), TDEIO peut lire le fichier source puis écrire les données sur le fichier de destination. Pour que cela fonctionne, le <literal>.protocol</literal> doit annoncer les actions que son esclave prend en charge. </para>
<para>Du fait que les esclaves sont chargés à titre de bibliothèques partagées mais constituent des programmes autonomes, l'environnement de leur code paraît un peu différent des modules externes (<emphasis>plugins</emphasis>) des bibliothèques partagées normales. La fonction appelée pour démarrer l'esclave est dénommée <function>kdemain()</function>. Elle effectue quelques initialisations puis entre dans une boucle d'événement et attend les requêtes de l'application qui l'utilise. Voici à quoi elle ressemble : </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, "Usage : tdeio_ftp protocol "
"domain-socket1 domain-socket2\n");
exit(-1);
}
FtpSlave slave(argv[2], argv[3]);
slave.dispatchLoop();
return 0;
}
</programlisting>
</simplesect>
<simplesect id="nettransparency-implementingslaves">
<title>Implémentation d'un ioslave</title>
<para>Les esclaves sont implémentés en tant que sous-classes de <classname>TDEIO::SlaveBase</classname> (FtpSlave dans l'exemple ci-dessus). Ainsi, les actions répertoriées dans le <literal>.protocol</literal> correspondent à certaines fonctions virtuelles dans <classname>TDEIO::SlaveBase</classname> que l'implémentation de l'esclave doit réimplémenter. Voici une liste des actions possibles et des fonctions virtuelles correspondantes : </para>
<variablelist>
<varlistentry><term>lecture — lit des données depuis une URL</term>
<listitem><para>void get(const KURL &url)</para></listitem></varlistentry>
<varlistentry><term>écriture — écrit des données dans une URL et crée le fichier s'il n'existe pas encore.</term>
<listitem><para>void put(const KURL &url, int permissions, bool overwrite, bool resume)</para></listitem></varlistentry>
<varlistentry><term>déplacement — renomme un fichier.</term>
<listitem><para>void rename(const KURL &src, const KURL &dest, bool overwrite)</para></listitem></varlistentry>
<varlistentry><term>suppression — supprime un fichier ou un dossier.</term>
<listitem><para>void del(const KURL &url, bool isFile)</para></listitem></varlistentry>
<varlistentry><term>listage — répertorie le contenu d'un dossier.</term>
<listitem><para>void listDir(const KURL &url)</para></listitem></varlistentry>
<varlistentry><term>makedir — crée un dossier.</term>
<listitem><para>void mkdir(const KURL &url, int permissions)</para></listitem></varlistentry>
</variablelist>
<para>En outre, il y a des fonctions réimplémentables non répertoriées dans le fichier <literal>.protocol</literal>. Pour ces opérations, TDEIO détermine automatiquement si elles sont prises en charge ou non (&cad; que l'implémentation par défaut retourne une erreur). </para>
<variablelist>
<varlistentry><term>Fournit des informations sur un fichier, similaire à la fonction C stat().</term>
<listitem><para>void stat(const KURL &url)</para></listitem></varlistentry>
<varlistentry><term>Modifie les droits d'accès d'un fichier.</term>
<listitem><para>void chmod(const KURL &url, int permissions)</para></listitem></varlistentry>
<varlistentry><term>Détermine le type MIME d'un fichier.</term>
<listitem><para>void mimetype(const KURL &url)</para></listitem></varlistentry>
<varlistentry><term>Copie un fichier.</term>
<listitem><para>copy(const KURL &url, const KURL &dest, int permissions, bool overwrite)</para></listitem></varlistentry>
<varlistentry><term>Crée un lien symbolique.</term>
<listitem><para>void symlink(const QString &target, const KURL &dest, bool overwrite)</para></listitem></varlistentry>
</variablelist>
<para>Toutes ces implémentations devront se terminer par un ou deux appels : si l'opération a réussi, elles devront appeler <literal>finished()</literal>. Si une erreur s'est produite, <literal>error()</literal> devra être appelée avec un code d'erreur comme premier argument et une chaîne dans le second. Les codes d'erreur possibles sont répertoriés sous forme d'énumération <type>TDEIO::Error</type>. Le second argument est habituellement l'URL en question. Elle est utilisée &pex; dans <function>TDEIO::Job::showErrorDialog()</function> afin de paramétrer le message d'erreur humainement lisible. </para>
<para>Pour les esclaves qui correspondent aux protocoles de réseau, il pourrait être intéressant de réimplémenter la méthode <function>SlaveBase::setHost()</function>. Cette dernière est appelée pour indiquer au processus esclave l'hôte et le port, ainsi que le nom d'utilisateur et le mot de passe pour se connecter. En général, les métadonnées définies par l'application peuvent être interrogées par <function>SlaveBase::metaData()</function>. Vous pouvez vérifier l'existence des métadonnées d'une certaine clé avec <function>SlaveBase::hasMetaData()</function>. </para>
</simplesect>
<simplesect id="nettransparency-communication">
<title>Communication à nouveau avec l'application</title>
<para>Diverses actions mises en œuvre dans un esclave doivent d'une certaine manière communiquer les données en retour à l'application à l'aide du processus esclave : </para>
<itemizedlist>
<listitem><para><function>get()</function> envoie des blocs de données. Pour ce faire, elle utilise <function>data()</function>, qui prend un <classname>QByteArray</classname> comme argument. Bien sûr, vous n'avez pas besoin d'envoyer toutes les données à la fois. Si vous envoyez un gros fichier, appelez <function>data()</function> avec des blocs de données plus petits, de façon à ce que l'application puisse les traiter. Appelez <function>finished()</function> quand le transfert est terminé. </para></listitem>
<listitem><para><function>listDir()</function> signale des informations sur les éléments d'un dossier. À cette fin, appelez <function>listEntries()</function> avec une <classname>TDEIO::UDSEntryList</classname> comme argument. De manière analogue à <function>data()</function>, vous pouvez l'appeler plusieurs fois. Quand vous avez fini, appelez <function>listEntry()</function> avec le second argument défini à « true ». Vous pouvez aussi appeler <function>totalSize()</function> pour signaler le nombre total des éléments du dossier, s'il est connu. </para></listitem>
<listitem><para><function>stat()</function> signale des informations sur un fichier, comme sa taille, son type MIME, &etc; Ce genre d'informations est conditionné dans une <classname>TDEIO::UDSEntry</classname>, que nous aborderons ci-après. Utilisez <function>statEntry()</function> pour envoyer un tel élément à l'application. </para></listitem>
<listitem><para><function>mimetype()</function> appelle <function>mimeType()</function> avec un argument chaîne. </para></listitem>
<listitem><para><function>get()</function> et <function>copy()</function> peuvent être amenées à fournir des informations sur la progression. Les méthodes <function>totalSize()</function>, <function>processedSize()</function>, <function>speed()</function> s'en chargent. La taille totale et la taille traitée sont signalées sous forme d'octets, la vitesse en octets par seconde. </para></listitem>
<listitem><para>Vous pouvez envoyer des paires clé/valeur arbitraires de métadonnées avec <function>setMetaData()</function>. </para></listitem>
</itemizedlist>
</simplesect>
<simplesect id="nettransparency-interacting">
<title>Interaction avec l'utilisateur</title>
<para>Parfois, un esclave doit interagir avec l'utilisateur. Des exemples incluent les messages d'information, les boîtes de dialogue d'authentification et de confirmation quand un fichier est sur le point d'être écrasé. </para>
<itemizedlist>
<listitem><para><function>infoMessage()</function> — il s'agit d'un message de retour d'informations, comme un message « Retrieving data from <host> » depuis l'esclave http, qui est souvent affiché dans la barre d'état du programme. Côté application, cette méthode correspond au signal <function>TDEIO::Job::infoMessage()</function>. </para></listitem>
<listitem><para><function>warning()</function> — affiche un avertissement dans une boîte de message avec <function>KMessageBox::information()</function>. Si une boîte de message est encore ouverte depuis un précédent appel de warning() provenant du même processus esclave, il ne se produit rien. </para></listitem>
<listitem><para><function>messageBox()</function> — cette méthode est plus riche que la précédente. Elle permet d'ouvrir une boîte de message avec du texte et une légende, voire quelques boutons. Reportez-vous à l'énumération <type>SlaveBase::MessageBoxType</type> à titre de référence. </para></listitem>
<listitem><para><function>openPassDlg()</function> — ouvre une boîte de dialogue pour la saisie du nom d'utilisateur et du mot de passe. </para></listitem>
</itemizedlist>
</simplesect>
</sect1>
</chapter>
<appendix id="misc">
<title>Licence</title>
&underFDL;
&underGPL;
</appendix>
</book>
|